Unverified Commit eee0dc84 authored by Jenn Magder's avatar Jenn Magder Committed by GitHub

Exclude arm64 from valid iOS simulators (#73828)

parent effa7d52
...@@ -447,6 +447,7 @@ ...@@ -447,6 +447,7 @@
DEBUG_INFORMATION_FORMAT = dwarf; DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES; ENABLE_TESTABILITY = YES;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
GCC_C_LANGUAGE_STANDARD = gnu11; GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO; GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES; GCC_NO_COMMON_BLOCKS = YES;
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
archiveVersion = 1; archiveVersion = 1;
classes = { classes = {
}; };
objectVersion = 50; objectVersion = 51;
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
...@@ -56,7 +56,6 @@ ...@@ -56,7 +56,6 @@
5EF266650049BC10ECFD8C86 /* Pods-Host.debug.xcconfig */, 5EF266650049BC10ECFD8C86 /* Pods-Host.debug.xcconfig */,
A412A4193ADC80C963762A82 /* Pods-Host.release.xcconfig */, A412A4193ADC80C963762A82 /* Pods-Host.release.xcconfig */,
); );
name = Pods;
path = Pods; path = Pods;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
...@@ -200,7 +199,7 @@ ...@@ -200,7 +199,7 @@
name = "[CP-User] Run Flutter Build hello Script"; name = "[CP-User] Run Flutter Build hello Script";
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "set -e\nset -u\nsource \"${SRCROOT}/../hello/.ios/Flutter/flutter_export_environment.sh\"\n\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/xcode_backend.sh build"; shellScript = "set -e\nset -u\nsource \"${SRCROOT}/../hello/.ios/Flutter/flutter_export_environment.sh\"\n\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/xcode_backend.sh build\n";
}; };
96286B727046BA8457A788D0 /* [CP] Copy Pods Resources */ = { 96286B727046BA8457A788D0 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
...@@ -391,6 +390,7 @@ ...@@ -391,6 +390,7 @@
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
INFOPLIST_FILE = Host/Info.plist; INFOPLIST_FILE = Host/Info.plist;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
......
...@@ -68,6 +68,9 @@ def flutter_additional_ios_build_settings(target) ...@@ -68,6 +68,9 @@ def flutter_additional_ios_build_settings(target)
# When deleted, the deployment version will inherit from the higher version derived from the 'Runner' target. # When deleted, the deployment version will inherit from the higher version derived from the 'Runner' target.
# If the pod only supports a higher version, do not delete to correctly produce an error. # If the pod only supports a higher version, do not delete to correctly produce an error.
build_configuration.build_settings.delete 'IPHONEOS_DEPLOYMENT_TARGET' if inherit_deployment_target build_configuration.build_settings.delete 'IPHONEOS_DEPLOYMENT_TARGET' if inherit_deployment_target
# Apple Silicon ARM simulators not yet supported.
build_configuration.build_settings['EXCLUDED_ARCHS[sdk=iphonesimulator*]'] = 'arm64 i386'
end end
end end
......
...@@ -255,7 +255,7 @@ Future<XcodeBuildResult> buildXcodeProject({ ...@@ -255,7 +255,7 @@ Future<XcodeBuildResult> buildXcodeProject({
if (buildForDevice) { if (buildForDevice) {
buildCommands.addAll(<String>['-sdk', 'iphoneos']); buildCommands.addAll(<String>['-sdk', 'iphoneos']);
} else { } else {
buildCommands.addAll(<String>['-sdk', 'iphonesimulator', '-arch', 'x86_64']); buildCommands.addAll(<String>['-sdk', 'iphonesimulator']);
} }
} }
......
...@@ -111,7 +111,9 @@ void _updateGeneratedEnvironmentVariablesScript({ ...@@ -111,7 +111,9 @@ void _updateGeneratedEnvironmentVariablesScript({
localsBuffer.writeln('#!/bin/sh'); localsBuffer.writeln('#!/bin/sh');
localsBuffer.writeln('# This is a generated file; do not edit or check into version control.'); localsBuffer.writeln('# This is a generated file; do not edit or check into version control.');
for (final String line in xcodeBuildSettings) { for (final String line in xcodeBuildSettings) {
localsBuffer.writeln('export "$line"'); if (!line.contains('[')) { // Exported conditional Xcode build settings do not work.
localsBuffer.writeln('export "$line"');
}
} }
final File generatedModuleBuildPhaseScript = useMacOSConfig final File generatedModuleBuildPhaseScript = useMacOSConfig
...@@ -226,6 +228,9 @@ List<String> _xcodeBuildSettingsLines({ ...@@ -226,6 +228,9 @@ List<String> _xcodeBuildSettingsLines({
if (useMacOSConfig) { if (useMacOSConfig) {
// ARM not yet supported https://github.com/flutter/flutter/issues/69221 // ARM not yet supported https://github.com/flutter/flutter/issues/69221
xcodeBuildSettings.add('EXCLUDED_ARCHS=arm64'); xcodeBuildSettings.add('EXCLUDED_ARCHS=arm64');
} else {
// Apple Silicon ARM simulators not yet supported.
xcodeBuildSettings.add('EXCLUDED_ARCHS[sdk=iphonesimulator*]=arm64 i386');
} }
for (final MapEntry<String, String> config in buildInfo.toEnvironmentConfig().entries) { for (final MapEntry<String, String> config in buildInfo.toEnvironmentConfig().entries) {
......
...@@ -671,12 +671,14 @@ Information about project "Runner": ...@@ -671,12 +671,14 @@ Information about project "Runner":
final String contents = config.readAsStringSync(); final String contents = config.readAsStringSync();
expect(contents.contains('ARCHS=armv7'), isTrue); expect(contents.contains('ARCHS=armv7'), isTrue);
expect(contents.contains('EXCLUDED_ARCHS[sdk=iphonesimulator*]=arm64 i386'), isTrue);
final File buildPhaseScript = fs.file('path/to/project/ios/Flutter/flutter_export_environment.sh'); final File buildPhaseScript = fs.file('path/to/project/ios/Flutter/flutter_export_environment.sh');
expect(buildPhaseScript.existsSync(), isTrue); expect(buildPhaseScript.existsSync(), isTrue);
final String buildPhaseScriptContents = buildPhaseScript.readAsStringSync(); final String buildPhaseScriptContents = buildPhaseScript.readAsStringSync();
expect(buildPhaseScriptContents.contains('ARCHS=armv7'), isTrue); expect(buildPhaseScriptContents.contains('ARCHS=armv7'), isTrue);
expect(buildPhaseScriptContents.contains('EXCLUDED_ARCHS'), isFalse);
}); });
testUsingOsxContext('sets TRACK_WIDGET_CREATION=true when trackWidgetCreation is true', () async { testUsingOsxContext('sets TRACK_WIDGET_CREATION=true when trackWidgetCreation is true', () async {
......
...@@ -43,10 +43,7 @@ void main() { ...@@ -43,10 +43,7 @@ void main() {
// Config is updated if command succeeded. // Config is updated if command succeeded.
expect(generatedConfig, exists); expect(generatedConfig, exists);
expect(generatedConfig.readAsStringSync(), allOf( expect(generatedConfig.readAsStringSync(), contains('DART_OBFUSCATION=true'));
contains('DART_OBFUSCATION=true'),
isNot(contains('EXCLUDED_ARCHS')),
));
// file that only exists if app was fully built. // file that only exists if app was fully built.
final File frameworkPlist = fileSystem.file( final File frameworkPlist = fileSystem.file(
......
...@@ -14,200 +14,258 @@ import '../src/darwin_common.dart'; ...@@ -14,200 +14,258 @@ import '../src/darwin_common.dart';
import 'test_utils.dart'; import 'test_utils.dart';
void main() { void main() {
for (final BuildMode buildMode in <BuildMode>[BuildMode.debug, BuildMode.release]) { group('iOS app validation', () {
group(buildMode.name, () { String flutterRoot;
String flutterRoot; String projectRoot;
String projectRoot; String flutterBin;
String flutterBin; Directory tempDir;
Directory tempDir;
Directory buildPath;
Directory outputApp;
Directory frameworkDirectory;
Directory outputFlutterFramework;
File outputFlutterFrameworkBinary;
Directory outputAppFramework;
File outputAppFrameworkBinary;
setUpAll(() {
flutterRoot = getFlutterRoot();
tempDir = createResolvedTempDirectorySync('ios_content_validation.');
flutterBin = fileSystem.path.join(
flutterRoot,
'bin',
'flutter',
);
processManager.runSync(<String>[
flutterBin,
...getLocalEngineArguments(),
'create',
'--platforms=ios',
'-i',
'objc',
'hello',
], workingDirectory: tempDir.path);
projectRoot = tempDir.childDirectory('hello').path; setUpAll(() {
flutterRoot = getFlutterRoot();
tempDir = createResolvedTempDirectorySync('ios_content_validation.');
flutterBin = fileSystem.path.join(
flutterRoot,
'bin',
'flutter',
);
processManager.runSync(<String>[ processManager.runSync(<String>[
flutterBin, flutterBin,
...getLocalEngineArguments(), ...getLocalEngineArguments(),
'build', 'create',
'ios', '--platforms=ios',
'--verbose', '-i',
'--no-codesign', 'objc',
'--${buildMode.name}', 'hello',
'--obfuscate', ], workingDirectory: tempDir.path);
'--split-debug-info=foo/',
], workingDirectory: projectRoot);
buildPath = fileSystem.directory(fileSystem.path.join( projectRoot = tempDir.childDirectory('hello').path;
projectRoot, });
'build',
'ios',
'iphoneos',
));
outputApp = buildPath.childDirectory('Runner.app'); tearDownAll(() {
tryToDelete(tempDir);
});
frameworkDirectory = outputApp.childDirectory('Frameworks'); for (final BuildMode buildMode in <BuildMode>[BuildMode.debug, BuildMode.release]) {
outputFlutterFramework = frameworkDirectory.childDirectory('Flutter.framework'); group('build in ${buildMode.name} mode', () {
outputFlutterFrameworkBinary = outputFlutterFramework.childFile('Flutter'); Directory buildPath;
Directory outputApp;
Directory frameworkDirectory;
Directory outputFlutterFramework;
File outputFlutterFrameworkBinary;
Directory outputAppFramework;
File outputAppFrameworkBinary;
outputAppFramework = frameworkDirectory.childDirectory('App.framework'); setUpAll(() {
outputAppFrameworkBinary = outputAppFramework.childFile('App'); flutterRoot = getFlutterRoot();
}); tempDir = createResolvedTempDirectorySync('ios_content_validation.');
flutterBin = fileSystem.path.join(
flutterRoot,
'bin',
'flutter',
);
tearDownAll(() { processManager.runSync(<String>[
tryToDelete(tempDir); flutterBin,
}); ...getLocalEngineArguments(),
'create',
'--platforms=ios',
'-i',
'objc',
'hello',
], workingDirectory: tempDir.path);
testWithoutContext('flutter build ios builds a valid app', () { projectRoot = tempDir.childDirectory('hello').path;
// Should only contain Flutter.framework and App.framework.
expect(frameworkDirectory.listSync().length, 2);
expect(outputAppFramework.childFile('App'), exists);
final File vmSnapshot = fileSystem.file(fileSystem.path.join( processManager.runSync(<String>[
outputAppFramework.path, flutterBin,
'flutter_assets', ...getLocalEngineArguments(),
'vm_snapshot_data', 'build',
)); 'ios',
'--verbose',
'--no-codesign',
'--${buildMode.name}',
'--obfuscate',
'--split-debug-info=foo/',
], workingDirectory: projectRoot);
expect(vmSnapshot.existsSync(), buildMode == BuildMode.debug); buildPath = fileSystem.directory(fileSystem.path.join(
projectRoot,
'build',
'ios',
'iphoneos',
));
expect(outputFlutterFramework.childDirectory('Headers'), isNot(exists)); outputApp = buildPath.childDirectory('Runner.app');
expect(outputFlutterFramework.childDirectory('Modules'), isNot(exists));
// Archiving should contain a bitcode blob, but not building. frameworkDirectory = outputApp.childDirectory('Frameworks');
// This mimics Xcode behavior and prevents a developer from having to install a outputFlutterFramework = frameworkDirectory.childDirectory('Flutter.framework');
// 300+MB app. outputFlutterFrameworkBinary = outputFlutterFramework.childFile('Flutter');
expect(containsBitcode(outputFlutterFrameworkBinary.path, processManager), isFalse);
});
testWithoutContext('Info.plist dart observatory Bonjour service', () { outputAppFramework = frameworkDirectory.childDirectory('App.framework');
final String infoPlistPath = fileSystem.path.join( outputAppFrameworkBinary = outputAppFramework.childFile('App');
outputApp.path, });
'Info.plist',
); testWithoutContext('flutter build ios builds a valid app', () {
final ProcessResult bonjourServices = processManager.runSync( // Should only contain Flutter.framework and App.framework.
<String>[ expect(frameworkDirectory.listSync().length, 2);
'plutil', expect(outputAppFramework.childFile('App'), exists);
'-extract',
'NSBonjourServices', final File vmSnapshot = fileSystem.file(fileSystem.path.join(
'xml1', outputAppFramework.path,
'-o', 'flutter_assets',
'-', 'vm_snapshot_data',
infoPlistPath, ));
],
); expect(vmSnapshot.existsSync(), buildMode == BuildMode.debug);
final bool bonjourServicesFound = (bonjourServices.stdout as String).contains('_dartobservatory._tcp');
expect(bonjourServicesFound, buildMode == BuildMode.debug);
final ProcessResult localNetworkUsage = processManager.runSync(
<String>[
'plutil',
'-extract',
'NSLocalNetworkUsageDescription',
'xml1',
'-o',
'-',
infoPlistPath,
],
);
final bool localNetworkUsageFound = localNetworkUsage.exitCode == 0;
expect(localNetworkUsageFound, buildMode == BuildMode.debug);
});
testWithoutContext('check symbols', () { expect(outputFlutterFramework.childDirectory('Headers'), isNot(exists));
final ProcessResult symbols = processManager.runSync( expect(outputFlutterFramework.childDirectory('Modules'), isNot(exists));
<String>[
'nm', // Archiving should contain a bitcode blob, but not building.
'-g', // This mimics Xcode behavior and prevents a developer from having to install a
// 300+MB app.
expect(containsBitcode(outputFlutterFrameworkBinary.path, processManager), isFalse);
});
testWithoutContext('Info.plist dart observatory Bonjour service', () {
final String infoPlistPath = fileSystem.path.join(
outputApp.path,
'Info.plist',
);
final ProcessResult bonjourServices = processManager.runSync(
<String>[
'plutil',
'-extract',
'NSBonjourServices',
'xml1',
'-o',
'-',
infoPlistPath,
],
);
final bool bonjourServicesFound = (bonjourServices.stdout as String).contains('_dartobservatory._tcp');
expect(bonjourServicesFound, buildMode == BuildMode.debug);
final ProcessResult localNetworkUsage = processManager.runSync(
<String>[
'plutil',
'-extract',
'NSLocalNetworkUsageDescription',
'xml1',
'-o',
'-',
infoPlistPath,
],
);
final bool localNetworkUsageFound = localNetworkUsage.exitCode == 0;
expect(localNetworkUsageFound, buildMode == BuildMode.debug);
});
testWithoutContext('check symbols', () {
final ProcessResult symbols = processManager.runSync(
<String>[
'nm',
'-g',
outputAppFrameworkBinary.path,
'-arch',
'arm64',
],
);
final bool aotSymbolsFound = (symbols.stdout as String).contains('_kDartVmSnapshot');
expect(aotSymbolsFound, buildMode != BuildMode.debug);
});
testWithoutContext('xcode_backend embed_and_thin', () {
outputFlutterFramework.deleteSync(recursive: true);
outputAppFramework.deleteSync(recursive: true);
expect(outputFlutterFrameworkBinary.existsSync(), isFalse);
expect(outputAppFrameworkBinary.existsSync(), isFalse);
final String xcodeBackendPath = fileSystem.path.join(
flutterRoot,
'packages',
'flutter_tools',
'bin',
'xcode_backend.sh',
);
// Simulate a common Xcode build setting misconfiguration
// where FLUTTER_APPLICATION_PATH is missing
final ProcessResult xcodeBackendResult = processManager.runSync(
<String>[
xcodeBackendPath,
'embed_and_thin',
],
environment: <String, String>{
'SOURCE_ROOT': fileSystem.path.join(projectRoot, 'ios'),
'BUILT_PRODUCTS_DIR': fileSystem.path.join(
projectRoot,
'build',
'ios',
'Release-iphoneos',
),
'TARGET_BUILD_DIR': buildPath.path,
'FRAMEWORKS_FOLDER_PATH': 'Runner.app/Frameworks',
'VERBOSE_SCRIPT_LOGGING': '1',
'FLUTTER_BUILD_MODE': 'release',
'ACTION': 'install',
// Skip bitcode stripping since we just checked that above.
},
);
expect(xcodeBackendResult.exitCode, 0);
expect(outputFlutterFrameworkBinary.existsSync(), isTrue);
expect(outputAppFrameworkBinary.existsSync(), isTrue);
}, skip: !platform.isMacOS || buildMode != BuildMode.release);
testWithoutContext('validate obfuscation', () {
final ProcessResult grepResult = processManager.runSync(<String>[
'grep',
'-i',
'hello',
outputAppFrameworkBinary.path, outputAppFrameworkBinary.path,
'-arch', ]);
'arm64', expect(grepResult.stdout, isNot(contains('matches')));
], });
);
final bool aotSymbolsFound = (symbols.stdout as String).contains('_kDartVmSnapshot');
expect(aotSymbolsFound, buildMode != BuildMode.debug);
}); });
}
testWithoutContext('xcode_backend embed_and_thin', () { testWithoutContext('build for simulator with all available architectures', () {
outputFlutterFramework.deleteSync(recursive: true); final ProcessResult buildSimulator = processManager.runSync(
outputAppFramework.deleteSync(recursive: true); <String>[
expect(outputFlutterFrameworkBinary.existsSync(), isFalse); flutterBin,
expect(outputAppFrameworkBinary.existsSync(), isFalse); ...getLocalEngineArguments(),
'build',
final String xcodeBackendPath = fileSystem.path.join( 'ios',
flutterRoot, '--simulator',
'packages', '--verbose',
'flutter_tools', '--no-codesign',
'bin', ],
'xcode_backend.sh', workingDirectory: projectRoot,
); environment: <String, String>{
'FLUTTER_XCODE_ONLY_ACTIVE_ARCH': 'NO',
// Simulate a common Xcode build setting misconfiguration },
// where FLUTTER_APPLICATION_PATH is missing );
final ProcessResult xcodeBackendResult = processManager.runSync( // This test case would fail if arm64 or i386 were not excluded.
<String>[ expect(buildSimulator.exitCode, 0);
xcodeBackendPath,
'embed_and_thin', final File simulatorAppFrameworkBinary = fileSystem.file(fileSystem.path.join(
], projectRoot,
environment: <String, String>{ 'build',
'SOURCE_ROOT': fileSystem.path.join(projectRoot, 'ios'), 'ios',
'BUILT_PRODUCTS_DIR': fileSystem.path.join( 'iphonesimulator',
projectRoot, 'Runner.app',
'build', 'Frameworks',
'ios', 'App.framework',
'Release-iphoneos', 'App',
), ));
'TARGET_BUILD_DIR': buildPath.path, expect(simulatorAppFrameworkBinary, exists);
'FRAMEWORKS_FOLDER_PATH': 'Runner.app/Frameworks', final ProcessResult archs = processManager.runSync(
'VERBOSE_SCRIPT_LOGGING': '1', <String>['file', simulatorAppFrameworkBinary.path],
'FLUTTER_BUILD_MODE': 'release', );
'ACTION': 'install', expect(archs.stdout, contains('Mach-O 64-bit dynamically linked shared library x86_64'));
// Skip bitcode stripping since we just checked that above. });
}, }, skip: !platform.isMacOS, timeout: const Timeout(Duration(minutes: 5))
); );
expect(xcodeBackendResult.exitCode, 0);
expect(outputFlutterFrameworkBinary.existsSync(), isTrue);
expect(outputAppFrameworkBinary.existsSync(), isTrue);
}, skip: !platform.isMacOS || buildMode != BuildMode.release);
testWithoutContext('validate obfuscation', () {
final ProcessResult grepResult = processManager.runSync(<String>[
'grep',
'-i',
'hello',
outputAppFrameworkBinary.path,
]);
expect(grepResult.stdout, isNot(contains('matches')));
});
},
skip: !platform.isMacOS,
timeout: const Timeout(Duration(minutes: 5)),
);
}
} }
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