mirror of
https://github.com/encounter/flutter.git
synced 2026-03-30 11:10:35 -07:00
Add bitcode and architectures to App.framework build ios framework command (#46130)
This commit is contained in:
@@ -79,18 +79,33 @@ Future<void> main() async {
|
||||
'App',
|
||||
));
|
||||
|
||||
final String aotSymbols = await dylibSymbols(path.join(
|
||||
final String appFrameworkPath = path.join(
|
||||
outputPath,
|
||||
'Debug',
|
||||
'App.framework',
|
||||
'App',
|
||||
));
|
||||
);
|
||||
final String aotSymbols = await dylibSymbols(appFrameworkPath);
|
||||
|
||||
if (aotSymbols.contains('architecture') ||
|
||||
aotSymbols.contains('_kDartVmSnapshot')) {
|
||||
throw TaskResult.failure('Debug App.framework contains AOT');
|
||||
}
|
||||
|
||||
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']) {
|
||||
@@ -116,6 +131,10 @@ Future<void> main() async {
|
||||
throw TaskResult.failure('$mode App.framework arm64 architecture missing');
|
||||
}
|
||||
|
||||
if (aotSymbols.contains('x86_64')) {
|
||||
throw TaskResult.failure('$mode App.framework contains x86_64 architecture');
|
||||
}
|
||||
|
||||
if (!aotSymbols.contains('_kDartVmSnapshot')) {
|
||||
throw TaskResult.failure('$mode App.framework missing Dart AOT');
|
||||
}
|
||||
|
||||
@@ -53,3 +53,7 @@ Future<Map<String, dynamic>> measureIosCpuGpu({
|
||||
Future<String> dylibSymbols(String pathToDylib) {
|
||||
return eval('nm', <String>['-g', pathToDylib]);
|
||||
}
|
||||
|
||||
Future<String> fileType(String pathToDylib) {
|
||||
return eval('file', <String>[pathToDylib]);
|
||||
}
|
||||
|
||||
@@ -244,7 +244,7 @@ class AOTSnapshotter {
|
||||
final String assemblyO = fs.path.join(outputPath, 'snapshot_assembly.o');
|
||||
List<String> isysrootArgs;
|
||||
if (isIOS) {
|
||||
final String iPhoneSDKLocation = await xcode.iPhoneSdkLocation();
|
||||
final String iPhoneSDKLocation = await xcode.sdkLocation(SdkType.iPhone);
|
||||
if (iPhoneSDKLocation != null) {
|
||||
isysrootArgs = <String>['-isysroot', iPhoneSDKLocation];
|
||||
}
|
||||
|
||||
@@ -157,17 +157,11 @@ class AotAssemblyProfile extends AotAssemblyBase {
|
||||
/// 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(Directory appFrameworkDirectory) async {
|
||||
File outputFile;
|
||||
Future<RunResult> createStubAppFramework(File outputFile, SdkType sdk) async {
|
||||
try {
|
||||
if (!appFrameworkDirectory.existsSync()) {
|
||||
appFrameworkDirectory.createSync(recursive: true);
|
||||
}
|
||||
|
||||
outputFile = appFrameworkDirectory.childFile('App');
|
||||
outputFile.createSync(recursive: true);
|
||||
} catch (e) {
|
||||
throwToolExit('Failed to create App.framework stub at ${appFrameworkDirectory.path}');
|
||||
throwToolExit('Failed to create App.framework stub at ${outputFile.path}');
|
||||
}
|
||||
|
||||
final Directory tempDir = fs.systemTempDirectory.createTempSync('flutter_tools_stub_source.');
|
||||
@@ -177,14 +171,32 @@ Future<RunResult> createStubAppFramework(Directory appFrameworkDirectory) async
|
||||
static const int Moo = 88;
|
||||
''');
|
||||
|
||||
List<String> archFlags;
|
||||
if (sdk == SdkType.iPhone) {
|
||||
archFlags = <String>[
|
||||
'-arch',
|
||||
getNameForDarwinArch(DarwinArch.armv7),
|
||||
'-arch',
|
||||
getNameForDarwinArch(DarwinArch.arm64),
|
||||
];
|
||||
} else {
|
||||
archFlags = <String>[
|
||||
'-arch',
|
||||
getNameForDarwinArch(DarwinArch.x86_64),
|
||||
];
|
||||
}
|
||||
|
||||
return await xcode.clang(<String>[
|
||||
'-x',
|
||||
'c',
|
||||
...archFlags,
|
||||
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 xcode.sdkLocation(sdk),
|
||||
'-o', outputFile.path,
|
||||
]);
|
||||
} finally {
|
||||
@@ -192,6 +204,8 @@ Future<RunResult> createStubAppFramework(Directory appFrameworkDirectory) async
|
||||
tempDir.deleteSync(recursive: true);
|
||||
} on FileSystemException catch (_) {
|
||||
// Best effort. Sometimes we can't delete things from system temp.
|
||||
} catch (e) {
|
||||
throwToolExit('Failed to create App.framework stub at ${outputFile.path}');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,7 +166,7 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
|
||||
await _produceFlutterFramework(outputDirectory, mode, iPhoneBuildOutput, simulatorBuildOutput, modeDirectory);
|
||||
|
||||
// Build aot, create module.framework and copy.
|
||||
await _produceAppFramework(mode, iPhoneBuildOutput, modeDirectory);
|
||||
await _produceAppFramework(mode, iPhoneBuildOutput, simulatorBuildOutput, modeDirectory);
|
||||
|
||||
// Build and copy plugins.
|
||||
await processPodsIfNeeded(_project.ios, getIosBuildDirectory(), mode);
|
||||
@@ -254,13 +254,14 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
|
||||
status.stop();
|
||||
}
|
||||
|
||||
Future<void> _produceAppFramework(BuildMode mode, Directory iPhoneBuildOutput, Directory modeDirectory) async {
|
||||
Future<void> _produceAppFramework(BuildMode mode, Directory iPhoneBuildOutput, Directory simulatorBuildOutput, Directory modeDirectory) async {
|
||||
const String appFrameworkName = 'App.framework';
|
||||
final Directory destinationAppFrameworkDirectory = modeDirectory.childDirectory(appFrameworkName);
|
||||
destinationAppFrameworkDirectory.createSync(recursive: true);
|
||||
|
||||
if (mode == BuildMode.debug) {
|
||||
final Status status = logger.startProgress(' ├─Add placeholder App.framework for debug...', timeout: timeoutConfiguration.fastOperation);
|
||||
await createStubAppFramework(destinationAppFrameworkDirectory);
|
||||
await _produceStubAppFrameworkIfNeeded(mode, iPhoneBuildOutput, simulatorBuildOutput, destinationAppFrameworkDirectory);
|
||||
status.stop();
|
||||
} else {
|
||||
await _produceAotAppFrameworkIfNeeded(mode, iPhoneBuildOutput, destinationAppFrameworkDirectory);
|
||||
@@ -283,6 +284,37 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
|
||||
status.stop();
|
||||
}
|
||||
|
||||
Future<void> _produceStubAppFrameworkIfNeeded(BuildMode mode, Directory iPhoneBuildOutput, Directory simulatorBuildOutput, Directory destinationAppFrameworkDirectory) async {
|
||||
if (mode != BuildMode.debug) {
|
||||
return;
|
||||
}
|
||||
const String appFrameworkName = 'App.framework';
|
||||
const String binaryName = 'App';
|
||||
|
||||
final Directory iPhoneAppFrameworkDirectory = iPhoneBuildOutput.childDirectory(appFrameworkName);
|
||||
final File iPhoneAppFrameworkFile = iPhoneAppFrameworkDirectory.childFile(binaryName);
|
||||
await createStubAppFramework(iPhoneAppFrameworkFile, SdkType.iPhone);
|
||||
|
||||
final Directory simulatorAppFrameworkDirectory = simulatorBuildOutput.childDirectory(appFrameworkName);
|
||||
final File simulatorAppFrameworkFile = simulatorAppFrameworkDirectory.childFile(binaryName);
|
||||
await createStubAppFramework(simulatorAppFrameworkFile, SdkType.iPhoneSimulator);
|
||||
|
||||
final List<String> lipoCommand = <String>[
|
||||
'xcrun',
|
||||
'lipo',
|
||||
'-create',
|
||||
iPhoneAppFrameworkFile.path,
|
||||
simulatorAppFrameworkFile.path,
|
||||
'-output',
|
||||
destinationAppFrameworkDirectory.childFile(binaryName).path
|
||||
];
|
||||
|
||||
await processUtils.run(
|
||||
lipoCommand,
|
||||
allowReentrantFlutter: false,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _produceAotAppFrameworkIfNeeded(BuildMode mode, Directory iPhoneBuildOutput, Directory destinationAppFrameworkDirectory) async {
|
||||
if (mode == BuildMode.debug) {
|
||||
return;
|
||||
@@ -295,6 +327,7 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
|
||||
// Relative paths show noise in the compiler https://github.com/dart-lang/sdk/issues/37978.
|
||||
mainDartFile: fs.path.absolute(targetFile),
|
||||
quiet: true,
|
||||
bitcode: true,
|
||||
reportTimings: false,
|
||||
iosBuildArchs: <DarwinArch>[DarwinArch.armv7, DarwinArch.arm64],
|
||||
dartDefines: dartDefines,
|
||||
|
||||
@@ -17,6 +17,31 @@ const int kXcodeRequiredVersionMinor = 2;
|
||||
|
||||
Xcode get xcode => context.get<Xcode>();
|
||||
|
||||
enum SdkType {
|
||||
iPhone,
|
||||
iPhoneSimulator,
|
||||
macOS,
|
||||
}
|
||||
|
||||
/// SDK name passed to `xcrun --sdk`. Corresponds to undocumented Xcode
|
||||
/// SUPPORTED_PLATFORMS values.
|
||||
///
|
||||
/// Usage: xcrun [options] <tool name> ... arguments ...
|
||||
/// ...
|
||||
/// --sdk <sdk name> find the tool for the given SDK name
|
||||
String getNameForSdk(SdkType sdk) {
|
||||
switch (sdk) {
|
||||
case SdkType.iPhone:
|
||||
return 'iphoneos';
|
||||
case SdkType.iPhoneSimulator:
|
||||
return 'iphonesimulator';
|
||||
case SdkType.macOS:
|
||||
return 'macosx';
|
||||
}
|
||||
assert(false);
|
||||
return null;
|
||||
}
|
||||
|
||||
class Xcode {
|
||||
bool get isInstalledAndMeetsVersionCheck => platform.isMacOS && isInstalled && isVersionSatisfactory;
|
||||
|
||||
@@ -117,9 +142,10 @@ class Xcode {
|
||||
);
|
||||
}
|
||||
|
||||
Future<String> iPhoneSdkLocation() async {
|
||||
Future<String> sdkLocation(SdkType sdk) async {
|
||||
assert(sdk != null);
|
||||
final RunResult runResult = await processUtils.run(
|
||||
<String>['xcrun', '--sdk', 'iphoneos', '--show-sdk-path'],
|
||||
<String>['xcrun', '--sdk', getNameForSdk(sdk), '--show-sdk-path'],
|
||||
throwOnError: true,
|
||||
);
|
||||
if (runResult.exitCode != 0) {
|
||||
|
||||
@@ -244,7 +244,7 @@ void main() {
|
||||
mockAndroidSdk = MockAndroidSdk();
|
||||
mockArtifacts = MockArtifacts();
|
||||
mockXcode = MockXcode();
|
||||
when(mockXcode.iPhoneSdkLocation()).thenAnswer((_) => Future<String>.value(kSDKPath));
|
||||
when(mockXcode.sdkLocation(any)).thenAnswer((_) => Future<String>.value(kSDKPath));
|
||||
|
||||
bufferLogger = BufferLogger();
|
||||
for (BuildMode mode in BuildMode.values) {
|
||||
|
||||
@@ -190,5 +190,11 @@ void main() {
|
||||
}, overrides: <Type, Generator>{
|
||||
ProcessManager: () => mockProcessManager,
|
||||
});
|
||||
|
||||
testUsingContext('SDK name', () {
|
||||
expect(getNameForSdk(SdkType.iPhone), 'iphoneos');
|
||||
expect(getNameForSdk(SdkType.iPhoneSimulator), 'iphonesimulator');
|
||||
expect(getNameForSdk(SdkType.macOS), 'macosx');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user