Stop embedding bitcode for iOS in tool (#112831)
This commit is contained in:
parent
8c0aa6c66c
commit
35afe1bdac
@ -171,7 +171,6 @@ Future<void> _testBuildIosFramework(Directory projectDir, { bool isModule = fals
|
|||||||
);
|
);
|
||||||
|
|
||||||
await _checkDylib(appFrameworkPath);
|
await _checkDylib(appFrameworkPath);
|
||||||
await _checkBitcode(appFrameworkPath, mode);
|
|
||||||
|
|
||||||
final String aotSymbols = await _dylibSymbols(appFrameworkPath);
|
final String aotSymbols = await _dylibSymbols(appFrameworkPath);
|
||||||
|
|
||||||
@ -228,15 +227,14 @@ Future<void> _testBuildIosFramework(Directory projectDir, { bool isModule = fals
|
|||||||
section("Check all modes' engine dylib");
|
section("Check all modes' engine dylib");
|
||||||
|
|
||||||
for (final String mode in <String>['Debug', 'Profile', 'Release']) {
|
for (final String mode in <String>['Debug', 'Profile', 'Release']) {
|
||||||
final String engineBinary = path.join(
|
checkFileExists(path.join(
|
||||||
outputPath,
|
outputPath,
|
||||||
mode,
|
mode,
|
||||||
'Flutter.xcframework',
|
'Flutter.xcframework',
|
||||||
'ios-arm64',
|
'ios-arm64',
|
||||||
'Flutter.framework',
|
'Flutter.framework',
|
||||||
'Flutter',
|
'Flutter',
|
||||||
);
|
));
|
||||||
await _checkBitcode(engineBinary, mode);
|
|
||||||
|
|
||||||
checkFileExists(path.join(
|
checkFileExists(path.join(
|
||||||
outputPath,
|
outputPath,
|
||||||
@ -836,15 +834,6 @@ Future<void> _checkStatic(String pathToLibrary) async {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _checkBitcode(String frameworkPath, String mode) async {
|
|
||||||
checkFileExists(frameworkPath);
|
|
||||||
|
|
||||||
// Bitcode only needed in Release mode for archiving.
|
|
||||||
if (mode == 'Release' && !await containsBitcode(frameworkPath)) {
|
|
||||||
throw TaskResult.failure('$frameworkPath does not contain bitcode');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<String> _dylibSymbols(String pathToDylib) {
|
Future<String> _dylibSymbols(String pathToDylib) {
|
||||||
return eval('nm', <String>[
|
return eval('nm', <String>[
|
||||||
'-g',
|
'-g',
|
||||||
|
@ -47,43 +47,6 @@ Future<String?> minPhoneOSVersion(String pathToBinary) async {
|
|||||||
return minVersion;
|
return minVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> containsBitcode(String pathToBinary) async {
|
|
||||||
// See: https://stackoverflow.com/questions/32755775/how-to-check-a-static-library-is-built-contain-bitcode
|
|
||||||
final String loadCommands = await eval('otool', <String>[
|
|
||||||
'-l',
|
|
||||||
'-arch',
|
|
||||||
'arm64',
|
|
||||||
pathToBinary,
|
|
||||||
]);
|
|
||||||
if (!loadCommands.contains('__LLVM')) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Presence of the section may mean a bitcode marker was embedded (size=1), but there is no content.
|
|
||||||
if (!loadCommands.contains('size 0x0000000000000001')) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// Check the false positives: size=1 wasn't referencing the __LLVM section.
|
|
||||||
|
|
||||||
bool emptyBitcodeMarkerFound = false;
|
|
||||||
// Section
|
|
||||||
// sectname __bundle
|
|
||||||
// segname __LLVM
|
|
||||||
// addr 0x003c4000
|
|
||||||
// size 0x0042b633
|
|
||||||
// offset 3932160
|
|
||||||
// ...
|
|
||||||
final List<String> lines = LineSplitter.split(loadCommands).toList();
|
|
||||||
lines.asMap().forEach((int index, String line) {
|
|
||||||
if (line.contains('segname __LLVM') && lines.length - index - 1 > 3) {
|
|
||||||
emptyBitcodeMarkerFound |= lines
|
|
||||||
.skip(index - 1)
|
|
||||||
.take(4)
|
|
||||||
.any((String line) => line.contains(' size 0x0000000000000001'));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return !emptyBitcodeMarkerFound;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates and boots a new simulator, passes the new simulator's identifier to
|
/// Creates and boots a new simulator, passes the new simulator's identifier to
|
||||||
/// `testFunction`.
|
/// `testFunction`.
|
||||||
///
|
///
|
||||||
|
@ -65,6 +65,9 @@ def flutter_additional_ios_build_settings(target)
|
|||||||
# Skip other updates if it's not a Flutter plugin (transitive dependency).
|
# Skip other updates if it's not a Flutter plugin (transitive dependency).
|
||||||
next unless target.dependencies.any? { |dependency| dependency.name == 'Flutter' }
|
next unless target.dependencies.any? { |dependency| dependency.name == 'Flutter' }
|
||||||
|
|
||||||
|
# Bitcode is deprecated, Flutter.framework bitcode blob will have been stripped.
|
||||||
|
build_configuration.build_settings['ENABLE_BITCODE'] = 'NO'
|
||||||
|
|
||||||
# Profile can't be derived from the CocoaPods build configuration. Use release framework (for linking only).
|
# Profile can't be derived from the CocoaPods build configuration. Use release framework (for linking only).
|
||||||
configuration_engine_dir = build_configuration.type == :debug ? debug_framework_dir : release_framework_dir
|
configuration_engine_dir = build_configuration.type == :debug ? debug_framework_dir : release_framework_dir
|
||||||
Dir.new(configuration_engine_dir).each_child do |xcframework_file|
|
Dir.new(configuration_engine_dir).each_child do |xcframework_file|
|
||||||
|
@ -333,11 +333,6 @@ class Context {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
String bitcodeFlag = '';
|
|
||||||
if (environment['ENABLE_BITCODE'] == 'YES' && environment['ACTION'] == 'install') {
|
|
||||||
bitcodeFlag = 'true';
|
|
||||||
}
|
|
||||||
|
|
||||||
final List<String> flutterArgs = <String>[];
|
final List<String> flutterArgs = <String>[];
|
||||||
|
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
@ -365,7 +360,6 @@ class Context {
|
|||||||
'-dTreeShakeIcons=${environment['TREE_SHAKE_ICONS'] ?? ''}',
|
'-dTreeShakeIcons=${environment['TREE_SHAKE_ICONS'] ?? ''}',
|
||||||
'-dTrackWidgetCreation=${environment['TRACK_WIDGET_CREATION'] ?? ''}',
|
'-dTrackWidgetCreation=${environment['TRACK_WIDGET_CREATION'] ?? ''}',
|
||||||
'-dDartObfuscation=${environment['DART_OBFUSCATION'] ?? ''}',
|
'-dDartObfuscation=${environment['DART_OBFUSCATION'] ?? ''}',
|
||||||
'-dEnableBitcode=$bitcodeFlag',
|
|
||||||
'-dAction=${environment['ACTION'] ?? ''}',
|
'-dAction=${environment['ACTION'] ?? ''}',
|
||||||
'--ExtraGenSnapshotOptions=${environment['EXTRA_GEN_SNAPSHOT_OPTIONS'] ?? ''}',
|
'--ExtraGenSnapshotOptions=${environment['EXTRA_GEN_SNAPSHOT_OPTIONS'] ?? ''}',
|
||||||
'--DartDefines=${environment['DART_DEFINES'] ?? ''}',
|
'--DartDefines=${environment['DART_DEFINES'] ?? ''}',
|
||||||
|
@ -116,16 +116,11 @@ class AOTSnapshotter {
|
|||||||
DarwinArch? darwinArch,
|
DarwinArch? darwinArch,
|
||||||
String? sdkRoot,
|
String? sdkRoot,
|
||||||
List<String> extraGenSnapshotOptions = const <String>[],
|
List<String> extraGenSnapshotOptions = const <String>[],
|
||||||
required bool bitcode,
|
|
||||||
String? splitDebugInfo,
|
String? splitDebugInfo,
|
||||||
required bool dartObfuscation,
|
required bool dartObfuscation,
|
||||||
bool quiet = false,
|
bool quiet = false,
|
||||||
}) async {
|
}) async {
|
||||||
assert(platform != TargetPlatform.ios || darwinArch != null);
|
assert(platform != TargetPlatform.ios || darwinArch != null);
|
||||||
if (bitcode && platform != TargetPlatform.ios) {
|
|
||||||
_logger.printError('Bitcode is only supported for iOS.');
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_isValidAotPlatform(platform, buildMode)) {
|
if (!_isValidAotPlatform(platform, buildMode)) {
|
||||||
_logger.printError('${getNameForTargetPlatform(platform)} does not support AOT compilation.');
|
_logger.printError('${getNameForTargetPlatform(platform)} does not support AOT compilation.');
|
||||||
@ -244,7 +239,6 @@ class AOTSnapshotter {
|
|||||||
sdkRoot: sdkRoot,
|
sdkRoot: sdkRoot,
|
||||||
assemblyPath: assembly,
|
assemblyPath: assembly,
|
||||||
outputPath: outputDir.path,
|
outputPath: outputDir.path,
|
||||||
bitcode: bitcode,
|
|
||||||
quiet: quiet,
|
quiet: quiet,
|
||||||
stripAfterBuild: stripAfterBuild,
|
stripAfterBuild: stripAfterBuild,
|
||||||
extractAppleDebugSymbols: extractAppleDebugSymbols
|
extractAppleDebugSymbols: extractAppleDebugSymbols
|
||||||
@ -262,7 +256,6 @@ class AOTSnapshotter {
|
|||||||
String? sdkRoot,
|
String? sdkRoot,
|
||||||
required String assemblyPath,
|
required String assemblyPath,
|
||||||
required String outputPath,
|
required String outputPath,
|
||||||
required bool bitcode,
|
|
||||||
required bool quiet,
|
required bool quiet,
|
||||||
required bool stripAfterBuild,
|
required bool stripAfterBuild,
|
||||||
required bool extractAppleDebugSymbols
|
required bool extractAppleDebugSymbols
|
||||||
@ -286,12 +279,10 @@ class AOTSnapshotter {
|
|||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
const String embedBitcodeArg = '-fembed-bitcode';
|
|
||||||
final String assemblyO = _fileSystem.path.join(outputPath, 'snapshot_assembly.o');
|
final String assemblyO = _fileSystem.path.join(outputPath, 'snapshot_assembly.o');
|
||||||
|
|
||||||
final RunResult compileResult = await _xcode.cc(<String>[
|
final RunResult compileResult = await _xcode.cc(<String>[
|
||||||
...commonBuildOptions,
|
...commonBuildOptions,
|
||||||
if (bitcode) embedBitcodeArg,
|
|
||||||
'-c',
|
'-c',
|
||||||
assemblyPath,
|
assemblyPath,
|
||||||
'-o',
|
'-o',
|
||||||
@ -311,7 +302,6 @@ class AOTSnapshotter {
|
|||||||
'-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',
|
||||||
if (bitcode) embedBitcodeArg,
|
|
||||||
'-o', appLib,
|
'-o', appLib,
|
||||||
assemblyO,
|
assemblyO,
|
||||||
];
|
];
|
||||||
|
@ -942,9 +942,6 @@ const String kTargetPlatform = 'TargetPlatform';
|
|||||||
/// The define to control what target file is used.
|
/// The define to control what target file is used.
|
||||||
const String kTargetFile = 'TargetFile';
|
const String kTargetFile = 'TargetFile';
|
||||||
|
|
||||||
/// The define to control whether the AOT snapshot is built with bitcode.
|
|
||||||
const String kBitcodeFlag = 'EnableBitcode';
|
|
||||||
|
|
||||||
/// Whether to enable or disable track widget creation.
|
/// Whether to enable or disable track widget creation.
|
||||||
const String kTrackWidgetCreation = 'TrackWidgetCreation';
|
const String kTrackWidgetCreation = 'TrackWidgetCreation';
|
||||||
|
|
||||||
|
@ -250,7 +250,6 @@ class AndroidAot extends AotElfBase {
|
|||||||
buildMode: buildMode,
|
buildMode: buildMode,
|
||||||
mainPath: environment.buildDir.childFile('app.dill').path,
|
mainPath: environment.buildDir.childFile('app.dill').path,
|
||||||
outputPath: output.path,
|
outputPath: output.path,
|
||||||
bitcode: false,
|
|
||||||
extraGenSnapshotOptions: extraGenSnapshotOptions,
|
extraGenSnapshotOptions: extraGenSnapshotOptions,
|
||||||
splitDebugInfo: splitDebugInfo,
|
splitDebugInfo: splitDebugInfo,
|
||||||
dartObfuscation: dartObfuscation,
|
dartObfuscation: dartObfuscation,
|
||||||
|
@ -296,7 +296,6 @@ abstract class AotElfBase extends Target {
|
|||||||
buildMode: buildMode,
|
buildMode: buildMode,
|
||||||
mainPath: environment.buildDir.childFile('app.dill').path,
|
mainPath: environment.buildDir.childFile('app.dill').path,
|
||||||
outputPath: outputPath,
|
outputPath: outputPath,
|
||||||
bitcode: false,
|
|
||||||
extraGenSnapshotOptions: extraGenSnapshotOptions,
|
extraGenSnapshotOptions: extraGenSnapshotOptions,
|
||||||
splitDebugInfo: splitDebugInfo,
|
splitDebugInfo: splitDebugInfo,
|
||||||
dartObfuscation: dartObfuscation,
|
dartObfuscation: dartObfuscation,
|
||||||
|
@ -56,7 +56,6 @@ abstract class AotAssemblyBase extends Target {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final List<String> extraGenSnapshotOptions = decodeCommaSeparated(environment.defines, kExtraGenSnapshotOptions);
|
final List<String> extraGenSnapshotOptions = decodeCommaSeparated(environment.defines, kExtraGenSnapshotOptions);
|
||||||
final bool bitcode = environment.defines[kBitcodeFlag] == 'true';
|
|
||||||
final BuildMode buildMode = getBuildModeForName(environmentBuildMode);
|
final BuildMode buildMode = getBuildModeForName(environmentBuildMode);
|
||||||
final TargetPlatform targetPlatform = getTargetPlatformForName(environmentTargetPlatform);
|
final TargetPlatform targetPlatform = getTargetPlatformForName(environmentTargetPlatform);
|
||||||
final String? splitDebugInfo = environment.defines[kSplitDebugInfo];
|
final String? splitDebugInfo = environment.defines[kSplitDebugInfo];
|
||||||
@ -101,7 +100,6 @@ abstract class AotAssemblyBase extends Target {
|
|||||||
outputPath: environment.fileSystem.path.join(buildOutputPath, getNameForDarwinArch(darwinArch)),
|
outputPath: environment.fileSystem.path.join(buildOutputPath, getNameForDarwinArch(darwinArch)),
|
||||||
darwinArch: darwinArch,
|
darwinArch: darwinArch,
|
||||||
sdkRoot: sdkRoot,
|
sdkRoot: sdkRoot,
|
||||||
bitcode: bitcode,
|
|
||||||
quiet: true,
|
quiet: true,
|
||||||
splitDebugInfo: splitDebugInfo,
|
splitDebugInfo: splitDebugInfo,
|
||||||
dartObfuscation: dartObfuscation,
|
dartObfuscation: dartObfuscation,
|
||||||
@ -287,9 +285,6 @@ abstract class UnpackIOS extends Target {
|
|||||||
if (archs == null) {
|
if (archs == null) {
|
||||||
throw MissingDefineException(kIosArchs, name);
|
throw MissingDefineException(kIosArchs, name);
|
||||||
}
|
}
|
||||||
if (environment.defines[kBitcodeFlag] == null) {
|
|
||||||
throw MissingDefineException(kBitcodeFlag, name);
|
|
||||||
}
|
|
||||||
_copyFramework(environment, sdkRoot);
|
_copyFramework(environment, sdkRoot);
|
||||||
|
|
||||||
final File frameworkBinary = environment.outputDir.childDirectory('Flutter.framework').childFile('Flutter');
|
final File frameworkBinary = environment.outputDir.childDirectory('Flutter.framework').childFile('Flutter');
|
||||||
@ -298,7 +293,9 @@ abstract class UnpackIOS extends Target {
|
|||||||
throw Exception('Binary $frameworkBinaryPath does not exist, cannot thin');
|
throw Exception('Binary $frameworkBinaryPath does not exist, cannot thin');
|
||||||
}
|
}
|
||||||
_thinFramework(environment, frameworkBinaryPath, archs);
|
_thinFramework(environment, frameworkBinaryPath, archs);
|
||||||
_bitcodeStripFramework(environment, frameworkBinaryPath);
|
if (buildMode == BuildMode.release) {
|
||||||
|
_bitcodeStripFramework(environment, frameworkBinaryPath);
|
||||||
|
}
|
||||||
_signFramework(environment, frameworkBinaryPath, buildMode);
|
_signFramework(environment, frameworkBinaryPath, buildMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -373,16 +370,14 @@ abstract class UnpackIOS extends Target {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Destructively strip bitcode from the framework, if needed.
|
/// Destructively strip bitcode from the framework. This can be removed
|
||||||
|
/// when the framework is no longer built with bitcode.
|
||||||
void _bitcodeStripFramework(Environment environment, String frameworkBinaryPath) {
|
void _bitcodeStripFramework(Environment environment, String frameworkBinaryPath) {
|
||||||
if (environment.defines[kBitcodeFlag] == 'true') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final ProcessResult stripResult = environment.processManager.runSync(<String>[
|
final ProcessResult stripResult = environment.processManager.runSync(<String>[
|
||||||
'xcrun',
|
'xcrun',
|
||||||
'bitcode_strip',
|
'bitcode_strip',
|
||||||
frameworkBinaryPath,
|
frameworkBinaryPath,
|
||||||
'-m', // leave the bitcode marker.
|
'-r', // Delete the bitcode segment.
|
||||||
'-o',
|
'-o',
|
||||||
frameworkBinaryPath,
|
frameworkBinaryPath,
|
||||||
]);
|
]);
|
||||||
@ -669,7 +664,6 @@ Future<void> _createStubAppFramework(File outputFile, Environment environment,
|
|||||||
for (String arch in iosArchNames ?? <String>{}) ...<String>['-arch', arch],
|
for (String arch in iosArchNames ?? <String>{}) ...<String>['-arch', arch],
|
||||||
stubSource.path,
|
stubSource.path,
|
||||||
'-dynamiclib',
|
'-dynamiclib',
|
||||||
'-fembed-bitcode-marker',
|
|
||||||
// Keep version in sync with AOTSnapshotter flag
|
// Keep version in sync with AOTSnapshotter flag
|
||||||
if (environmentType == EnvironmentType.physical)
|
if (environmentType == EnvironmentType.physical)
|
||||||
'-miphoneos-version-min=11.0'
|
'-miphoneos-version-min=11.0'
|
||||||
|
@ -285,7 +285,6 @@ class CompileMacOSFramework extends Target {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pending.add(snapshotter.build(
|
pending.add(snapshotter.build(
|
||||||
bitcode: false,
|
|
||||||
buildMode: buildMode,
|
buildMode: buildMode,
|
||||||
mainPath: environment.buildDir.childFile('app.dill').path,
|
mainPath: environment.buildDir.childFile('app.dill').path,
|
||||||
outputPath: environment.fileSystem.path.join(buildOutputPath, getNameForDarwinArch(darwinArch)),
|
outputPath: environment.fileSystem.path.join(buildOutputPath, getNameForDarwinArch(darwinArch)),
|
||||||
|
@ -238,25 +238,12 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand {
|
|||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>method</key>
|
<key>method</key>
|
||||||
''');
|
|
||||||
|
|
||||||
plistContents.write('''
|
|
||||||
<string>${stringArgDeprecated('export-method')}</string>
|
<string>${stringArgDeprecated('export-method')}</string>
|
||||||
''');
|
<key>uploadBitcode</key>
|
||||||
if (xcodeBuildResult?.xcodeBuildExecution?.buildSettings['ENABLE_BITCODE'] != 'YES') {
|
|
||||||
// Bitcode is off by default in Flutter iOS apps.
|
|
||||||
plistContents.write('''
|
|
||||||
<key>uploadBitcode</key>
|
|
||||||
<false/>
|
<false/>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
''');
|
''');
|
||||||
} else {
|
|
||||||
plistContents.write('''
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
''');
|
|
||||||
}
|
|
||||||
|
|
||||||
final File tempPlist = globals.fs.systemTempDirectory
|
final File tempPlist = globals.fs.systemTempDirectory
|
||||||
.createTempSync('flutter_build_ios.').childFile('ExportOptions.plist');
|
.createTempSync('flutter_build_ios.').childFile('ExportOptions.plist');
|
||||||
|
@ -152,7 +152,7 @@ abstract class BuildFrameworkCommand extends BuildSubCommand {
|
|||||||
...framework.parent
|
...framework.parent
|
||||||
.listSync()
|
.listSync()
|
||||||
.where((FileSystemEntity entity) =>
|
.where((FileSystemEntity entity) =>
|
||||||
entity.basename.endsWith('bcsymbolmap') || entity.basename.endsWith('dSYM'))
|
entity.basename.endsWith('dSYM'))
|
||||||
.map((FileSystemEntity entity) => <String>['-debug-symbols', entity.path])
|
.map((FileSystemEntity entity) => <String>['-debug-symbols', entity.path])
|
||||||
.expand<String>((List<String> parameter) => parameter),
|
.expand<String>((List<String> parameter) => parameter),
|
||||||
],
|
],
|
||||||
@ -421,7 +421,6 @@ end
|
|||||||
defines: <String, String>{
|
defines: <String, String>{
|
||||||
kTargetFile: targetFile,
|
kTargetFile: targetFile,
|
||||||
kTargetPlatform: getNameForTargetPlatform(TargetPlatform.ios),
|
kTargetPlatform: getNameForTargetPlatform(TargetPlatform.ios),
|
||||||
kBitcodeFlag: 'true',
|
|
||||||
kIosArchs: defaultIOSArchsForEnvironment(sdkType, globals.artifacts!)
|
kIosArchs: defaultIOSArchsForEnvironment(sdkType, globals.artifacts!)
|
||||||
.map(getNameForDarwinArch)
|
.map(getNameForDarwinArch)
|
||||||
.join(' '),
|
.join(' '),
|
||||||
@ -480,9 +479,6 @@ end
|
|||||||
' ├─Building plugins...'
|
' ├─Building plugins...'
|
||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
final String bitcodeGenerationMode = mode == BuildMode.release ?
|
|
||||||
'bitcode' : 'marker'; // In release, force bitcode embedding without archiving.
|
|
||||||
|
|
||||||
List<String> pluginsBuildCommand = <String>[
|
List<String> pluginsBuildCommand = <String>[
|
||||||
...globals.xcode!.xcrunCommand(),
|
...globals.xcode!.xcrunCommand(),
|
||||||
'xcodebuild',
|
'xcodebuild',
|
||||||
@ -492,7 +488,6 @@ end
|
|||||||
'-configuration',
|
'-configuration',
|
||||||
xcodeBuildConfiguration,
|
xcodeBuildConfiguration,
|
||||||
'SYMROOT=${iPhoneBuildOutput.path}',
|
'SYMROOT=${iPhoneBuildOutput.path}',
|
||||||
'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.
|
||||||
'BUILD_LIBRARY_FOR_DISTRIBUTION=YES',
|
'BUILD_LIBRARY_FOR_DISTRIBUTION=YES',
|
||||||
if (boolArg('static') ?? false)
|
if (boolArg('static') ?? false)
|
||||||
@ -519,7 +514,6 @@ end
|
|||||||
'-configuration',
|
'-configuration',
|
||||||
simulatorConfiguration,
|
simulatorConfiguration,
|
||||||
'SYMROOT=${simulatorBuildOutput.path}',
|
'SYMROOT=${simulatorBuildOutput.path}',
|
||||||
'ENABLE_BITCODE=YES', // Support host apps with bitcode enabled.
|
|
||||||
'ONLY_ACTIVE_ARCH=NO', // No device targeted, so build all valid architectures.
|
'ONLY_ACTIVE_ARCH=NO', // No device targeted, so build all valid architectures.
|
||||||
'BUILD_LIBRARY_FOR_DISTRIBUTION=YES',
|
'BUILD_LIBRARY_FOR_DISTRIBUTION=YES',
|
||||||
if (boolArg('static') ?? false)
|
if (boolArg('static') ?? false)
|
||||||
|
@ -1,66 +0,0 @@
|
|||||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
import '../artifacts.dart';
|
|
||||||
import '../base/common.dart';
|
|
||||||
import '../base/context.dart';
|
|
||||||
import '../base/process.dart';
|
|
||||||
import '../base/version.dart';
|
|
||||||
import '../build_info.dart';
|
|
||||||
import '../globals.dart' as globals;
|
|
||||||
import '../macos/xcode.dart';
|
|
||||||
|
|
||||||
const bool kBitcodeEnabledDefault = false;
|
|
||||||
|
|
||||||
Future<void> validateBitcode(BuildMode buildMode, TargetPlatform targetPlatform, EnvironmentType environmentType) async {
|
|
||||||
final Artifacts? localArtifacts = globals.artifacts;
|
|
||||||
final String? flutterFrameworkPath = localArtifacts?.getArtifactPath(
|
|
||||||
Artifact.flutterFramework,
|
|
||||||
mode: buildMode,
|
|
||||||
platform: targetPlatform,
|
|
||||||
environmentType: environmentType,
|
|
||||||
);
|
|
||||||
final Xcode? xcode = context.get<Xcode>();
|
|
||||||
|
|
||||||
final RunResult? clangResult = await xcode?.clang(<String>['--version']);
|
|
||||||
final String? clangVersion = clangResult?.stdout.split('\n').first;
|
|
||||||
final String? engineClangVersion = flutterFrameworkPath == null
|
|
||||||
? null
|
|
||||||
: globals.plistParser.getStringValueFromFile(
|
|
||||||
globals.fs.path.join(flutterFrameworkPath, 'Info.plist'),
|
|
||||||
'ClangVersion',
|
|
||||||
);
|
|
||||||
final Version engineClangSemVer = _parseVersionFromClang(engineClangVersion);
|
|
||||||
final Version clangSemVer = _parseVersionFromClang(clangVersion);
|
|
||||||
if (engineClangSemVer > clangSemVer) {
|
|
||||||
throwToolExit(
|
|
||||||
'The Flutter.framework at $flutterFrameworkPath was built '
|
|
||||||
'with "${engineClangVersion ?? 'unknown'}", but the current version '
|
|
||||||
'of clang is "$clangVersion". This will result in failures when trying to '
|
|
||||||
'archive an IPA. To resolve this issue, update your version of Xcode to '
|
|
||||||
'at least $engineClangSemVer.',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Version _parseVersionFromClang(String? clangVersion) {
|
|
||||||
final RegExp pattern = RegExp(r'Apple (LLVM|clang) version (\d+\.\d+\.\d+) ');
|
|
||||||
Never invalid() {
|
|
||||||
throwToolExit('Unable to parse Clang version from "$clangVersion". '
|
|
||||||
'Expected a string like "Apple (LLVM|clang) #.#.# (clang-####.#.##.#)".');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (clangVersion == null || clangVersion.isEmpty) {
|
|
||||||
invalid();
|
|
||||||
}
|
|
||||||
final RegExpMatch? match = pattern.firstMatch(clangVersion);
|
|
||||||
if (match == null || match.groupCount != 2) {
|
|
||||||
invalid();
|
|
||||||
}
|
|
||||||
final Version? version = Version.parse(match.group(2));
|
|
||||||
if (version == null) {
|
|
||||||
invalid();
|
|
||||||
}
|
|
||||||
return version;
|
|
||||||
}
|
|
@ -539,12 +539,10 @@ void main() {
|
|||||||
|
|
||||||
testWithoutContext('created with symbols', () async {
|
testWithoutContext('created with symbols', () async {
|
||||||
final Directory parentA = fileSystem.directory('FrameworkA')..createSync();
|
final Directory parentA = fileSystem.directory('FrameworkA')..createSync();
|
||||||
final File bcsymbolmapA = parentA.childFile('ABC123.bcsymbolmap')..createSync();
|
|
||||||
final File dSYMA = parentA.childFile('FrameworkA.framework.dSYM')..createSync();
|
final File dSYMA = parentA.childFile('FrameworkA.framework.dSYM')..createSync();
|
||||||
final Directory frameworkA = parentA.childDirectory('FrameworkA.framework')..createSync();
|
final Directory frameworkA = parentA.childDirectory('FrameworkA.framework')..createSync();
|
||||||
|
|
||||||
final Directory parentB = fileSystem.directory('FrameworkB')..createSync();
|
final Directory parentB = fileSystem.directory('FrameworkB')..createSync();
|
||||||
final File bcsymbolmapB = parentB.childFile('ZYX987.bcsymbolmap')..createSync();
|
|
||||||
final File dSYMB = parentB.childFile('FrameworkB.framework.dSYM')..createSync();
|
final File dSYMB = parentB.childFile('FrameworkB.framework.dSYM')..createSync();
|
||||||
final Directory frameworkB = parentB.childDirectory('FrameworkB.framework')..createSync();
|
final Directory frameworkB = parentB.childDirectory('FrameworkB.framework')..createSync();
|
||||||
final Directory output = fileSystem.directory('output');
|
final Directory output = fileSystem.directory('output');
|
||||||
@ -557,14 +555,10 @@ void main() {
|
|||||||
'-framework',
|
'-framework',
|
||||||
frameworkA.path,
|
frameworkA.path,
|
||||||
'-debug-symbols',
|
'-debug-symbols',
|
||||||
bcsymbolmapA.path,
|
|
||||||
'-debug-symbols',
|
|
||||||
dSYMA.path,
|
dSYMA.path,
|
||||||
'-framework',
|
'-framework',
|
||||||
frameworkB.path,
|
frameworkB.path,
|
||||||
'-debug-symbols',
|
'-debug-symbols',
|
||||||
bcsymbolmapB.path,
|
|
||||||
'-debug-symbols',
|
|
||||||
dSYMB.path,
|
dSYMB.path,
|
||||||
'-output',
|
'-output',
|
||||||
output.childDirectory('Combine.xcframework').path,
|
output.childDirectory('Combine.xcframework').path,
|
||||||
|
@ -444,42 +444,6 @@ void main() {
|
|||||||
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
|
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
|
||||||
});
|
});
|
||||||
|
|
||||||
testUsingContext('ipa build invokes xcodebuild and archives with bitcode on', () async {
|
|
||||||
final File cachedExportOptionsPlist = fileSystem.file('/CachedExportOptions.plist');
|
|
||||||
final BuildCommand command = BuildCommand();
|
|
||||||
fakeProcessManager.addCommands(<FakeCommand>[
|
|
||||||
xattrCommand,
|
|
||||||
setUpFakeXcodeBuildHandler(),
|
|
||||||
exportArchiveCommand(exportOptionsPlist: _exportOptionsPlist, cachePlist: cachedExportOptionsPlist),
|
|
||||||
]);
|
|
||||||
createMinimalMockProjectFiles();
|
|
||||||
|
|
||||||
await createTestCommandRunner(command).run(
|
|
||||||
const <String>['build', 'ipa', '--no-pub',]
|
|
||||||
);
|
|
||||||
|
|
||||||
const String expectedIpaPlistContents = '''
|
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>method</key>
|
|
||||||
<string>app-store</string>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
''';
|
|
||||||
|
|
||||||
final String actualIpaPlistContents = fileSystem.file(cachedExportOptionsPlist).readAsStringSync();
|
|
||||||
expect(actualIpaPlistContents, expectedIpaPlistContents);
|
|
||||||
}, overrides: <Type, Generator>{
|
|
||||||
FileSystem: () => fileSystem,
|
|
||||||
ProcessManager: () => fakeProcessManager,
|
|
||||||
Platform: () => macosPlatform,
|
|
||||||
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(
|
|
||||||
overrides: <String, String>{'ENABLE_BITCODE': 'YES'},
|
|
||||||
),
|
|
||||||
});
|
|
||||||
|
|
||||||
testUsingContext('ipa build invokes xcode build with verbosity', () async {
|
testUsingContext('ipa build invokes xcode build with verbosity', () async {
|
||||||
final BuildCommand command = BuildCommand();
|
final BuildCommand command = BuildCommand();
|
||||||
fakeProcessManager.addCommands(<FakeCommand>[
|
fakeProcessManager.addCommands(<FakeCommand>[
|
||||||
|
@ -165,7 +165,6 @@ void main() {
|
|||||||
buildMode: BuildMode.debug,
|
buildMode: BuildMode.debug,
|
||||||
mainPath: 'main.dill',
|
mainPath: 'main.dill',
|
||||||
outputPath: outputPath,
|
outputPath: outputPath,
|
||||||
bitcode: false,
|
|
||||||
dartObfuscation: false,
|
dartObfuscation: false,
|
||||||
), isNot(equals(0)));
|
), isNot(equals(0)));
|
||||||
});
|
});
|
||||||
@ -178,7 +177,6 @@ void main() {
|
|||||||
buildMode: BuildMode.debug,
|
buildMode: BuildMode.debug,
|
||||||
mainPath: 'main.dill',
|
mainPath: 'main.dill',
|
||||||
outputPath: outputPath,
|
outputPath: outputPath,
|
||||||
bitcode: false,
|
|
||||||
dartObfuscation: false,
|
dartObfuscation: false,
|
||||||
), isNot(0));
|
), isNot(0));
|
||||||
});
|
});
|
||||||
@ -191,99 +189,10 @@ void main() {
|
|||||||
buildMode: BuildMode.debug,
|
buildMode: BuildMode.debug,
|
||||||
mainPath: 'main.dill',
|
mainPath: 'main.dill',
|
||||||
outputPath: outputPath,
|
outputPath: outputPath,
|
||||||
bitcode: false,
|
|
||||||
dartObfuscation: false,
|
dartObfuscation: false,
|
||||||
), isNot(0));
|
), isNot(0));
|
||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('builds iOS with bitcode', () async {
|
|
||||||
final String outputPath = fileSystem.path.join('build', 'foo');
|
|
||||||
final String assembly = fileSystem.path.join(outputPath, 'snapshot_assembly.S');
|
|
||||||
final String genSnapshotPath = artifacts.getArtifactPath(
|
|
||||||
Artifact.genSnapshot,
|
|
||||||
platform: TargetPlatform.ios,
|
|
||||||
mode: BuildMode.profile,
|
|
||||||
);
|
|
||||||
processManager.addCommands(<FakeCommand>[
|
|
||||||
FakeCommand(command: <String>[
|
|
||||||
'${genSnapshotPath}_arm64',
|
|
||||||
'--deterministic',
|
|
||||||
'--snapshot_kind=app-aot-assembly',
|
|
||||||
'--assembly=$assembly',
|
|
||||||
'main.dill',
|
|
||||||
]),
|
|
||||||
kWhichSysctlCommand,
|
|
||||||
kARMCheckCommand,
|
|
||||||
const FakeCommand(command: <String>[
|
|
||||||
'xcrun',
|
|
||||||
'cc',
|
|
||||||
'-arch',
|
|
||||||
'arm64',
|
|
||||||
'-miphoneos-version-min=11.0',
|
|
||||||
'-isysroot',
|
|
||||||
'path/to/sdk',
|
|
||||||
'-fembed-bitcode',
|
|
||||||
'-c',
|
|
||||||
'build/foo/snapshot_assembly.S',
|
|
||||||
'-o',
|
|
||||||
'build/foo/snapshot_assembly.o',
|
|
||||||
]),
|
|
||||||
const FakeCommand(command: <String>[
|
|
||||||
'xcrun',
|
|
||||||
'clang',
|
|
||||||
'-arch',
|
|
||||||
'arm64',
|
|
||||||
'-miphoneos-version-min=11.0',
|
|
||||||
'-isysroot',
|
|
||||||
'path/to/sdk',
|
|
||||||
'-dynamiclib',
|
|
||||||
'-Xlinker',
|
|
||||||
'-rpath',
|
|
||||||
'-Xlinker',
|
|
||||||
'@executable_path/Frameworks',
|
|
||||||
'-Xlinker',
|
|
||||||
'-rpath',
|
|
||||||
'-Xlinker',
|
|
||||||
'@loader_path/Frameworks',
|
|
||||||
'-install_name',
|
|
||||||
'@rpath/App.framework/App',
|
|
||||||
'-fembed-bitcode',
|
|
||||||
'-o',
|
|
||||||
'build/foo/App.framework/App',
|
|
||||||
'build/foo/snapshot_assembly.o',
|
|
||||||
]),
|
|
||||||
const FakeCommand(command: <String>[
|
|
||||||
'xcrun',
|
|
||||||
'dsymutil',
|
|
||||||
'-o',
|
|
||||||
'build/foo/App.framework.dSYM',
|
|
||||||
'build/foo/App.framework/App',
|
|
||||||
]),
|
|
||||||
const FakeCommand(command: <String>[
|
|
||||||
'xcrun',
|
|
||||||
'strip',
|
|
||||||
'-x',
|
|
||||||
'build/foo/App.framework/App',
|
|
||||||
'-o',
|
|
||||||
'build/foo/App.framework/App',
|
|
||||||
]),
|
|
||||||
]);
|
|
||||||
|
|
||||||
final int genSnapshotExitCode = await snapshotter.build(
|
|
||||||
platform: TargetPlatform.ios,
|
|
||||||
buildMode: BuildMode.profile,
|
|
||||||
mainPath: 'main.dill',
|
|
||||||
outputPath: outputPath,
|
|
||||||
darwinArch: DarwinArch.arm64,
|
|
||||||
sdkRoot: 'path/to/sdk',
|
|
||||||
bitcode: true,
|
|
||||||
dartObfuscation: false,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(genSnapshotExitCode, 0);
|
|
||||||
expect(processManager, hasNoRemainingExpectations);
|
|
||||||
});
|
|
||||||
|
|
||||||
testWithoutContext('builds iOS snapshot with dwarfStackTraces', () async {
|
testWithoutContext('builds iOS snapshot with dwarfStackTraces', () async {
|
||||||
final String outputPath = fileSystem.path.join('build', 'foo');
|
final String outputPath = fileSystem.path.join('build', 'foo');
|
||||||
final String assembly = fileSystem.path.join(outputPath, 'snapshot_assembly.S');
|
final String assembly = fileSystem.path.join(outputPath, 'snapshot_assembly.S');
|
||||||
@ -349,7 +258,6 @@ void main() {
|
|||||||
outputPath: outputPath,
|
outputPath: outputPath,
|
||||||
darwinArch: DarwinArch.arm64,
|
darwinArch: DarwinArch.arm64,
|
||||||
sdkRoot: 'path/to/sdk',
|
sdkRoot: 'path/to/sdk',
|
||||||
bitcode: false,
|
|
||||||
splitDebugInfo: 'foo',
|
splitDebugInfo: 'foo',
|
||||||
dartObfuscation: false,
|
dartObfuscation: false,
|
||||||
);
|
);
|
||||||
@ -421,7 +329,6 @@ void main() {
|
|||||||
outputPath: outputPath,
|
outputPath: outputPath,
|
||||||
darwinArch: DarwinArch.arm64,
|
darwinArch: DarwinArch.arm64,
|
||||||
sdkRoot: 'path/to/sdk',
|
sdkRoot: 'path/to/sdk',
|
||||||
bitcode: false,
|
|
||||||
dartObfuscation: true,
|
dartObfuscation: true,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -490,7 +397,6 @@ void main() {
|
|||||||
outputPath: outputPath,
|
outputPath: outputPath,
|
||||||
darwinArch: DarwinArch.arm64,
|
darwinArch: DarwinArch.arm64,
|
||||||
sdkRoot: 'path/to/sdk',
|
sdkRoot: 'path/to/sdk',
|
||||||
bitcode: false,
|
|
||||||
dartObfuscation: false,
|
dartObfuscation: false,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -518,7 +424,6 @@ void main() {
|
|||||||
buildMode: BuildMode.release,
|
buildMode: BuildMode.release,
|
||||||
mainPath: 'main.dill',
|
mainPath: 'main.dill',
|
||||||
outputPath: outputPath,
|
outputPath: outputPath,
|
||||||
bitcode: false,
|
|
||||||
dartObfuscation: false,
|
dartObfuscation: false,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -549,7 +454,6 @@ void main() {
|
|||||||
buildMode: BuildMode.release,
|
buildMode: BuildMode.release,
|
||||||
mainPath: 'main.dill',
|
mainPath: 'main.dill',
|
||||||
outputPath: outputPath,
|
outputPath: outputPath,
|
||||||
bitcode: false,
|
|
||||||
splitDebugInfo: 'foo',
|
splitDebugInfo: 'foo',
|
||||||
dartObfuscation: false,
|
dartObfuscation: false,
|
||||||
);
|
);
|
||||||
@ -579,7 +483,6 @@ void main() {
|
|||||||
buildMode: BuildMode.release,
|
buildMode: BuildMode.release,
|
||||||
mainPath: 'main.dill',
|
mainPath: 'main.dill',
|
||||||
outputPath: outputPath,
|
outputPath: outputPath,
|
||||||
bitcode: false,
|
|
||||||
dartObfuscation: true,
|
dartObfuscation: true,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -607,7 +510,6 @@ void main() {
|
|||||||
buildMode: BuildMode.release,
|
buildMode: BuildMode.release,
|
||||||
mainPath: 'main.dill',
|
mainPath: 'main.dill',
|
||||||
outputPath: outputPath,
|
outputPath: outputPath,
|
||||||
bitcode: false,
|
|
||||||
splitDebugInfo: '',
|
splitDebugInfo: '',
|
||||||
dartObfuscation: false,
|
dartObfuscation: false,
|
||||||
);
|
);
|
||||||
@ -634,7 +536,6 @@ void main() {
|
|||||||
buildMode: BuildMode.release,
|
buildMode: BuildMode.release,
|
||||||
mainPath: 'main.dill',
|
mainPath: 'main.dill',
|
||||||
outputPath: outputPath,
|
outputPath: outputPath,
|
||||||
bitcode: false,
|
|
||||||
dartObfuscation: false,
|
dartObfuscation: false,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -659,7 +560,6 @@ void main() {
|
|||||||
buildMode: BuildMode.release,
|
buildMode: BuildMode.release,
|
||||||
mainPath: 'main.dill',
|
mainPath: 'main.dill',
|
||||||
outputPath: outputPath,
|
outputPath: outputPath,
|
||||||
bitcode: false,
|
|
||||||
dartObfuscation: false,
|
dartObfuscation: false,
|
||||||
extraGenSnapshotOptions: const <String>['--no-strip'],
|
extraGenSnapshotOptions: const <String>['--no-strip'],
|
||||||
);
|
);
|
||||||
|
@ -465,98 +465,10 @@ void main() {
|
|||||||
ProcessManager: () => processManager,
|
ProcessManager: () => processManager,
|
||||||
});
|
});
|
||||||
|
|
||||||
testUsingContext('AotAssemblyProfile with bitcode sends correct argument to snapshotter', () async {
|
|
||||||
iosEnvironment.defines[kIosArchs] = 'arm64';
|
|
||||||
iosEnvironment.defines[kBitcodeFlag] = 'true';
|
|
||||||
iosEnvironment.defines[kSdkRoot] = 'path/to/iPhoneOS.sdk';
|
|
||||||
final String build = iosEnvironment.buildDir.path;
|
|
||||||
processManager.addCommands(<FakeCommand>[
|
|
||||||
FakeCommand(command: <String>[
|
|
||||||
// This path is not known by the cache due to the iOS gen_snapshot split.
|
|
||||||
'Artifact.genSnapshot.TargetPlatform.ios.profile_arm64',
|
|
||||||
'--deterministic',
|
|
||||||
kAssemblyAot,
|
|
||||||
'--assembly=$build/arm64/snapshot_assembly.S',
|
|
||||||
'$build/app.dill',
|
|
||||||
]),
|
|
||||||
FakeCommand(command: <String>[
|
|
||||||
'xcrun',
|
|
||||||
'cc',
|
|
||||||
'-arch',
|
|
||||||
'arm64',
|
|
||||||
'-miphoneos-version-min=11.0',
|
|
||||||
'-isysroot',
|
|
||||||
'path/to/iPhoneOS.sdk',
|
|
||||||
// Contains bitcode flag.
|
|
||||||
'-fembed-bitcode',
|
|
||||||
'-c',
|
|
||||||
'$build/arm64/snapshot_assembly.S',
|
|
||||||
'-o',
|
|
||||||
'$build/arm64/snapshot_assembly.o',
|
|
||||||
]),
|
|
||||||
FakeCommand(command: <String>[
|
|
||||||
'xcrun',
|
|
||||||
'clang',
|
|
||||||
'-arch',
|
|
||||||
'arm64',
|
|
||||||
'-miphoneos-version-min=11.0',
|
|
||||||
'-isysroot',
|
|
||||||
'path/to/iPhoneOS.sdk',
|
|
||||||
'-dynamiclib',
|
|
||||||
'-Xlinker',
|
|
||||||
'-rpath',
|
|
||||||
'-Xlinker',
|
|
||||||
'@executable_path/Frameworks',
|
|
||||||
'-Xlinker',
|
|
||||||
'-rpath',
|
|
||||||
'-Xlinker',
|
|
||||||
'@loader_path/Frameworks',
|
|
||||||
'-install_name',
|
|
||||||
'@rpath/App.framework/App',
|
|
||||||
// Contains bitcode flag.
|
|
||||||
'-fembed-bitcode',
|
|
||||||
'-o',
|
|
||||||
'$build/arm64/App.framework/App',
|
|
||||||
'$build/arm64/snapshot_assembly.o',
|
|
||||||
]),
|
|
||||||
FakeCommand(command: <String>[
|
|
||||||
'xcrun',
|
|
||||||
'dsymutil',
|
|
||||||
'-o',
|
|
||||||
'$build/arm64/App.framework.dSYM',
|
|
||||||
'$build/arm64/App.framework/App',
|
|
||||||
]),
|
|
||||||
FakeCommand(command: <String>[
|
|
||||||
'xcrun',
|
|
||||||
'strip',
|
|
||||||
'-x',
|
|
||||||
'$build/arm64/App.framework/App',
|
|
||||||
'-o',
|
|
||||||
'$build/arm64/App.framework/App',
|
|
||||||
]),
|
|
||||||
FakeCommand(command: <String>[
|
|
||||||
'lipo',
|
|
||||||
'$build/arm64/App.framework/App',
|
|
||||||
'-create',
|
|
||||||
'-output',
|
|
||||||
'$build/App.framework/App',
|
|
||||||
]),
|
|
||||||
]);
|
|
||||||
|
|
||||||
await const AotAssemblyProfile().build(iosEnvironment);
|
|
||||||
|
|
||||||
expect(processManager, hasNoRemainingExpectations);
|
|
||||||
}, overrides: <Type, Generator>{
|
|
||||||
Platform: () => macPlatform,
|
|
||||||
FileSystem: () => fileSystem,
|
|
||||||
ProcessManager: () => processManager,
|
|
||||||
});
|
|
||||||
|
|
||||||
testUsingContext('AotAssemblyRelease configures gen_snapshot with code size directory', () async {
|
testUsingContext('AotAssemblyRelease configures gen_snapshot with code size directory', () async {
|
||||||
iosEnvironment.defines[kCodeSizeDirectory] = 'code_size_1';
|
iosEnvironment.defines[kCodeSizeDirectory] = 'code_size_1';
|
||||||
iosEnvironment.defines[kIosArchs] = 'arm64';
|
iosEnvironment.defines[kIosArchs] = 'arm64';
|
||||||
iosEnvironment.defines[kSdkRoot] = 'path/to/iPhoneOS.sdk';
|
iosEnvironment.defines[kSdkRoot] = 'path/to/iPhoneOS.sdk';
|
||||||
iosEnvironment.defines[kBitcodeFlag] = 'true';
|
|
||||||
final String build = iosEnvironment.buildDir.path;
|
final String build = iosEnvironment.buildDir.path;
|
||||||
processManager.addCommands(<FakeCommand>[
|
processManager.addCommands(<FakeCommand>[
|
||||||
FakeCommand(command: <String>[
|
FakeCommand(command: <String>[
|
||||||
@ -577,8 +489,6 @@ void main() {
|
|||||||
'-miphoneos-version-min=11.0',
|
'-miphoneos-version-min=11.0',
|
||||||
'-isysroot',
|
'-isysroot',
|
||||||
'path/to/iPhoneOS.sdk',
|
'path/to/iPhoneOS.sdk',
|
||||||
// Contains bitcode flag.
|
|
||||||
'-fembed-bitcode',
|
|
||||||
'-c',
|
'-c',
|
||||||
'$build/arm64/snapshot_assembly.S',
|
'$build/arm64/snapshot_assembly.S',
|
||||||
'-o',
|
'-o',
|
||||||
@ -603,8 +513,6 @@ void main() {
|
|||||||
'@loader_path/Frameworks',
|
'@loader_path/Frameworks',
|
||||||
'-install_name',
|
'-install_name',
|
||||||
'@rpath/App.framework/App',
|
'@rpath/App.framework/App',
|
||||||
// Contains bitcode flag.
|
|
||||||
'-fembed-bitcode',
|
|
||||||
'-o',
|
'-o',
|
||||||
'$build/arm64/App.framework/App',
|
'$build/arm64/App.framework/App',
|
||||||
'$build/arm64/snapshot_assembly.o',
|
'$build/arm64/snapshot_assembly.o',
|
||||||
|
@ -22,7 +22,6 @@ final Platform macPlatform = FakePlatform(operatingSystem: 'macos', environment:
|
|||||||
|
|
||||||
const List<String> _kSharedConfig = <String>[
|
const List<String> _kSharedConfig = <String>[
|
||||||
'-dynamiclib',
|
'-dynamiclib',
|
||||||
'-fembed-bitcode-marker',
|
|
||||||
'-miphoneos-version-min=11.0',
|
'-miphoneos-version-min=11.0',
|
||||||
'-Xlinker',
|
'-Xlinker',
|
||||||
'-rpath',
|
'-rpath',
|
||||||
@ -87,7 +86,6 @@ void main() {
|
|||||||
fileSystem.path.absolute(fileSystem.path.join(
|
fileSystem.path.absolute(fileSystem.path.join(
|
||||||
'.tmp_rand0', 'flutter_tools_stub_source.rand0', 'debug_app.cc')),
|
'.tmp_rand0', 'flutter_tools_stub_source.rand0', 'debug_app.cc')),
|
||||||
'-dynamiclib',
|
'-dynamiclib',
|
||||||
'-fembed-bitcode-marker',
|
|
||||||
'-miphonesimulator-version-min=11.0',
|
'-miphonesimulator-version-min=11.0',
|
||||||
'-Xlinker',
|
'-Xlinker',
|
||||||
'-rpath',
|
'-rpath',
|
||||||
@ -393,7 +391,6 @@ void main() {
|
|||||||
late FakeCommand copyPhysicalFrameworkCommand;
|
late FakeCommand copyPhysicalFrameworkCommand;
|
||||||
late FakeCommand lipoCommandNonFatResult;
|
late FakeCommand lipoCommandNonFatResult;
|
||||||
late FakeCommand lipoVerifyArm64Command;
|
late FakeCommand lipoVerifyArm64Command;
|
||||||
late FakeCommand bitcodeStripCommand;
|
|
||||||
late FakeCommand adHocCodesignCommand;
|
late FakeCommand adHocCodesignCommand;
|
||||||
|
|
||||||
setUp(() {
|
setUp(() {
|
||||||
@ -423,15 +420,6 @@ void main() {
|
|||||||
'arm64',
|
'arm64',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
bitcodeStripCommand = FakeCommand(command: <String>[
|
|
||||||
'xcrun',
|
|
||||||
'bitcode_strip',
|
|
||||||
binary.path,
|
|
||||||
'-m',
|
|
||||||
'-o',
|
|
||||||
binary.path,
|
|
||||||
]);
|
|
||||||
|
|
||||||
adHocCodesignCommand = FakeCommand(command: <String>[
|
adHocCodesignCommand = FakeCommand(command: <String>[
|
||||||
'codesign',
|
'codesign',
|
||||||
'--force',
|
'--force',
|
||||||
@ -453,7 +441,6 @@ void main() {
|
|||||||
defines: <String, String>{
|
defines: <String, String>{
|
||||||
kIosArchs: 'x86_64',
|
kIosArchs: 'x86_64',
|
||||||
kSdkRoot: 'path/to/iPhoneSimulator.sdk',
|
kSdkRoot: 'path/to/iPhoneSimulator.sdk',
|
||||||
kBitcodeFlag: 'true',
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -495,7 +482,6 @@ void main() {
|
|||||||
defines: <String, String>{
|
defines: <String, String>{
|
||||||
kIosArchs: 'arm64',
|
kIosArchs: 'arm64',
|
||||||
kSdkRoot: 'path/to/iPhoneOS.sdk',
|
kSdkRoot: 'path/to/iPhoneOS.sdk',
|
||||||
kBitcodeFlag: '',
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
processManager.addCommand(copyPhysicalFrameworkCommand);
|
processManager.addCommand(copyPhysicalFrameworkCommand);
|
||||||
@ -521,7 +507,6 @@ void main() {
|
|||||||
defines: <String, String>{
|
defines: <String, String>{
|
||||||
kIosArchs: 'arm64 armv7',
|
kIosArchs: 'arm64 armv7',
|
||||||
kSdkRoot: 'path/to/iPhoneOS.sdk',
|
kSdkRoot: 'path/to/iPhoneOS.sdk',
|
||||||
kBitcodeFlag: '',
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -564,7 +549,6 @@ void main() {
|
|||||||
defines: <String, String>{
|
defines: <String, String>{
|
||||||
kIosArchs: 'arm64 armv7',
|
kIosArchs: 'arm64 armv7',
|
||||||
kSdkRoot: 'path/to/iPhoneOS.sdk',
|
kSdkRoot: 'path/to/iPhoneOS.sdk',
|
||||||
kBitcodeFlag: '',
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -618,7 +602,6 @@ void main() {
|
|||||||
defines: <String, String>{
|
defines: <String, String>{
|
||||||
kIosArchs: 'arm64',
|
kIosArchs: 'arm64',
|
||||||
kSdkRoot: 'path/to/iPhoneOS.sdk',
|
kSdkRoot: 'path/to/iPhoneOS.sdk',
|
||||||
kBitcodeFlag: 'true',
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -648,7 +631,6 @@ void main() {
|
|||||||
defines: <String, String>{
|
defines: <String, String>{
|
||||||
kIosArchs: 'arm64 armv7',
|
kIosArchs: 'arm64 armv7',
|
||||||
kSdkRoot: 'path/to/iPhoneOS.sdk',
|
kSdkRoot: 'path/to/iPhoneOS.sdk',
|
||||||
kBitcodeFlag: 'true',
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -696,26 +678,33 @@ void main() {
|
|||||||
defines: <String, String>{
|
defines: <String, String>{
|
||||||
kIosArchs: 'arm64',
|
kIosArchs: 'arm64',
|
||||||
kSdkRoot: 'path/to/iPhoneOS.sdk',
|
kSdkRoot: 'path/to/iPhoneOS.sdk',
|
||||||
kBitcodeFlag: '',
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
processManager.addCommands(<FakeCommand>[
|
processManager.addCommands(<FakeCommand>[
|
||||||
copyPhysicalFrameworkCommand,
|
FakeCommand(command: <String>[
|
||||||
|
'rsync',
|
||||||
|
'-av',
|
||||||
|
'--delete',
|
||||||
|
'--filter',
|
||||||
|
'- .DS_Store/',
|
||||||
|
'Artifact.flutterFramework.TargetPlatform.ios.release.EnvironmentType.physical',
|
||||||
|
outputDir.path,
|
||||||
|
]),
|
||||||
lipoCommandNonFatResult,
|
lipoCommandNonFatResult,
|
||||||
lipoVerifyArm64Command,
|
lipoVerifyArm64Command,
|
||||||
FakeCommand(command: <String>[
|
FakeCommand(command: <String>[
|
||||||
'xcrun',
|
'xcrun',
|
||||||
'bitcode_strip',
|
'bitcode_strip',
|
||||||
binary.path,
|
binary.path,
|
||||||
'-m',
|
'-r',
|
||||||
'-o',
|
'-o',
|
||||||
binary.path,
|
binary.path,
|
||||||
], exitCode: 1, stderr: 'bitcode_strip error'),
|
], exitCode: 1, stderr: 'bitcode_strip error'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
await expectLater(
|
await expectLater(
|
||||||
const DebugUnpackIOS().build(environment),
|
const ReleaseUnpackIOS().build(environment),
|
||||||
throwsA(isException.having(
|
throwsA(isException.having(
|
||||||
(Exception exception) => exception.toString(),
|
(Exception exception) => exception.toString(),
|
||||||
'description',
|
'description',
|
||||||
@ -739,7 +728,6 @@ void main() {
|
|||||||
defines: <String, String>{
|
defines: <String, String>{
|
||||||
kIosArchs: 'arm64',
|
kIosArchs: 'arm64',
|
||||||
kSdkRoot: 'path/to/iPhoneOS.sdk',
|
kSdkRoot: 'path/to/iPhoneOS.sdk',
|
||||||
kBitcodeFlag: '',
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -747,7 +735,6 @@ void main() {
|
|||||||
copyPhysicalFrameworkCommand,
|
copyPhysicalFrameworkCommand,
|
||||||
lipoCommandNonFatResult,
|
lipoCommandNonFatResult,
|
||||||
lipoVerifyArm64Command,
|
lipoVerifyArm64Command,
|
||||||
bitcodeStripCommand,
|
|
||||||
adHocCodesignCommand,
|
adHocCodesignCommand,
|
||||||
]);
|
]);
|
||||||
await const DebugUnpackIOS().build(environment);
|
await const DebugUnpackIOS().build(environment);
|
||||||
@ -768,7 +755,6 @@ void main() {
|
|||||||
defines: <String, String>{
|
defines: <String, String>{
|
||||||
kIosArchs: 'arm64',
|
kIosArchs: 'arm64',
|
||||||
kSdkRoot: 'path/to/iPhoneOS.sdk',
|
kSdkRoot: 'path/to/iPhoneOS.sdk',
|
||||||
kBitcodeFlag: '',
|
|
||||||
kCodesignIdentity: 'ABC123',
|
kCodesignIdentity: 'ABC123',
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -777,7 +763,6 @@ void main() {
|
|||||||
copyPhysicalFrameworkCommand,
|
copyPhysicalFrameworkCommand,
|
||||||
lipoCommandNonFatResult,
|
lipoCommandNonFatResult,
|
||||||
lipoVerifyArm64Command,
|
lipoVerifyArm64Command,
|
||||||
bitcodeStripCommand,
|
|
||||||
FakeCommand(command: <String>[
|
FakeCommand(command: <String>[
|
||||||
'codesign',
|
'codesign',
|
||||||
'--force',
|
'--force',
|
||||||
@ -813,7 +798,6 @@ void main() {
|
|||||||
defines: <String, String>{
|
defines: <String, String>{
|
||||||
kIosArchs: 'arm64',
|
kIosArchs: 'arm64',
|
||||||
kSdkRoot: 'path/to/iPhoneOS.sdk',
|
kSdkRoot: 'path/to/iPhoneOS.sdk',
|
||||||
kBitcodeFlag: '',
|
|
||||||
kCodesignIdentity: 'ABC123',
|
kCodesignIdentity: 'ABC123',
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -822,7 +806,6 @@ void main() {
|
|||||||
copyPhysicalFrameworkCommand,
|
copyPhysicalFrameworkCommand,
|
||||||
lipoCommandNonFatResult,
|
lipoCommandNonFatResult,
|
||||||
lipoVerifyArm64Command,
|
lipoVerifyArm64Command,
|
||||||
bitcodeStripCommand,
|
|
||||||
FakeCommand(command: <String>[
|
FakeCommand(command: <String>[
|
||||||
'codesign',
|
'codesign',
|
||||||
'--force',
|
'--force',
|
||||||
|
@ -31,7 +31,6 @@ void main() {
|
|||||||
<String, String>{
|
<String, String>{
|
||||||
'ACTION': 'build',
|
'ACTION': 'build',
|
||||||
'BUILT_PRODUCTS_DIR': buildDir.path,
|
'BUILT_PRODUCTS_DIR': buildDir.path,
|
||||||
'ENABLE_BITCODE': 'YES',
|
|
||||||
'FLUTTER_ROOT': flutterRoot.path,
|
'FLUTTER_ROOT': flutterRoot.path,
|
||||||
'INFOPLIST_PATH': 'Info.plist',
|
'INFOPLIST_PATH': 'Info.plist',
|
||||||
},
|
},
|
||||||
@ -51,7 +50,6 @@ void main() {
|
|||||||
'-dTreeShakeIcons=',
|
'-dTreeShakeIcons=',
|
||||||
'-dTrackWidgetCreation=',
|
'-dTrackWidgetCreation=',
|
||||||
'-dDartObfuscation=',
|
'-dDartObfuscation=',
|
||||||
'-dEnableBitcode=',
|
|
||||||
'-dAction=build',
|
'-dAction=build',
|
||||||
'--ExtraGenSnapshotOptions=',
|
'--ExtraGenSnapshotOptions=',
|
||||||
'--DartDefines=',
|
'--DartDefines=',
|
||||||
@ -85,7 +83,6 @@ void main() {
|
|||||||
<String, String>{
|
<String, String>{
|
||||||
'BUILT_PRODUCTS_DIR': buildDir.path,
|
'BUILT_PRODUCTS_DIR': buildDir.path,
|
||||||
'CONFIGURATION': buildMode,
|
'CONFIGURATION': buildMode,
|
||||||
'ENABLE_BITCODE': 'YES',
|
|
||||||
'FLUTTER_ROOT': flutterRoot.path,
|
'FLUTTER_ROOT': flutterRoot.path,
|
||||||
'INFOPLIST_PATH': 'Info.plist',
|
'INFOPLIST_PATH': 'Info.plist',
|
||||||
},
|
},
|
||||||
@ -105,7 +102,6 @@ void main() {
|
|||||||
'-dTreeShakeIcons=',
|
'-dTreeShakeIcons=',
|
||||||
'-dTrackWidgetCreation=',
|
'-dTrackWidgetCreation=',
|
||||||
'-dDartObfuscation=',
|
'-dDartObfuscation=',
|
||||||
'-dEnableBitcode=',
|
|
||||||
'-dAction=',
|
'-dAction=',
|
||||||
'--ExtraGenSnapshotOptions=',
|
'--ExtraGenSnapshotOptions=',
|
||||||
'--DartDefines=',
|
'--DartDefines=',
|
||||||
@ -154,7 +150,6 @@ void main() {
|
|||||||
'CONFIGURATION': buildMode,
|
'CONFIGURATION': buildMode,
|
||||||
'DART_DEFINES': dartDefines,
|
'DART_DEFINES': dartDefines,
|
||||||
'DART_OBFUSCATION': dartObfuscation,
|
'DART_OBFUSCATION': dartObfuscation,
|
||||||
'ENABLE_BITCODE': 'YES',
|
|
||||||
'EXPANDED_CODE_SIGN_IDENTITY': expandedCodeSignIdentity,
|
'EXPANDED_CODE_SIGN_IDENTITY': expandedCodeSignIdentity,
|
||||||
'EXTRA_FRONT_END_OPTIONS': extraFrontEndOptions,
|
'EXTRA_FRONT_END_OPTIONS': extraFrontEndOptions,
|
||||||
'EXTRA_GEN_SNAPSHOT_OPTIONS': extraGenSnapshotOptions,
|
'EXTRA_GEN_SNAPSHOT_OPTIONS': extraGenSnapshotOptions,
|
||||||
@ -181,7 +176,6 @@ void main() {
|
|||||||
'-dTreeShakeIcons=$treeShake',
|
'-dTreeShakeIcons=$treeShake',
|
||||||
'-dTrackWidgetCreation=$trackWidgetCreation',
|
'-dTrackWidgetCreation=$trackWidgetCreation',
|
||||||
'-dDartObfuscation=$dartObfuscation',
|
'-dDartObfuscation=$dartObfuscation',
|
||||||
'-dEnableBitcode=true',
|
|
||||||
'-dAction=install',
|
'-dAction=install',
|
||||||
'--ExtraGenSnapshotOptions=$extraGenSnapshotOptions',
|
'--ExtraGenSnapshotOptions=$extraGenSnapshotOptions',
|
||||||
'--DartDefines=$dartDefines',
|
'--DartDefines=$dartDefines',
|
||||||
|
@ -7,10 +7,11 @@ import 'package:flutter_tools/src/base/file_system.dart';
|
|||||||
import 'package:flutter_tools/src/base/io.dart';
|
import 'package:flutter_tools/src/base/io.dart';
|
||||||
import 'package:flutter_tools/src/base/utils.dart';
|
import 'package:flutter_tools/src/base/utils.dart';
|
||||||
import 'package:flutter_tools/src/build_info.dart';
|
import 'package:flutter_tools/src/build_info.dart';
|
||||||
|
import 'package:flutter_tools/src/convert.dart';
|
||||||
|
|
||||||
import '../integration.shard/test_utils.dart';
|
import '../integration.shard/test_utils.dart';
|
||||||
import '../src/common.dart';
|
import '../src/common.dart';
|
||||||
import '../src/darwin_common.dart';
|
import '../src/fake_process_manager.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
group('iOS app validation', () {
|
group('iOS app validation', () {
|
||||||
@ -152,10 +153,8 @@ void main() {
|
|||||||
|
|
||||||
expect(vmSnapshot.existsSync(), buildMode == BuildMode.debug);
|
expect(vmSnapshot.existsSync(), buildMode == BuildMode.debug);
|
||||||
|
|
||||||
// Archiving should contain a bitcode blob, but not building.
|
// Builds should not contain deprecated bitcode.
|
||||||
// This mimics Xcode behavior and prevents a developer from having to install a
|
expect(_containsBitcode(outputFlutterFrameworkBinary.path, processManager), isFalse);
|
||||||
// 300+MB app.
|
|
||||||
expect(containsBitcode(outputFlutterFrameworkBinary.path, processManager), isFalse);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('Info.plist dart observatory Bonjour service', () {
|
testWithoutContext('Info.plist dart observatory Bonjour service', () {
|
||||||
@ -358,3 +357,46 @@ void main() {
|
|||||||
timeout: const Timeout(Duration(minutes: 7))
|
timeout: const Timeout(Duration(minutes: 7))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool _containsBitcode(String pathToBinary, ProcessManager processManager) {
|
||||||
|
// See: https://stackoverflow.com/questions/32755775/how-to-check-a-static-library-is-built-contain-bitcode
|
||||||
|
final ProcessResult result = processManager.runSync(<String>[
|
||||||
|
'otool',
|
||||||
|
'-l',
|
||||||
|
'-arch',
|
||||||
|
'arm64',
|
||||||
|
pathToBinary,
|
||||||
|
]);
|
||||||
|
final String loadCommands = result.stdout as String;
|
||||||
|
if (!loadCommands.contains('__LLVM')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Presence of the section may mean a bitcode marker was embedded (size=1), but there is no content.
|
||||||
|
if (!loadCommands.contains('size 0x0000000000000001')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Check the false positives: size=1 wasn't referencing the __LLVM section.
|
||||||
|
|
||||||
|
bool emptyBitcodeMarkerFound = false;
|
||||||
|
// Section
|
||||||
|
// sectname __bundle
|
||||||
|
// segname __LLVM
|
||||||
|
// addr 0x003c4000
|
||||||
|
// size 0x0042b633
|
||||||
|
// offset 3932160
|
||||||
|
// ...
|
||||||
|
final List<String> lines = LineSplitter.split(loadCommands).toList();
|
||||||
|
lines.asMap().forEach((int index, String line) {
|
||||||
|
if (line.contains('segname __LLVM') && lines.length - index - 1 > 3) {
|
||||||
|
final bool bitcodeMarkerFound = lines
|
||||||
|
.skip(index - 1)
|
||||||
|
.take(4)
|
||||||
|
.any((String line) => line.contains(' size 0x0000000000000001'));
|
||||||
|
if (bitcodeMarkerFound) {
|
||||||
|
emptyBitcodeMarkerFound = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return !emptyBitcodeMarkerFound;
|
||||||
|
}
|
||||||
|
@ -8,7 +8,6 @@ import 'package:flutter_tools/src/base/io.dart';
|
|||||||
|
|
||||||
import '../integration.shard/test_utils.dart';
|
import '../integration.shard/test_utils.dart';
|
||||||
import '../src/common.dart';
|
import '../src/common.dart';
|
||||||
import '../src/darwin_common.dart';
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
final String flutterBin = fileSystem.path.join(
|
final String flutterBin = fileSystem.path.join(
|
||||||
@ -150,18 +149,6 @@ void main() {
|
|||||||
expect(outputFlutterFramework.childLink('Modules'), isNot(exists));
|
expect(outputFlutterFramework.childLink('Modules'), isNot(exists));
|
||||||
expect(outputFlutterFramework.childDirectory('Modules'), isNot(exists));
|
expect(outputFlutterFramework.childDirectory('Modules'), isNot(exists));
|
||||||
|
|
||||||
// Archiving should contain a bitcode blob, but not building.
|
|
||||||
// This mimics Xcode behavior and prevents a developer from having to install a
|
|
||||||
// 300+MB app.
|
|
||||||
final File outputFlutterFrameworkBinary = outputFlutterFramework
|
|
||||||
.childDirectory('Versions')
|
|
||||||
.childDirectory('A')
|
|
||||||
.childFile('FlutterMacOS');
|
|
||||||
expect(
|
|
||||||
containsBitcode(outputFlutterFrameworkBinary.path, processManager),
|
|
||||||
isFalse,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Build again without cleaning.
|
// Build again without cleaning.
|
||||||
final ProcessResult secondBuild = processManager.runSync(buildCommand, workingDirectory: workingDirectory);
|
final ProcessResult secondBuild = processManager.runSync(buildCommand, workingDirectory: workingDirectory);
|
||||||
|
|
||||||
|
@ -1,51 +0,0 @@
|
|||||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
import 'dart:convert';
|
|
||||||
|
|
||||||
import 'package:flutter_tools/src/base/io.dart';
|
|
||||||
import 'package:process/process.dart';
|
|
||||||
|
|
||||||
bool containsBitcode(String pathToBinary, ProcessManager processManager) {
|
|
||||||
// See: https://stackoverflow.com/questions/32755775/how-to-check-a-static-library-is-built-contain-bitcode
|
|
||||||
final ProcessResult result = processManager.runSync(<String>[
|
|
||||||
'otool',
|
|
||||||
'-l',
|
|
||||||
'-arch',
|
|
||||||
'arm64',
|
|
||||||
pathToBinary,
|
|
||||||
]);
|
|
||||||
final String loadCommands = result.stdout as String;
|
|
||||||
if (!loadCommands.contains('__LLVM')) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Presence of the section may mean a bitcode marker was embedded (size=1), but there is no content.
|
|
||||||
if (!loadCommands.contains('size 0x0000000000000001')) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// Check the false positives: size=1 wasn't referencing the __LLVM section.
|
|
||||||
|
|
||||||
bool emptyBitcodeMarkerFound = false;
|
|
||||||
// Section
|
|
||||||
// sectname __bundle
|
|
||||||
// segname __LLVM
|
|
||||||
// addr 0x003c4000
|
|
||||||
// size 0x0042b633
|
|
||||||
// offset 3932160
|
|
||||||
// ...
|
|
||||||
final List<String> lines = LineSplitter.split(loadCommands).toList();
|
|
||||||
lines.asMap().forEach((int index, String line) {
|
|
||||||
if (line.contains('segname __LLVM') && lines.length - index - 1 > 3) {
|
|
||||||
final bool bitcodeMarkerFound = lines
|
|
||||||
.skip(index - 1)
|
|
||||||
.take(4)
|
|
||||||
.any((String line) => line.contains(' size 0x0000000000000001'));
|
|
||||||
if (bitcodeMarkerFound) {
|
|
||||||
emptyBitcodeMarkerFound = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return !emptyBitcodeMarkerFound;
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user