Unverified Commit 1be922c3 authored by Jenn Magder's avatar Jenn Magder Committed by GitHub

Build either iphoneos or iphonesimulator App.framework, not both (#69840)

parent 0823d625
...@@ -244,7 +244,7 @@ LipoExecutable() { ...@@ -244,7 +244,7 @@ LipoExecutable() {
all_executables+=("${output}") all_executables+=("${output}")
else else
echo "Failed to extract ${arch} for ${executable}. Running lipo -info:" echo "Failed to extract ${arch} for ${executable}. Running lipo -info:"
lipo -info "${executable}" RunCommand lipo -info "${executable}"
exit 1 exit 1
fi fi
fi fi
...@@ -254,10 +254,10 @@ LipoExecutable() { ...@@ -254,10 +254,10 @@ LipoExecutable() {
# Skip this step for non-fat executables. # Skip this step for non-fat executables.
if [[ ${#all_executables[@]} > 0 ]]; then if [[ ${#all_executables[@]} > 0 ]]; then
local merged="${executable}_merged" local merged="${executable}_merged"
lipo -output "${merged}" -create "${all_executables[@]}" RunCommand lipo -output "${merged}" -create "${all_executables[@]}"
cp -f -- "${merged}" "${executable}" > /dev/null RunCommand cp -f -- "${merged}" "${executable}" > /dev/null
rm -f -- "${merged}" "${all_executables[@]}" RunCommand rm -f -- "${merged}" "${all_executables[@]}"
fi fi
} }
......
...@@ -10,7 +10,6 @@ import '../../base/io.dart'; ...@@ -10,7 +10,6 @@ import '../../base/io.dart';
import '../../base/process.dart'; import '../../base/process.dart';
import '../../build_info.dart'; import '../../build_info.dart';
import '../../globals.dart' as globals hide fs, logger, processManager, artifacts; import '../../globals.dart' as globals hide fs, logger, processManager, artifacts;
import '../../macos/xcode.dart';
import '../../project.dart'; import '../../project.dart';
import '../build_system.dart'; import '../build_system.dart';
import '../depfile.dart'; import '../depfile.dart';
...@@ -209,45 +208,19 @@ class DebugUniversalFramework extends Target { ...@@ -209,45 +208,19 @@ class DebugUniversalFramework extends Target {
@override @override
Future<void> build(Environment environment) async { Future<void> build(Environment environment) async {
// Generate a trivial App.framework. // Generate a trivial App.framework.
final Set<DarwinArch> iosArchs = environment.defines[kIosArchs] final Set<String> iosArchNames = environment.defines[kIosArchs]
?.split(' ') ?.split(' ')
?.map(getIOSArchForName) ?.toSet();
?.toSet() final File output = environment.buildDir
?? <DarwinArch>{DarwinArch.arm64};
final File iphoneFile = environment.buildDir.childFile('iphone_framework');
final File simulatorFile = environment.buildDir.childFile('simulator_framework');
final File lipoOutputFile = environment.buildDir
.childDirectory('App.framework') .childDirectory('App.framework')
.childFile('App'); .childFile('App');
lipoOutputFile.parent.createSync(recursive: true); environment.buildDir.createSync(recursive: true);
final RunResult iphoneResult = await createStubAppFramework( final RunResult createFrameworkResult = await createStubAppFramework(
iphoneFile, output,
SdkType.iPhone, environment.defines[kSdkRoot],
// Only include 32bit if it is contained in the active architectures. iosArchNames,
include32Bit: iosArchs.contains(DarwinArch.armv7)
);
final RunResult simulatorResult = await createStubAppFramework(
simulatorFile,
SdkType.iPhoneSimulator,
); );
if (iphoneResult.exitCode != 0 || simulatorResult.exitCode != 0) { if (createFrameworkResult.exitCode != 0) {
throw Exception('Failed to create App.framework.');
}
final List<String> lipoCommand = <String>[
...globals.xcode.xcrunCommand(),
'lipo',
'-create',
iphoneFile.path,
simulatorFile.path,
'-output',
lipoOutputFile.path,
];
final RunResult lipoResult = await globals.processUtils.run(
lipoCommand,
);
if (lipoResult.exitCode != 0) {
throw Exception('Failed to create App.framework.'); throw Exception('Failed to create App.framework.');
} }
} }
...@@ -410,7 +383,8 @@ class ReleaseIosApplicationBundle extends IosAssetBundle { ...@@ -410,7 +383,8 @@ class ReleaseIosApplicationBundle extends IosAssetBundle {
/// This framework needs to exist for the Xcode project to link/bundle, /// This framework needs to exist for the Xcode project to link/bundle,
/// but it isn't actually executed. To generate something valid, we compile a trivial /// but it isn't actually executed. To generate something valid, we compile a trivial
/// constant. /// constant.
Future<RunResult> createStubAppFramework(File outputFile, SdkType sdk, { bool include32Bit = true }) async { Future<RunResult> createStubAppFramework(File outputFile, String sdkRoot,
Set<String> iosArchNames) async {
try { try {
outputFile.createSync(recursive: true); outputFile.createSync(recursive: true);
} on Exception catch (e) { } on Exception catch (e) {
...@@ -425,32 +399,17 @@ Future<RunResult> createStubAppFramework(File outputFile, SdkType sdk, { bool in ...@@ -425,32 +399,17 @@ Future<RunResult> createStubAppFramework(File outputFile, SdkType sdk, { bool in
static const int Moo = 88; static const int Moo = 88;
'''); ''');
List<String> archFlags;
if (sdk == SdkType.iPhone) {
archFlags = <String>[
if (include32Bit)
...<String>['-arch', getNameForDarwinArch(DarwinArch.armv7)],
'-arch',
getNameForDarwinArch(DarwinArch.arm64),
];
} else {
archFlags = <String>[
'-arch',
getNameForDarwinArch(DarwinArch.x86_64),
];
}
return await globals.xcode.clang(<String>[ return await globals.xcode.clang(<String>[
'-x', '-x',
'c', 'c',
...archFlags, for (String arch in iosArchNames) ...<String>['-arch', arch],
stubSource.path, stubSource.path,
'-dynamiclib', '-dynamiclib',
'-fembed-bitcode-marker', '-fembed-bitcode-marker',
'-Xlinker', '-rpath', '-Xlinker', '@executable_path/Frameworks', '-Xlinker', '-rpath', '-Xlinker', '@executable_path/Frameworks',
'-Xlinker', '-rpath', '-Xlinker', '@loader_path/Frameworks', '-Xlinker', '-rpath', '-Xlinker', '@loader_path/Frameworks',
'-install_name', '@rpath/App.framework/App', '-install_name', '@rpath/App.framework/App',
'-isysroot', await globals.xcode.sdkLocation(sdk), '-isysroot', sdkRoot,
'-o', outputFile.path, '-o', outputFile.path,
]); ]);
} finally { } finally {
......
...@@ -203,12 +203,15 @@ class BuildIOSFrameworkCommand extends BuildSubCommand { ...@@ -203,12 +203,15 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
} }
// Build aot, create module.framework and copy. // Build aot, create module.framework and copy.
await _produceAppFramework(buildInfo, modeDirectory); final Directory iPhoneBuildOutput =
modeDirectory.childDirectory('iphoneos');
final Directory simulatorBuildOutput =
modeDirectory.childDirectory('iphonesimulator');
await _produceAppFramework(
buildInfo, modeDirectory, iPhoneBuildOutput, simulatorBuildOutput);
// Build and copy plugins. // Build and copy plugins.
await processPodsIfNeeded(_project.ios, getIosBuildDirectory(), buildInfo.mode); await processPodsIfNeeded(_project.ios, getIosBuildDirectory(), buildInfo.mode);
final Directory iPhoneBuildOutput = modeDirectory.childDirectory('iphoneos');
final Directory simulatorBuildOutput = modeDirectory.childDirectory('iphonesimulator');
if (hasPlugins(_project)) { if (hasPlugins(_project)) {
await _producePlugins(buildInfo.mode, xcodeBuildConfiguration, iPhoneBuildOutput, simulatorBuildOutput, modeDirectory, outputDirectory); await _producePlugins(buildInfo.mode, xcodeBuildConfiguration, iPhoneBuildOutput, simulatorBuildOutput, modeDirectory, outputDirectory);
} }
...@@ -348,64 +351,81 @@ end ...@@ -348,64 +351,81 @@ end
await _produceXCFrameworkFromUniversal(buildInfo, fatFlutterFrameworkCopy); await _produceXCFrameworkFromUniversal(buildInfo, fatFlutterFrameworkCopy);
} }
Future<void> _produceAppFramework(BuildInfo buildInfo, Directory modeDirectory) async { Future<void> _produceAppFramework(
BuildInfo buildInfo,
Directory outputDirectory,
Directory iPhoneBuildOutput,
Directory simulatorBuildOutput,
) async {
const String appFrameworkName = 'App.framework'; const String appFrameworkName = 'App.framework';
final Status status = globals.logger.startProgress( final Status status = globals.logger.startProgress(
' ├─Building App.framework...', ' ├─Building App.framework...',
); );
try { final List<SdkType> sdkTypes = <SdkType>[SdkType.iPhone];
Target target; final List<Directory> frameworks = <Directory>[];
if (buildInfo.isDebug) { Target target;
target = const DebugIosApplicationBundle(); if (buildInfo.isDebug) {
} else if (buildInfo.isProfile) { sdkTypes.add(SdkType.iPhoneSimulator);
target = const ProfileIosApplicationBundle(); target = const DebugIosApplicationBundle();
} else { } else if (buildInfo.isProfile) {
target = const ReleaseIosApplicationBundle(); target = const ProfileIosApplicationBundle();
} } else {
target = const ReleaseIosApplicationBundle();
}
final Environment environment = Environment( try {
projectDir: globals.fs.currentDirectory, for (final SdkType sdkType in sdkTypes) {
outputDir: modeDirectory, final Directory outputBuildDirectory = sdkType == SdkType.iPhone
buildDir: _project.dartTool.childDirectory('flutter_build'), ? iPhoneBuildOutput
cacheDir: null, : simulatorBuildOutput;
flutterRootDir: globals.fs.directory(Cache.flutterRoot), frameworks.add(outputBuildDirectory.childDirectory(appFrameworkName));
defines: <String, String>{ final Environment environment = Environment(
kTargetFile: targetFile, projectDir: globals.fs.currentDirectory,
kBuildMode: getNameForBuildMode(buildInfo.mode), outputDir: outputBuildDirectory,
kTargetPlatform: getNameForTargetPlatform(TargetPlatform.ios), buildDir: _project.dartTool.childDirectory('flutter_build'),
kIconTreeShakerFlag: buildInfo.treeShakeIcons.toString(), cacheDir: null,
kDartDefines: jsonEncode(buildInfo.dartDefines), flutterRootDir: globals.fs.directory(Cache.flutterRoot),
kBitcodeFlag: 'true', defines: <String, String>{
if (buildInfo?.extraGenSnapshotOptions?.isNotEmpty ?? false) kTargetFile: targetFile,
kExtraGenSnapshotOptions: buildInfo.extraGenSnapshotOptions.join(','), kBuildMode: getNameForBuildMode(buildInfo.mode),
if (buildInfo?.extraFrontEndOptions?.isNotEmpty ?? false) kTargetPlatform: getNameForTargetPlatform(TargetPlatform.ios),
kExtraFrontEndOptions: buildInfo.extraFrontEndOptions.join(','), kIconTreeShakerFlag: buildInfo.treeShakeIcons.toString(),
kIosArchs: <DarwinArch>[DarwinArch.armv7, DarwinArch.arm64] kDartDefines: jsonEncode(buildInfo.dartDefines),
.map(getNameForDarwinArch).join(' '), kBitcodeFlag: 'true',
kSdkRoot: await globals.xcode.sdkLocation(SdkType.iPhone), if (buildInfo?.extraGenSnapshotOptions?.isNotEmpty ?? false)
}, kExtraGenSnapshotOptions:
artifacts: globals.artifacts, buildInfo.extraGenSnapshotOptions.join(','),
fileSystem: globals.fs, if (buildInfo?.extraFrontEndOptions?.isNotEmpty ?? false)
logger: globals.logger, kExtraFrontEndOptions: buildInfo.extraFrontEndOptions.join(','),
processManager: globals.processManager, kIosArchs: defaultIOSArchsForSdk(sdkType)
engineVersion: globals.artifacts.isLocalEngine .map(getNameForDarwinArch)
? null .join(' '),
: globals.flutterVersion.engineRevision, kSdkRoot: await globals.xcode.sdkLocation(sdkType),
); },
final BuildResult result = await buildSystem.build(target, environment); artifacts: globals.artifacts,
if (!result.success) { fileSystem: globals.fs,
for (final ExceptionMeasurement measurement in result.exceptions.values) { logger: globals.logger,
globals.printError(measurement.exception.toString()); processManager: globals.processManager,
engineVersion: globals.artifacts.isLocalEngine
? null
: globals.flutterVersion.engineRevision,
);
final BuildResult result = await buildSystem.build(target, environment);
if (!result.success) {
for (final ExceptionMeasurement measurement
in result.exceptions.values) {
globals.printError(measurement.exception.toString());
}
throwToolExit('The App.framework build failed.');
} }
throwToolExit('The App.framework build failed.');
} }
} finally { } finally {
status.stop(); status.stop();
} }
final Directory destinationAppFrameworkDirectory = modeDirectory.childDirectory(appFrameworkName); await _produceUniversalFramework(frameworks, 'App', outputDirectory);
await _produceXCFrameworkFromUniversal(buildInfo, destinationAppFrameworkDirectory); await _produceXCFramework(frameworks, 'App', outputDirectory);
} }
Future<void> _producePlugins( Future<void> _producePlugins(
...@@ -437,7 +457,6 @@ end ...@@ -437,7 +457,6 @@ end
'iphoneos', 'iphoneos',
'-configuration', '-configuration',
xcodeBuildConfiguration, xcodeBuildConfiguration,
'-destination generic/platform=iOS',
'SYMROOT=${iPhoneBuildOutput.path}', 'SYMROOT=${iPhoneBuildOutput.path}',
'BITCODE_GENERATION_MODE=$bitcodeGenerationMode', 'BITCODE_GENERATION_MODE=$bitcodeGenerationMode',
'ONLY_ACTIVE_ARCH=NO', // No device targeted, so build all valid architectures. 'ONLY_ACTIVE_ARCH=NO', // No device targeted, so build all valid architectures.
...@@ -463,7 +482,6 @@ end ...@@ -463,7 +482,6 @@ end
'iphonesimulator', 'iphonesimulator',
'-configuration', '-configuration',
xcodeBuildConfiguration, xcodeBuildConfiguration,
'-destination generic/platform=iOS',
'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.
......
...@@ -35,6 +35,7 @@ const List<String> _kSharedConfig = <String>[ ...@@ -35,6 +35,7 @@ const List<String> _kSharedConfig = <String>[
'-install_name', '-install_name',
'@rpath/App.framework/App', '@rpath/App.framework/App',
'-isysroot', '-isysroot',
'path/to/sdk',
]; ];
void main() { void main() {
...@@ -70,49 +71,26 @@ void main() { ...@@ -70,49 +71,26 @@ void main() {
testUsingContext('DebugUniveralFramework creates expected binary with arm64 only arch', () async { testUsingContext('DebugUniveralFramework creates expected binary with arm64 only arch', () async {
environment.defines[kIosArchs] = 'arm64'; environment.defines[kIosArchs] = 'arm64';
processManager.addCommands(<FakeCommand>[ environment.defines[kSdkRoot] = 'path/to/sdk';
const FakeCommand(command: <String>['xcrun', '--sdk', 'iphoneos', '--show-sdk-path']), processManager.addCommand(
FakeCommand(command: <String>[ FakeCommand(command: <String>[
'xcrun', 'xcrun',
'clang', 'clang',
'-x', '-x',
'c', 'c',
// iphone only gets 64 bit arch based on kIosArchs // iphone only gets 64 bit arch based on kIosArchs
'-arch', '-arch',
'arm64', 'arm64',
fileSystem.path.absolute(fileSystem.path.join('.tmp_rand0', 'flutter_tools_stub_source.rand0', 'debug_app.cc')), fileSystem.path.absolute(fileSystem.path.join(
'.tmp_rand0', 'flutter_tools_stub_source.rand0', 'debug_app.cc')),
..._kSharedConfig, ..._kSharedConfig,
'',
'-o', '-o',
environment.buildDir.childFile('iphone_framework').path environment.buildDir
.childDirectory('App.framework')
.childFile('App')
.path,
]), ]),
// Create simulator stub. );
const FakeCommand(command: <String>['xcrun', '--sdk', 'iphonesimulator', '--show-sdk-path']),
FakeCommand(command: <String>[
'xcrun',
'clang',
'-x',
'c',
// Simulator only as x86_64 arch
'-arch',
'x86_64',
fileSystem.path.absolute(fileSystem.path.join('.tmp_rand0', 'flutter_tools_stub_source.rand0', 'debug_app.cc')),
..._kSharedConfig,
'',
'-o',
environment.buildDir.childFile('simulator_framework').path
]),
// Lipo stubs together.
FakeCommand(command: <String>[
'xcrun',
'lipo',
'-create',
environment.buildDir.childFile('iphone_framework').path,
environment.buildDir.childFile('simulator_framework').path,
'-output',
environment.buildDir.childDirectory('App.framework').childFile('App').path,
]),
]);
await const DebugUniversalFramework().build(environment); await const DebugUniversalFramework().build(environment);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
......
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