Unverified Commit b52297da authored by Victoria Ashworth's avatar Victoria Ashworth Committed by GitHub

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](https://luci-milo.appspot.com/raw/build/logs.chromium.org/flutter/led/vashworth_google.com/04e485a0b152a0720f5e561266f7a6e4fb64fc76227fcacc95b67486ae2771e7/+/build.proto)
* [Post-fix success](https://luci-milo.appspot.com/raw/build/logs.chromium.org/flutter/led/vashworth_google.com/d454a3e181e1a97692bdc1fcc197738fe04e4acf1cb20026fd040fd78513f3b0/+/build.proto)

Fixes https://github.com/flutter/flutter/issues/132755.
parent 312ef541
...@@ -19,6 +19,7 @@ import '../build_info.dart'; ...@@ -19,6 +19,7 @@ import '../build_info.dart';
import '../cache.dart'; import '../cache.dart';
import '../ios/xcodeproj.dart'; import '../ios/xcodeproj.dart';
import '../migrations/cocoapods_script_symlink.dart'; import '../migrations/cocoapods_script_symlink.dart';
import '../migrations/cocoapods_toolchain_directory_migration.dart';
import '../reporting/reporting.dart'; import '../reporting/reporting.dart';
import '../xcode_project.dart'; import '../xcode_project.dart';
...@@ -172,6 +173,11 @@ class CocoaPods { ...@@ -172,6 +173,11 @@ class CocoaPods {
// This migrator works around a CocoaPods bug, and should be run after `pod install` is run. // This migrator works around a CocoaPods bug, and should be run after `pod install` is run.
final ProjectMigration postPodMigration = ProjectMigration(<ProjectMigrator>[ final ProjectMigration postPodMigration = ProjectMigration(<ProjectMigrator>[
CocoaPodsScriptReadlink(xcodeProject, _xcodeProjectInterpreter, _logger), CocoaPodsScriptReadlink(xcodeProject, _xcodeProjectInterpreter, _logger),
CocoaPodsToolchainDirectoryMigration(
xcodeProject,
_xcodeProjectInterpreter,
_logger,
),
]); ]);
postPodMigration.run(); postPodMigration.run();
......
// 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 { ...@@ -104,11 +104,14 @@ abstract class XcodeBasedProject extends FlutterProjectPlatform {
File get podManifestLock => hostAppRoot.childDirectory('Pods').childFile('Manifest.lock'); File get podManifestLock => hostAppRoot.childDirectory('Pods').childFile('Manifest.lock');
/// The CocoaPods generated 'Pods-Runner-frameworks.sh'. /// 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('Pods')
.childDirectory('Target Support Files') .childDirectory('Target Support Files')
.childDirectory('Pods-Runner') .childDirectory('Pods-Runner');
.childFile('Pods-Runner-frameworks.sh');
} }
/// Represents the iOS sub-project of a Flutter project. /// 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 ...@@ -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/migrations/xcode_build_system_migration.dart';
import 'package:flutter_tools/src/ios/xcodeproj.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_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_project_object_version_migration.dart';
import 'package:flutter_tools/src/migrations/xcode_script_build_phase_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'; import 'package:flutter_tools/src/migrations/xcode_thin_binary_build_phase_input_paths_migration.dart';
...@@ -1003,6 +1004,150 @@ platform :ios, '11.0' ...@@ -1003,6 +1004,150 @@ platform :ios, '11.0'
expect(testLogger.statusText, contains('Upgrading Pods-Runner-frameworks.sh')); 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', () { group('update Xcode script build phase', () {
...@@ -1239,6 +1384,9 @@ class FakeIosProject extends Fake implements IosProject { ...@@ -1239,6 +1384,9 @@ class FakeIosProject extends Fake implements IosProject {
@override @override
File podRunnerFrameworksScript = MemoryFileSystem.test().file('podRunnerFrameworksScript'); File podRunnerFrameworksScript = MemoryFileSystem.test().file('podRunnerFrameworksScript');
@override
Directory podRunnerTargetSupportFiles = MemoryFileSystem.test().directory('Pods-Runner');
} }
class FakeIOSMigrator extends ProjectMigrator { class FakeIOSMigrator extends ProjectMigrator {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment