Run more xcodebuild commands in native arm on Apple Silicon (#69837)
diff --git a/packages/flutter_tools/lib/src/ios/xcodeproj.dart b/packages/flutter_tools/lib/src/ios/xcodeproj.dart index 043179e..0a39a87 100644 --- a/packages/flutter_tools/lib/src/ios/xcodeproj.dart +++ b/packages/flutter_tools/lib/src/ios/xcodeproj.dart
@@ -10,6 +10,7 @@ import '../base/file_system.dart'; import '../base/io.dart'; import '../base/logger.dart'; +import '../base/os.dart'; import '../base/platform.dart'; import '../base/process.dart'; import '../base/terminal.dart'; @@ -242,26 +243,32 @@ _terminal = terminal, _logger = logger, _processUtils = ProcessUtils(logger: logger, processManager: processManager), + _operatingSystemUtils = OperatingSystemUtils( + fileSystem: fileSystem, + logger: logger, + platform: platform, + processManager: processManager, + ), _usage = usage; final Platform _platform; final FileSystem _fileSystem; final ProcessUtils _processUtils; + final OperatingSystemUtils _operatingSystemUtils; final Terminal _terminal; final Logger _logger; final Usage _usage; - static const String _executable = '/usr/bin/xcodebuild'; static final RegExp _versionRegex = RegExp(r'Xcode ([0-9.]+)'); void _updateVersion() { - if (!_platform.isMacOS || !_fileSystem.file(_executable).existsSync()) { + if (!_platform.isMacOS || !_fileSystem.file('/usr/bin/xcodebuild').existsSync()) { return; } try { if (_versionText == null) { final RunResult result = _processUtils.runSync( - <String>[_executable, '-version'], + <String>[...xcrunCommand(), 'xcodebuild', '-version'], ); if (result.exitCode != 0) { return; @@ -316,6 +323,25 @@ return _patchVersion; } + /// The `xcrun` Xcode command to run or locate development + /// tools and properties. + /// + /// Returns `xcrun` on x86 macOS. + /// Returns `/usr/bin/arch -arm64e xcrun` on ARM macOS to force Xcode commands + /// to run outside the x86 Rosetta translation, which may cause crashes. + List<String> xcrunCommand() { + final List<String> xcrunCommand = <String>[]; + if (_operatingSystemUtils.hostPlatform == HostPlatform.darwin_arm) { + // Force Xcode commands to run outside Rosetta. + xcrunCommand.addAll(<String>[ + '/usr/bin/arch', + '-arm64e', + ]); + } + xcrunCommand.add('xcrun'); + return xcrunCommand; + } + /// Asynchronously retrieve xcode build settings. This one is preferred for /// new call-sites. /// @@ -331,7 +357,8 @@ terminal: _terminal, ); final List<String> showBuildSettingsCommand = <String>[ - _executable, + ...xcrunCommand(), + 'xcodebuild', '-project', _fileSystem.path.absolute(projectPath), if (scheme != null) @@ -368,7 +395,8 @@ Future<void> cleanWorkspace(String workspacePath, String scheme, { bool verbose = false }) async { await _processUtils.run(<String>[ - _executable, + ...xcrunCommand(), + 'xcodebuild', '-workspace', workspacePath, '-scheme', @@ -387,7 +415,8 @@ const int missingProjectExitCode = 66; final RunResult result = await _processUtils.run( <String>[ - _executable, + ...xcrunCommand(), + 'xcodebuild', '-list', if (projectFilename != null) ...<String>['-project', projectFilename], ],