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