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}")
|
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() {
|
|||||||
# 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';
|
|||||||
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 {
|
|||||||
@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(
|
if (createFrameworkResult.exitCode != 0) {
|
||||||
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) {
|
|
||||||
throw Exception('Failed to create App.framework.');
|
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,
|
/// 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
|
|||||||
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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
|||||||
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
|
|||||||
'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
|
|||||||
'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>[
|
|||||||
'-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() {
|
|||||||
|
|
||||||
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>{
|
||||||
|
Loading…
Reference in New Issue
Block a user