Commit dc99d61e authored by Jenn Magder's avatar Jenn Magder Committed by Flutter GitHub Bot

Remove simulator arch in Profile and Release, App.xcframework (#48002)

parent a6c3ffe1
...@@ -80,61 +80,51 @@ Future<void> main() async { ...@@ -80,61 +80,51 @@ Future<void> main() async {
'App', 'App',
)); ));
final String appFrameworkPath = path.join( final String debugAppFrameworkPath = path.join(
outputPath, outputPath,
'Debug', 'Debug',
'App.framework', 'App.framework',
'App', 'App',
); );
final String aotSymbols = await dylibSymbols(appFrameworkPath); final String aotSymbols = await dylibSymbols(debugAppFrameworkPath);
if (aotSymbols.contains('architecture') || if (aotSymbols.contains('architecture') ||
aotSymbols.contains('_kDartVmSnapshot')) { aotSymbols.contains('_kDartVmSnapshot')) {
throw TaskResult.failure('Debug App.framework contains AOT'); throw TaskResult.failure('Debug App.framework contains AOT');
} }
await _checkFrameworkArchs(debugAppFrameworkPath, 'Debug');
final String debugAppArchs = await fileType(appFrameworkPath);
if (!debugAppArchs.contains('armv7')) {
throw TaskResult.failure('Debug App.framework armv7 architecture missing');
}
if (!debugAppArchs.contains('arm64')) {
throw TaskResult.failure('Debug App.framework arm64 architecture missing');
}
if (!debugAppArchs.contains('x86_64')) {
throw TaskResult.failure('Debug App.framework x86_64 architecture missing');
}
section('Check profile, release builds has Dart AOT dylib');
for (String mode in <String>['Profile', 'Release']) {
checkFileExists(path.join( checkFileExists(path.join(
outputPath, outputPath,
mode, 'Debug',
'App.xcframework',
'ios-armv7_arm64',
'App.framework', 'App.framework',
'App', 'App',
)); ));
final String aotSymbols = await dylibSymbols(path.join( checkFileExists(path.join(
outputPath, outputPath,
mode, 'Debug',
'App.xcframework',
'ios-x86_64-simulator',
'App.framework', 'App.framework',
'App', 'App',
)); ));
if (!aotSymbols.contains('armv7')) { section('Check profile, release builds has Dart AOT dylib');
throw TaskResult.failure('$mode App.framework armv7 architecture missing');
}
if (!aotSymbols.contains('arm64')) { for (String mode in <String>['Profile', 'Release']) {
throw TaskResult.failure('$mode App.framework arm64 architecture missing'); final String appFrameworkPath = path.join(
} outputPath,
mode,
'App.framework',
'App',
);
if (aotSymbols.contains('x86_64')) { await _checkFrameworkArchs(appFrameworkPath, mode);
throw TaskResult.failure('$mode App.framework contains x86_64 architecture');
} final String aotSymbols = await dylibSymbols(appFrameworkPath);
if (!aotSymbols.contains('_kDartVmSnapshot')) { if (!aotSymbols.contains('_kDartVmSnapshot')) {
throw TaskResult.failure('$mode App.framework missing Dart AOT'); throw TaskResult.failure('$mode App.framework missing Dart AOT');
...@@ -147,17 +137,38 @@ Future<void> main() async { ...@@ -147,17 +137,38 @@ Future<void> main() async {
'flutter_assets', 'flutter_assets',
'vm_snapshot_data', 'vm_snapshot_data',
)); ));
checkFileExists(path.join(
outputPath,
mode,
'App.xcframework',
'ios-armv7_arm64',
'App.framework',
'App',
));
checkFileNotExists(path.join(
outputPath,
mode,
'App.xcframework',
'ios-x86_64-simulator',
'App.framework',
'App',
));
} }
section("Check all modes' engine dylib"); section("Check all modes' engine dylib");
for (String mode in <String>['Debug', 'Profile', 'Release']) { for (String mode in <String>['Debug', 'Profile', 'Release']) {
checkFileExists(path.join( final String engineFrameworkPath = path.join(
outputPath, outputPath,
mode, mode,
'Flutter.framework', 'Flutter.framework',
'Flutter', 'Flutter',
)); );
await _checkFrameworkArchs(engineFrameworkPath, mode);
checkFileExists(path.join( checkFileExists(path.join(
outputPath, outputPath,
mode, mode,
...@@ -166,14 +177,19 @@ Future<void> main() async { ...@@ -166,14 +177,19 @@ Future<void> main() async {
'Flutter.framework', 'Flutter.framework',
'Flutter', 'Flutter',
)); ));
checkFileExists(path.join( final String simulatorFrameworkPath = path.join(
outputPath, outputPath,
mode, mode,
'Flutter.xcframework', 'Flutter.xcframework',
'ios-x86_64-simulator', 'ios-x86_64-simulator',
'Flutter.framework', 'Flutter.framework',
'Flutter', 'Flutter',
)); );
if (mode == 'Debug') {
checkFileExists(simulatorFrameworkPath);
} else {
checkFileNotExists(simulatorFrameworkPath);
}
} }
section("Check all modes' engine header"); section("Check all modes' engine header");
...@@ -188,12 +204,14 @@ Future<void> main() async { ...@@ -188,12 +204,14 @@ Future<void> main() async {
section("Check all modes' have plugin dylib"); section("Check all modes' have plugin dylib");
for (String mode in <String>['Debug', 'Profile', 'Release']) { for (String mode in <String>['Debug', 'Profile', 'Release']) {
checkFileExists(path.join( final String pluginFrameworkPath = path.join(
outputPath, outputPath,
mode, mode,
'device_info.framework', 'device_info.framework',
'device_info', 'device_info',
)); );
await _checkFrameworkArchs(pluginFrameworkPath, mode);
checkFileExists(path.join( checkFileExists(path.join(
outputPath, outputPath,
mode, mode,
...@@ -202,19 +220,33 @@ Future<void> main() async { ...@@ -202,19 +220,33 @@ Future<void> main() async {
'device_info.framework', 'device_info.framework',
'device_info', 'device_info',
)); ));
checkFileExists(path.join( final String simulatorFrameworkPath = path.join(
outputPath, outputPath,
mode, mode,
'device_info.xcframework', 'device_info.xcframework',
'ios-x86_64-simulator', 'ios-x86_64-simulator',
'device_info.framework', 'device_info.framework',
'device_info', 'device_info',
)); );
if (mode == 'Debug') {
checkFileExists(simulatorFrameworkPath);
} else {
checkFileNotExists(simulatorFrameworkPath);
}
} }
section("Check all modes' have generated plugin registrant"); section("Check all modes' have generated plugin registrant");
for (String mode in <String>['Debug', 'Profile', 'Release']) { for (String mode in <String>['Debug', 'Profile', 'Release']) {
final String registrantFrameworkPath = path.join(
outputPath,
mode,
'FlutterPluginRegistrant.framework',
'FlutterPluginRegistrant'
);
await _checkFrameworkArchs(registrantFrameworkPath, mode);
checkFileExists(path.join( checkFileExists(path.join(
outputPath, outputPath,
mode, mode,
...@@ -231,7 +263,7 @@ Future<void> main() async { ...@@ -231,7 +263,7 @@ Future<void> main() async {
'Headers', 'Headers',
'GeneratedPluginRegistrant.h', 'GeneratedPluginRegistrant.h',
)); ));
checkFileExists(path.join( final String simulatorHeaderPath = path.join(
outputPath, outputPath,
mode, mode,
'FlutterPluginRegistrant.xcframework', 'FlutterPluginRegistrant.xcframework',
...@@ -239,7 +271,12 @@ Future<void> main() async { ...@@ -239,7 +271,12 @@ Future<void> main() async {
'FlutterPluginRegistrant.framework', 'FlutterPluginRegistrant.framework',
'Headers', 'Headers',
'GeneratedPluginRegistrant.h', 'GeneratedPluginRegistrant.h',
)); );
if (mode == 'Debug') {
checkFileExists(simulatorHeaderPath);
} else {
checkFileNotExists(simulatorHeaderPath);
}
} }
return TaskResult.success(null); return TaskResult.success(null);
...@@ -252,3 +289,24 @@ Future<void> main() async { ...@@ -252,3 +289,24 @@ Future<void> main() async {
} }
}); });
} }
Future<void> _checkFrameworkArchs(String frameworkPath, String mode) async {
checkFileExists(frameworkPath);
final String archs = await fileType(frameworkPath);
if (!archs.contains('armv7')) {
throw TaskResult.failure('$mode $frameworkPath armv7 architecture missing');
}
if (!archs.contains('arm64')) {
throw TaskResult.failure('$mode $frameworkPath arm64 architecture missing');
}
final bool containsSimulator = archs.contains('x86_64');
final bool isDebug = mode == 'Debug';
// Debug should contain the simulator archs.
// Release and Profile should not.
if (containsSimulator != isDebug) {
throw TaskResult.failure('$mode $frameworkPath x86_64 architecture ${isDebug ? 'missing' : 'present'}');
}
}
...@@ -185,7 +185,7 @@ class BuildIOSFrameworkCommand extends BuildSubCommand { ...@@ -185,7 +185,7 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
// Build and copy plugins. // Build and copy plugins.
await processPodsIfNeeded(_project.ios, getIosBuildDirectory(), mode); await processPodsIfNeeded(_project.ios, getIosBuildDirectory(), mode);
if (hasPlugins(_project)) { if (hasPlugins(_project)) {
await _producePlugins(xcodeBuildConfiguration, iPhoneBuildOutput, simulatorBuildOutput, modeDirectory, outputDirectory); await _producePlugins(mode, xcodeBuildConfiguration, iPhoneBuildOutput, simulatorBuildOutput, modeDirectory, outputDirectory);
} }
final Status status = logger.startProgress(' └─Moving to ${fs.path.relative(modeDirectory.path)}', timeout: timeoutConfiguration.slowOperation); final Status status = logger.startProgress(' └─Moving to ${fs.path.relative(modeDirectory.path)}', timeout: timeoutConfiguration.slowOperation);
...@@ -268,80 +268,42 @@ end ...@@ -268,80 +268,42 @@ end
Future<void> _produceFlutterFramework(Directory outputDirectory, BuildMode mode, Directory iPhoneBuildOutput, Directory simulatorBuildOutput, Directory modeDirectory) async { Future<void> _produceFlutterFramework(Directory outputDirectory, BuildMode mode, Directory iPhoneBuildOutput, Directory simulatorBuildOutput, Directory modeDirectory) async {
final Status status = logger.startProgress(' ├─Populating Flutter.framework...', timeout: timeoutConfiguration.slowOperation); final Status status = logger.startProgress(' ├─Populating Flutter.framework...', timeout: timeoutConfiguration.slowOperation);
try {
final String engineCacheFlutterFrameworkDirectory = artifacts.getArtifactPath(Artifact.flutterFramework, platform: TargetPlatform.ios, mode: mode); final String engineCacheFlutterFrameworkDirectory = artifacts.getArtifactPath(Artifact.flutterFramework, platform: TargetPlatform.ios, mode: mode);
// Copy universal engine cache framework to mode directory.
final String flutterFrameworkFileName = fs.path.basename(engineCacheFlutterFrameworkDirectory); final String flutterFrameworkFileName = fs.path.basename(engineCacheFlutterFrameworkDirectory);
final Directory fatFlutterFrameworkCopy = modeDirectory.childDirectory(flutterFrameworkFileName); final Directory fatFlutterFrameworkCopy = modeDirectory.childDirectory(flutterFrameworkFileName);
try {
// Copy universal engine cache framework to mode directory.
copyDirectorySync(fs.directory(engineCacheFlutterFrameworkDirectory), fatFlutterFrameworkCopy); copyDirectorySync(fs.directory(engineCacheFlutterFrameworkDirectory), fatFlutterFrameworkCopy);
if (boolArg('xcframework')) { if (mode != BuildMode.debug) {
// Copy universal framework to variant directory.
final Directory armFlutterFrameworkDirectory = iPhoneBuildOutput.childDirectory(flutterFrameworkFileName);
final File armFlutterFrameworkBinary = armFlutterFrameworkDirectory.childFile('Flutter');
final File fatFlutterFrameworkBinary = fatFlutterFrameworkCopy.childFile('Flutter'); final File fatFlutterFrameworkBinary = fatFlutterFrameworkCopy.childFile('Flutter');
copyDirectorySync(fatFlutterFrameworkCopy, armFlutterFrameworkDirectory);
// Create iOS framework. // Remove simulator architecture in profile and release mode.
List<String> lipoCommand = <String>['xcrun', 'lipo', fatFlutterFrameworkBinary.path, '-remove', 'x86_64', '-output', armFlutterFrameworkBinary.path]; final List<String> lipoCommand = <String>[
RunResult lipoResult = processUtils.runSync(
lipoCommand,
workingDirectory: outputDirectory.path,
allowReentrantFlutter: false,
);
if (lipoResult.exitCode != 0) {
throwToolExit('Unable to create ARM engine framework: ${lipoResult.stderr}');
}
// Create simulator framework.
final Directory simulatorFlutterFrameworkDirectory = simulatorBuildOutput.childDirectory(flutterFrameworkFileName);
final File simulatorFlutterFrameworkBinary = simulatorFlutterFrameworkDirectory.childFile('Flutter');
copyDirectorySync(fatFlutterFrameworkCopy, simulatorFlutterFrameworkDirectory);
lipoCommand = <String>['xcrun', 'lipo', fatFlutterFrameworkBinary.path, '-thin', 'x86_64', '-output', simulatorFlutterFrameworkBinary.path];
lipoResult = processUtils.runSync(
lipoCommand,
workingDirectory: outputDirectory.path,
allowReentrantFlutter: false,
);
if (lipoResult.exitCode != 0) {
throwToolExit('Unable to create simulator engine framework: ${lipoResult.stderr}');
}
// Create XCFramework from iOS and simulator frameworks.
final List<String> xcframeworkCommand = <String>[
'xcrun', 'xcrun',
'xcodebuild', 'lipo',
'-create-xcframework', fatFlutterFrameworkBinary.path,
'-framework', armFlutterFrameworkDirectory.path, '-remove',
'-framework', simulatorFlutterFrameworkDirectory.path, 'x86_64',
'-output', modeDirectory '-output',
.childFile('Flutter.xcframework') fatFlutterFrameworkBinary.path
.path
]; ];
final RunResult lipoResult = processUtils.runSync(
final RunResult xcframeworkResult = processUtils.runSync( lipoCommand,
xcframeworkCommand,
workingDirectory: outputDirectory.path,
allowReentrantFlutter: false, allowReentrantFlutter: false,
); );
if (xcframeworkResult.exitCode != 0) { if (lipoResult.exitCode != 0) {
throwToolExit('Unable to create engine XCFramework: ${xcframeworkResult.stderr}'); throwToolExit(
} 'Unable to remove simulator architecture in $mode: ${lipoResult.stderr}');
} }
if (!boolArg('universal')) {
fatFlutterFrameworkCopy.deleteSync(recursive: true);
} }
} finally { } finally {
status.stop(); status.stop();
} }
_produceXCFramework(mode, fatFlutterFrameworkCopy);
} }
Future<void> _produceAppFramework(BuildMode mode, Directory iPhoneBuildOutput, Directory simulatorBuildOutput, Directory modeDirectory) async { Future<void> _produceAppFramework(BuildMode mode, Directory iPhoneBuildOutput, Directory simulatorBuildOutput, Directory modeDirectory) async {
...@@ -378,6 +340,7 @@ end ...@@ -378,6 +340,7 @@ end
} finally { } finally {
status.stop(); status.stop();
} }
_produceXCFramework(mode, destinationAppFrameworkDirectory);
} }
Future<void> _produceStubAppFrameworkIfNeeded(BuildMode mode, Directory iPhoneBuildOutput, Directory simulatorBuildOutput, Directory destinationAppFrameworkDirectory) async { Future<void> _produceStubAppFrameworkIfNeeded(BuildMode mode, Directory iPhoneBuildOutput, Directory simulatorBuildOutput, Directory destinationAppFrameworkDirectory) async {
...@@ -442,6 +405,7 @@ end ...@@ -442,6 +405,7 @@ end
} }
Future<void> _producePlugins( Future<void> _producePlugins(
BuildMode mode,
String xcodeBuildConfiguration, String xcodeBuildConfiguration,
Directory iPhoneBuildOutput, Directory iPhoneBuildOutput,
Directory simulatorBuildOutput, Directory simulatorBuildOutput,
...@@ -472,6 +436,7 @@ end ...@@ -472,6 +436,7 @@ end
throwToolExit('Unable to build plugin frameworks: ${buildPluginsResult.stderr}'); throwToolExit('Unable to build plugin frameworks: ${buildPluginsResult.stderr}');
} }
if (mode == BuildMode.debug) {
pluginsBuildCommand = <String>[ pluginsBuildCommand = <String>[
'xcrun', 'xcrun',
'xcodebuild', 'xcodebuild',
...@@ -482,18 +447,22 @@ end ...@@ -482,18 +447,22 @@ end
xcodeBuildConfiguration, xcodeBuildConfiguration,
'SYMROOT=${simulatorBuildOutput.path}', 'SYMROOT=${simulatorBuildOutput.path}',
'ARCHS=x86_64', 'ARCHS=x86_64',
'ONLY_ACTIVE_ARCH=NO' // No device targeted, so build all valid architectures. 'ONLY_ACTIVE_ARCH=NO'
// No device targeted, so build all valid architectures.
]; ];
buildPluginsResult = processUtils.runSync( buildPluginsResult = processUtils.runSync(
pluginsBuildCommand, pluginsBuildCommand,
workingDirectory: _project.ios.hostAppRoot.childDirectory('Pods').path, workingDirectory: _project.ios.hostAppRoot
.childDirectory('Pods')
.path,
allowReentrantFlutter: false, allowReentrantFlutter: false,
); );
if (buildPluginsResult.exitCode != 0) { if (buildPluginsResult.exitCode != 0) {
throwToolExit('Unable to build plugin frameworks for simulator: ${buildPluginsResult.stderr}'); throwToolExit('Unable to build plugin frameworks for simulator: ${buildPluginsResult.stderr}');
} }
}
final Directory iPhoneBuildConfiguration = iPhoneBuildOutput.childDirectory('$xcodeBuildConfiguration-iphoneos'); final Directory iPhoneBuildConfiguration = iPhoneBuildOutput.childDirectory('$xcodeBuildConfiguration-iphoneos');
final Directory simulatorBuildConfiguration = simulatorBuildOutput.childDirectory('$xcodeBuildConfiguration-iphonesimulator'); final Directory simulatorBuildConfiguration = simulatorBuildOutput.childDirectory('$xcodeBuildConfiguration-iphonesimulator');
...@@ -510,6 +479,7 @@ end ...@@ -510,6 +479,7 @@ end
'lipo', 'lipo',
'-create', '-create',
fs.path.join(podProduct.path, binaryName), fs.path.join(podProduct.path, binaryName),
if (mode == BuildMode.debug)
simulatorBuildConfiguration.childDirectory(binaryName).childDirectory(podFrameworkName).childFile(binaryName).path, simulatorBuildConfiguration.childDirectory(binaryName).childDirectory(podFrameworkName).childFile(binaryName).path,
'-output', '-output',
modeDirectory.childDirectory(podFrameworkName).childFile(binaryName).path modeDirectory.childDirectory(podFrameworkName).childFile(binaryName).path
...@@ -533,7 +503,9 @@ end ...@@ -533,7 +503,9 @@ end
'-create-xcframework', '-create-xcframework',
'-framework', '-framework',
podProduct.path, podProduct.path,
if (mode == BuildMode.debug)
'-framework', '-framework',
if (mode == BuildMode.debug)
simulatorBuildConfiguration.childDirectory(binaryName).childDirectory(podFrameworkName).path, simulatorBuildConfiguration.childDirectory(binaryName).childDirectory(podFrameworkName).path,
'-output', '-output',
modeDirectory.childFile('$binaryName.xcframework').path modeDirectory.childFile('$binaryName.xcframework').path
...@@ -556,4 +528,143 @@ end ...@@ -556,4 +528,143 @@ end
status.stop(); status.stop();
} }
} }
void _produceXCFramework(BuildMode mode, Directory fatFramework) {
if (boolArg('xcframework')) {
final String frameworkBinaryName = fs.path.basenameWithoutExtension(
fatFramework.basename);
final Status status = logger.startProgress(' ├─Creating $frameworkBinaryName.xcframework...', timeout: timeoutConfiguration.fastOperation);
try {
if (mode == BuildMode.debug) {
_produceDebugXCFramework(fatFramework, frameworkBinaryName);
} else {
_produceNonDebugXCFramework(mode, fatFramework, frameworkBinaryName);
}
} finally {
status.stop();
}
}
if (!boolArg('universal')) {
fatFramework.deleteSync(recursive: true);
}
}
void _produceDebugXCFramework(Directory fatFramework, String frameworkBinaryName) {
final String frameworkFileName = fatFramework.basename;
final File fatFlutterFrameworkBinary = fatFramework.childFile(
frameworkBinaryName);
final Directory temporaryOutput = fs.systemTempDirectory.createTempSync(
'flutter_tool_build_ios_framework.');
try {
// Copy universal framework to variant directory.
final Directory iPhoneBuildOutput = temporaryOutput.childDirectory(
'ios')
..createSync(recursive: true);
final Directory simulatorBuildOutput = temporaryOutput.childDirectory(
'simulator')
..createSync(recursive: true);
final Directory armFlutterFrameworkDirectory = iPhoneBuildOutput
.childDirectory(frameworkFileName);
final File armFlutterFrameworkBinary = armFlutterFrameworkDirectory
.childFile(frameworkBinaryName);
copyDirectorySync(fatFramework, armFlutterFrameworkDirectory);
// Create iOS framework.
List<String> lipoCommand = <String>[
'xcrun',
'lipo',
fatFlutterFrameworkBinary.path,
'-remove',
'x86_64',
'-output',
armFlutterFrameworkBinary.path
];
RunResult lipoResult = processUtils.runSync(
lipoCommand,
allowReentrantFlutter: false,
);
if (lipoResult.exitCode != 0) {
throwToolExit('Unable to create ARM framework: ${lipoResult.stderr}');
}
// Create simulator framework.
final Directory simulatorFlutterFrameworkDirectory = simulatorBuildOutput
.childDirectory(frameworkFileName);
final File simulatorFlutterFrameworkBinary = simulatorFlutterFrameworkDirectory
.childFile(frameworkBinaryName);
copyDirectorySync(fatFramework, simulatorFlutterFrameworkDirectory);
lipoCommand = <String>[
'xcrun',
'lipo',
fatFlutterFrameworkBinary.path,
'-thin',
'x86_64',
'-output',
simulatorFlutterFrameworkBinary.path
];
lipoResult = processUtils.runSync(
lipoCommand,
allowReentrantFlutter: false,
);
if (lipoResult.exitCode != 0) {
throwToolExit(
'Unable to create simulator framework: ${lipoResult.stderr}');
}
// Create XCFramework from iOS and simulator frameworks.
final List<String> xcframeworkCommand = <String>[
'xcrun',
'xcodebuild',
'-create-xcframework',
'-framework', armFlutterFrameworkDirectory.path,
'-framework', simulatorFlutterFrameworkDirectory.path,
'-output', fatFramework.parent
.childFile('$frameworkBinaryName.xcframework')
.path
];
final RunResult xcframeworkResult = processUtils.runSync(
xcframeworkCommand,
allowReentrantFlutter: false,
);
if (xcframeworkResult.exitCode != 0) {
throwToolExit(
'Unable to create XCFramework: ${xcframeworkResult.stderr}');
}
} finally {
temporaryOutput.deleteSync(recursive: true);
}
}
void _produceNonDebugXCFramework(BuildMode mode, Directory fatFramework, String frameworkBinaryName) {
// Simulator is only supported in Debug mode.
// "Fat" framework here must only contain arm.
final List<String> xcframeworkCommand = <String>[
'xcrun',
'xcodebuild',
'-create-xcframework',
'-framework', fatFramework.path,
'-output', fatFramework.parent
.childFile('$frameworkBinaryName.xcframework')
.path
];
final RunResult xcframeworkResult = processUtils.runSync(
xcframeworkCommand,
allowReentrantFlutter: false,
);
if (xcframeworkResult.exitCode != 0) {
throwToolExit(
'Unable to create XCFramework: ${xcframeworkResult.stderr}');
}
}
} }
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