Fix Xcode 15 build failure due to DT_TOOLCHAIN_DIR (#132803)
Starting in Xcode 15, when building macOS, DT_TOOLCHAIN_DIR cannot be used to evaluate LD_RUNPATH_SEARCH_PATHS or LIBRARY_SEARCH_PATHS. `xcodebuild` error message recommend using TOOLCHAIN_DIR instead. Since Xcode 15 isn't in CI, I tested it in a one-off `led` test: * [Pre-fix failure](04e485a0b1/+/build.proto
) * [Post-fix success](d454a3e181/+/build.proto
) Fixes https://github.com/flutter/flutter/issues/132755.
This commit is contained in:
parent
312ef54115
commit
b52297da06
@ -19,6 +19,7 @@ import '../build_info.dart';
|
||||
import '../cache.dart';
|
||||
import '../ios/xcodeproj.dart';
|
||||
import '../migrations/cocoapods_script_symlink.dart';
|
||||
import '../migrations/cocoapods_toolchain_directory_migration.dart';
|
||||
import '../reporting/reporting.dart';
|
||||
import '../xcode_project.dart';
|
||||
|
||||
@ -172,6 +173,11 @@ class CocoaPods {
|
||||
// This migrator works around a CocoaPods bug, and should be run after `pod install` is run.
|
||||
final ProjectMigration postPodMigration = ProjectMigration(<ProjectMigrator>[
|
||||
CocoaPodsScriptReadlink(xcodeProject, _xcodeProjectInterpreter, _logger),
|
||||
CocoaPodsToolchainDirectoryMigration(
|
||||
xcodeProject,
|
||||
_xcodeProjectInterpreter,
|
||||
_logger,
|
||||
),
|
||||
]);
|
||||
postPodMigration.run();
|
||||
|
||||
|
@ -0,0 +1,62 @@
|
||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import '../base/file_system.dart';
|
||||
import '../base/project_migrator.dart';
|
||||
import '../base/version.dart';
|
||||
import '../ios/xcodeproj.dart';
|
||||
import '../xcode_project.dart';
|
||||
|
||||
/// Starting in Xcode 15, when building macOS, DT_TOOLCHAIN_DIR cannot be used
|
||||
/// to evaluate LD_RUNPATH_SEARCH_PATHS or LIBRARY_SEARCH_PATHS. `xcodebuild`
|
||||
/// error message recommend using TOOLCHAIN_DIR instead.
|
||||
///
|
||||
/// This has been fixed upstream in CocoaPods, but migrate a copy of their
|
||||
/// workaround so users don't need to update.
|
||||
class CocoaPodsToolchainDirectoryMigration extends ProjectMigrator {
|
||||
CocoaPodsToolchainDirectoryMigration(
|
||||
XcodeBasedProject project,
|
||||
XcodeProjectInterpreter xcodeProjectInterpreter,
|
||||
super.logger,
|
||||
) : _podRunnerTargetSupportFiles = project.podRunnerTargetSupportFiles,
|
||||
_xcodeProjectInterpreter = xcodeProjectInterpreter;
|
||||
|
||||
final Directory _podRunnerTargetSupportFiles;
|
||||
final XcodeProjectInterpreter _xcodeProjectInterpreter;
|
||||
|
||||
@override
|
||||
void migrate() {
|
||||
if (!_podRunnerTargetSupportFiles.existsSync()) {
|
||||
logger.printTrace('CocoaPods Pods-Runner Target Support Files not found, skipping TOOLCHAIN_DIR workaround.');
|
||||
return;
|
||||
}
|
||||
|
||||
final Version? version = _xcodeProjectInterpreter.version;
|
||||
|
||||
// If Xcode not installed or less than 15, skip this migration.
|
||||
if (version == null || version < Version(15, 0, 0)) {
|
||||
logger.printTrace('Detected Xcode version is $version, below 15.0, skipping TOOLCHAIN_DIR workaround.');
|
||||
return;
|
||||
}
|
||||
|
||||
final List<FileSystemEntity> files = _podRunnerTargetSupportFiles.listSync();
|
||||
for (final FileSystemEntity file in files) {
|
||||
if (file.basename.endsWith('xcconfig') && file is File) {
|
||||
processFileLines(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
String? migrateLine(String line) {
|
||||
final String trimmedString = line.trim();
|
||||
if (trimmedString.startsWith('LD_RUNPATH_SEARCH_PATHS') || trimmedString.startsWith('LIBRARY_SEARCH_PATHS')) {
|
||||
const String originalReadLinkLine = r'{DT_TOOLCHAIN_DIR}';
|
||||
const String replacementReadLinkLine = r'{TOOLCHAIN_DIR}';
|
||||
|
||||
return line.replaceAll(originalReadLinkLine, replacementReadLinkLine);
|
||||
}
|
||||
return line;
|
||||
}
|
||||
}
|
@ -104,11 +104,14 @@ abstract class XcodeBasedProject extends FlutterProjectPlatform {
|
||||
File get podManifestLock => hostAppRoot.childDirectory('Pods').childFile('Manifest.lock');
|
||||
|
||||
/// The CocoaPods generated 'Pods-Runner-frameworks.sh'.
|
||||
File get podRunnerFrameworksScript => hostAppRoot
|
||||
File get podRunnerFrameworksScript => podRunnerTargetSupportFiles
|
||||
.childFile('Pods-Runner-frameworks.sh');
|
||||
|
||||
/// The CocoaPods generated directory 'Pods-Runner'.
|
||||
Directory get podRunnerTargetSupportFiles => hostAppRoot
|
||||
.childDirectory('Pods')
|
||||
.childDirectory('Target Support Files')
|
||||
.childDirectory('Pods-Runner')
|
||||
.childFile('Pods-Runner-frameworks.sh');
|
||||
.childDirectory('Pods-Runner');
|
||||
}
|
||||
|
||||
/// Represents the iOS sub-project of a Flutter project.
|
||||
|
@ -16,6 +16,7 @@ import 'package:flutter_tools/src/ios/migrations/remove_framework_link_and_embed
|
||||
import 'package:flutter_tools/src/ios/migrations/xcode_build_system_migration.dart';
|
||||
import 'package:flutter_tools/src/ios/xcodeproj.dart';
|
||||
import 'package:flutter_tools/src/migrations/cocoapods_script_symlink.dart';
|
||||
import 'package:flutter_tools/src/migrations/cocoapods_toolchain_directory_migration.dart';
|
||||
import 'package:flutter_tools/src/migrations/xcode_project_object_version_migration.dart';
|
||||
import 'package:flutter_tools/src/migrations/xcode_script_build_phase_migration.dart';
|
||||
import 'package:flutter_tools/src/migrations/xcode_thin_binary_build_phase_input_paths_migration.dart';
|
||||
@ -1003,6 +1004,150 @@ platform :ios, '11.0'
|
||||
expect(testLogger.statusText, contains('Upgrading Pods-Runner-frameworks.sh'));
|
||||
});
|
||||
});
|
||||
|
||||
group('Cocoapods migrate toolchain directory', () {
|
||||
late MemoryFileSystem memoryFileSystem;
|
||||
late BufferLogger testLogger;
|
||||
late FakeIosProject project;
|
||||
late Directory podRunnerTargetSupportFiles;
|
||||
late ProcessManager processManager;
|
||||
late XcodeProjectInterpreter xcode15ProjectInterpreter;
|
||||
|
||||
setUp(() {
|
||||
memoryFileSystem = MemoryFileSystem();
|
||||
podRunnerTargetSupportFiles = memoryFileSystem.directory('Pods-Runner');
|
||||
testLogger = BufferLogger.test();
|
||||
project = FakeIosProject();
|
||||
processManager = FakeProcessManager.any();
|
||||
xcode15ProjectInterpreter = XcodeProjectInterpreter.test(processManager: processManager, version: Version(15, 0, 0));
|
||||
project.podRunnerTargetSupportFiles = podRunnerTargetSupportFiles;
|
||||
});
|
||||
|
||||
testWithoutContext('skip if directory is missing', () {
|
||||
final CocoaPodsToolchainDirectoryMigration iosProjectMigration = CocoaPodsToolchainDirectoryMigration(
|
||||
project,
|
||||
xcode15ProjectInterpreter,
|
||||
testLogger,
|
||||
);
|
||||
iosProjectMigration.migrate();
|
||||
expect(podRunnerTargetSupportFiles.existsSync(), isFalse);
|
||||
|
||||
expect(testLogger.traceText, contains('CocoaPods Pods-Runner Target Support Files not found'));
|
||||
expect(testLogger.statusText, isEmpty);
|
||||
});
|
||||
|
||||
testWithoutContext('skip if xcconfig files are missing', () {
|
||||
podRunnerTargetSupportFiles.createSync();
|
||||
final CocoaPodsToolchainDirectoryMigration iosProjectMigration = CocoaPodsToolchainDirectoryMigration(
|
||||
project,
|
||||
xcode15ProjectInterpreter,
|
||||
testLogger,
|
||||
);
|
||||
iosProjectMigration.migrate();
|
||||
expect(podRunnerTargetSupportFiles.existsSync(), isTrue);
|
||||
expect(testLogger.traceText, isEmpty);
|
||||
expect(testLogger.statusText, isEmpty);
|
||||
});
|
||||
|
||||
testWithoutContext('skip if nothing to upgrade', () {
|
||||
podRunnerTargetSupportFiles.createSync();
|
||||
final File debugConfig = podRunnerTargetSupportFiles.childFile('Pods-Runner.debug.xcconfig');
|
||||
const String contents = r'''
|
||||
LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/../Frameworks' '@loader_path/Frameworks' "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
|
||||
LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift
|
||||
''';
|
||||
debugConfig.writeAsStringSync(contents);
|
||||
|
||||
final File profileConfig = podRunnerTargetSupportFiles.childFile('Pods-Runner.profile.xcconfig');
|
||||
profileConfig.writeAsStringSync(contents);
|
||||
|
||||
final File releaseConfig = podRunnerTargetSupportFiles.childFile('Pods-Runner.release.xcconfig');
|
||||
releaseConfig.writeAsStringSync(contents);
|
||||
|
||||
final CocoaPodsToolchainDirectoryMigration iosProjectMigration = CocoaPodsToolchainDirectoryMigration(
|
||||
project,
|
||||
xcode15ProjectInterpreter,
|
||||
testLogger,
|
||||
);
|
||||
iosProjectMigration.migrate();
|
||||
expect(debugConfig.existsSync(), isTrue);
|
||||
expect(testLogger.traceText, isEmpty);
|
||||
expect(testLogger.statusText, isEmpty);
|
||||
});
|
||||
|
||||
testWithoutContext('skipped if Xcode version below 15', () {
|
||||
podRunnerTargetSupportFiles.createSync();
|
||||
final File debugConfig = podRunnerTargetSupportFiles.childFile('Pods-Runner.debug.xcconfig');
|
||||
const String contents = r'''
|
||||
LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/../Frameworks' '@loader_path/Frameworks' "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
|
||||
LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift
|
||||
''';
|
||||
debugConfig.writeAsStringSync(contents);
|
||||
|
||||
final File profileConfig = podRunnerTargetSupportFiles.childFile('Pods-Runner.profile.xcconfig');
|
||||
profileConfig.writeAsStringSync(contents);
|
||||
|
||||
final File releaseConfig = podRunnerTargetSupportFiles.childFile('Pods-Runner.release.xcconfig');
|
||||
releaseConfig.writeAsStringSync(contents);
|
||||
|
||||
final XcodeProjectInterpreter xcode14ProjectInterpreter = XcodeProjectInterpreter.test(
|
||||
processManager: processManager,
|
||||
version: Version(14, 0, 0),
|
||||
);
|
||||
|
||||
final CocoaPodsToolchainDirectoryMigration iosProjectMigration = CocoaPodsToolchainDirectoryMigration(
|
||||
project,
|
||||
xcode14ProjectInterpreter,
|
||||
testLogger,
|
||||
);
|
||||
iosProjectMigration.migrate();
|
||||
expect(debugConfig.existsSync(), isTrue);
|
||||
expect(testLogger.traceText, contains('Detected Xcode version is 14.0.0, below 15.0'));
|
||||
expect(testLogger.statusText, isEmpty);
|
||||
});
|
||||
|
||||
testWithoutContext('Xcode project is migrated and ignores leading whitespace', () {
|
||||
podRunnerTargetSupportFiles.createSync();
|
||||
final File debugConfig = podRunnerTargetSupportFiles.childFile('Pods-Runner.debug.xcconfig');
|
||||
const String contents = r'''
|
||||
LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/../Frameworks' '@loader_path/Frameworks' "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
|
||||
LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift
|
||||
''';
|
||||
debugConfig.writeAsStringSync(contents);
|
||||
|
||||
final File profileConfig = podRunnerTargetSupportFiles.childFile('Pods-Runner.profile.xcconfig');
|
||||
profileConfig.writeAsStringSync(contents);
|
||||
|
||||
final File releaseConfig = podRunnerTargetSupportFiles.childFile('Pods-Runner.release.xcconfig');
|
||||
releaseConfig.writeAsStringSync(contents);
|
||||
|
||||
final CocoaPodsToolchainDirectoryMigration iosProjectMigration = CocoaPodsToolchainDirectoryMigration(
|
||||
project,
|
||||
xcode15ProjectInterpreter,
|
||||
testLogger,
|
||||
);
|
||||
iosProjectMigration.migrate();
|
||||
|
||||
expect(debugConfig.existsSync(), isTrue);
|
||||
expect(debugConfig.readAsStringSync(), r'''
|
||||
LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/../Frameworks' '@loader_path/Frameworks' "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
|
||||
LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift
|
||||
''');
|
||||
expect(profileConfig.existsSync(), isTrue);
|
||||
expect(profileConfig.readAsStringSync(), r'''
|
||||
LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/../Frameworks' '@loader_path/Frameworks' "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
|
||||
LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift
|
||||
''');
|
||||
expect(releaseConfig.existsSync(), isTrue);
|
||||
expect(releaseConfig.readAsStringSync(), r'''
|
||||
LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/../Frameworks' '@loader_path/Frameworks' "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
|
||||
LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift
|
||||
''');
|
||||
expect(testLogger.statusText, contains('Upgrading Pods-Runner.debug.xcconfig'));
|
||||
expect(testLogger.statusText, contains('Upgrading Pods-Runner.profile.xcconfig'));
|
||||
expect(testLogger.statusText, contains('Upgrading Pods-Runner.release.xcconfig'));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
group('update Xcode script build phase', () {
|
||||
@ -1239,6 +1384,9 @@ class FakeIosProject extends Fake implements IosProject {
|
||||
|
||||
@override
|
||||
File podRunnerFrameworksScript = MemoryFileSystem.test().file('podRunnerFrameworksScript');
|
||||
|
||||
@override
|
||||
Directory podRunnerTargetSupportFiles = MemoryFileSystem.test().directory('Pods-Runner');
|
||||
}
|
||||
|
||||
class FakeIOSMigrator extends ProjectMigrator {
|
||||
|
Loading…
x
Reference in New Issue
Block a user