mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Build either iphoneos or iphonesimulator App.framework, not both (#69840)
This commit is contained in:
parent
0823d625bc
commit
1be922c353
@ -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)
|
||||
environment.buildDir.createSync(recursive: true);
|
||||
final RunResult createFrameworkResult = await createStubAppFramework(
|
||||
output,
|
||||
environment.defines[kSdkRoot],
|
||||
iosArchNames,
|
||||
);
|
||||
final RunResult simulatorResult = await createStubAppFramework(
|
||||
simulatorFile,
|
||||
SdkType.iPhoneSimulator,
|
||||
);
|
||||
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>{
|
||||
|
Loading…
Reference in New Issue
Block a user