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 _checkBitcode(appFrameworkPath, mode);
|
||||
|
||||
final String aotSymbols = await _dylibSymbols(appFrameworkPath);
|
||||
|
||||
@ -228,15 +227,14 @@ Future<void> _testBuildIosFramework(Directory projectDir, { bool isModule = fals
|
||||
section("Check all modes' engine dylib");
|
||||
|
||||
for (final String mode in <String>['Debug', 'Profile', 'Release']) {
|
||||
final String engineBinary = path.join(
|
||||
checkFileExists(path.join(
|
||||
outputPath,
|
||||
mode,
|
||||
'Flutter.xcframework',
|
||||
'ios-arm64',
|
||||
'Flutter.framework',
|
||||
'Flutter',
|
||||
);
|
||||
await _checkBitcode(engineBinary, mode);
|
||||
));
|
||||
|
||||
checkFileExists(path.join(
|
||||
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) {
|
||||
return eval('nm', <String>[
|
||||
'-g',
|
||||
|
@ -47,43 +47,6 @@ Future<String?> minPhoneOSVersion(String pathToBinary) async {
|
||||
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
|
||||
/// `testFunction`.
|
||||
///
|
||||
|
@ -65,6 +65,9 @@ def flutter_additional_ios_build_settings(target)
|
||||
# Skip other updates if it's not a Flutter plugin (transitive dependency).
|
||||
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).
|
||||
configuration_engine_dir = build_configuration.type == :debug ? debug_framework_dir : release_framework_dir
|
||||
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>[];
|
||||
|
||||
if (verbose) {
|
||||
@ -365,7 +360,6 @@ class Context {
|
||||
'-dTreeShakeIcons=${environment['TREE_SHAKE_ICONS'] ?? ''}',
|
||||
'-dTrackWidgetCreation=${environment['TRACK_WIDGET_CREATION'] ?? ''}',
|
||||
'-dDartObfuscation=${environment['DART_OBFUSCATION'] ?? ''}',
|
||||
'-dEnableBitcode=$bitcodeFlag',
|
||||
'-dAction=${environment['ACTION'] ?? ''}',
|
||||
'--ExtraGenSnapshotOptions=${environment['EXTRA_GEN_SNAPSHOT_OPTIONS'] ?? ''}',
|
||||
'--DartDefines=${environment['DART_DEFINES'] ?? ''}',
|
||||
|
@ -116,16 +116,11 @@ class AOTSnapshotter {
|
||||
DarwinArch? darwinArch,
|
||||
String? sdkRoot,
|
||||
List<String> extraGenSnapshotOptions = const <String>[],
|
||||
required bool bitcode,
|
||||
String? splitDebugInfo,
|
||||
required bool dartObfuscation,
|
||||
bool quiet = false,
|
||||
}) async {
|
||||
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)) {
|
||||
_logger.printError('${getNameForTargetPlatform(platform)} does not support AOT compilation.');
|
||||
@ -244,7 +239,6 @@ class AOTSnapshotter {
|
||||
sdkRoot: sdkRoot,
|
||||
assemblyPath: assembly,
|
||||
outputPath: outputDir.path,
|
||||
bitcode: bitcode,
|
||||
quiet: quiet,
|
||||
stripAfterBuild: stripAfterBuild,
|
||||
extractAppleDebugSymbols: extractAppleDebugSymbols
|
||||
@ -262,7 +256,6 @@ class AOTSnapshotter {
|
||||
String? sdkRoot,
|
||||
required String assemblyPath,
|
||||
required String outputPath,
|
||||
required bool bitcode,
|
||||
required bool quiet,
|
||||
required bool stripAfterBuild,
|
||||
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 RunResult compileResult = await _xcode.cc(<String>[
|
||||
...commonBuildOptions,
|
||||
if (bitcode) embedBitcodeArg,
|
||||
'-c',
|
||||
assemblyPath,
|
||||
'-o',
|
||||
@ -311,7 +302,6 @@ class AOTSnapshotter {
|
||||
'-Xlinker', '-rpath', '-Xlinker', '@executable_path/Frameworks',
|
||||
'-Xlinker', '-rpath', '-Xlinker', '@loader_path/Frameworks',
|
||||
'-install_name', '@rpath/App.framework/App',
|
||||
if (bitcode) embedBitcodeArg,
|
||||
'-o', appLib,
|
||||
assemblyO,
|
||||
];
|
||||
|
@ -942,9 +942,6 @@ const String kTargetPlatform = 'TargetPlatform';
|
||||
/// The define to control what target file is used.
|
||||
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.
|
||||
const String kTrackWidgetCreation = 'TrackWidgetCreation';
|
||||
|
||||
|
@ -250,7 +250,6 @@ class AndroidAot extends AotElfBase {
|
||||
buildMode: buildMode,
|
||||
mainPath: environment.buildDir.childFile('app.dill').path,
|
||||
outputPath: output.path,
|
||||
bitcode: false,
|
||||
extraGenSnapshotOptions: extraGenSnapshotOptions,
|
||||
splitDebugInfo: splitDebugInfo,
|
||||
dartObfuscation: dartObfuscation,
|
||||
|
@ -296,7 +296,6 @@ abstract class AotElfBase extends Target {
|
||||
buildMode: buildMode,
|
||||
mainPath: environment.buildDir.childFile('app.dill').path,
|
||||
outputPath: outputPath,
|
||||
bitcode: false,
|
||||
extraGenSnapshotOptions: extraGenSnapshotOptions,
|
||||
splitDebugInfo: splitDebugInfo,
|
||||
dartObfuscation: dartObfuscation,
|
||||
|
@ -56,7 +56,6 @@ abstract class AotAssemblyBase extends Target {
|
||||
}
|
||||
|
||||
final List<String> extraGenSnapshotOptions = decodeCommaSeparated(environment.defines, kExtraGenSnapshotOptions);
|
||||
final bool bitcode = environment.defines[kBitcodeFlag] == 'true';
|
||||
final BuildMode buildMode = getBuildModeForName(environmentBuildMode);
|
||||
final TargetPlatform targetPlatform = getTargetPlatformForName(environmentTargetPlatform);
|
||||
final String? splitDebugInfo = environment.defines[kSplitDebugInfo];
|
||||
@ -101,7 +100,6 @@ abstract class AotAssemblyBase extends Target {
|
||||
outputPath: environment.fileSystem.path.join(buildOutputPath, getNameForDarwinArch(darwinArch)),
|
||||
darwinArch: darwinArch,
|
||||
sdkRoot: sdkRoot,
|
||||
bitcode: bitcode,
|
||||
quiet: true,
|
||||
splitDebugInfo: splitDebugInfo,
|
||||
dartObfuscation: dartObfuscation,
|
||||
@ -287,9 +285,6 @@ abstract class UnpackIOS extends Target {
|
||||
if (archs == null) {
|
||||
throw MissingDefineException(kIosArchs, name);
|
||||
}
|
||||
if (environment.defines[kBitcodeFlag] == null) {
|
||||
throw MissingDefineException(kBitcodeFlag, name);
|
||||
}
|
||||
_copyFramework(environment, sdkRoot);
|
||||
|
||||
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');
|
||||
}
|
||||
_thinFramework(environment, frameworkBinaryPath, archs);
|
||||
_bitcodeStripFramework(environment, frameworkBinaryPath);
|
||||
if (buildMode == BuildMode.release) {
|
||||
_bitcodeStripFramework(environment, frameworkBinaryPath);
|
||||
}
|
||||
_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) {
|
||||
if (environment.defines[kBitcodeFlag] == 'true') {
|
||||
return;
|
||||
}
|
||||
final ProcessResult stripResult = environment.processManager.runSync(<String>[
|
||||
'xcrun',
|
||||
'bitcode_strip',
|
||||
frameworkBinaryPath,
|
||||
'-m', // leave the bitcode marker.
|
||||
'-r', // Delete the bitcode segment.
|
||||
'-o',
|
||||
frameworkBinaryPath,
|
||||
]);
|
||||
@ -669,7 +664,6 @@ Future<void> _createStubAppFramework(File outputFile, Environment environment,
|
||||
for (String arch in iosArchNames ?? <String>{}) ...<String>['-arch', arch],
|
||||
stubSource.path,
|
||||
'-dynamiclib',
|
||||
'-fembed-bitcode-marker',
|
||||
// Keep version in sync with AOTSnapshotter flag
|
||||
if (environmentType == EnvironmentType.physical)
|
||||
'-miphoneos-version-min=11.0'
|
||||
|
@ -285,7 +285,6 @@ class CompileMacOSFramework extends Target {
|
||||
}
|
||||
|
||||
pending.add(snapshotter.build(
|
||||
bitcode: false,
|
||||
buildMode: buildMode,
|
||||
mainPath: environment.buildDir.childFile('app.dill').path,
|
||||
outputPath: environment.fileSystem.path.join(buildOutputPath, getNameForDarwinArch(darwinArch)),
|
||||
|
@ -238,25 +238,12 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand {
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>method</key>
|
||||
''');
|
||||
|
||||
plistContents.write('''
|
||||
<string>${stringArgDeprecated('export-method')}</string>
|
||||
''');
|
||||
if (xcodeBuildResult?.xcodeBuildExecution?.buildSettings['ENABLE_BITCODE'] != 'YES') {
|
||||
// Bitcode is off by default in Flutter iOS apps.
|
||||
plistContents.write('''
|
||||
<key>uploadBitcode</key>
|
||||
<key>uploadBitcode</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
''');
|
||||
} else {
|
||||
plistContents.write('''
|
||||
</dict>
|
||||
</plist>
|
||||
''');
|
||||
}
|
||||
|
||||
final File tempPlist = globals.fs.systemTempDirectory
|
||||
.createTempSync('flutter_build_ios.').childFile('ExportOptions.plist');
|
||||
|
@ -152,7 +152,7 @@ abstract class BuildFrameworkCommand extends BuildSubCommand {
|
||||
...framework.parent
|
||||
.listSync()
|
||||
.where((FileSystemEntity entity) =>
|
||||
entity.basename.endsWith('bcsymbolmap') || entity.basename.endsWith('dSYM'))
|
||||
entity.basename.endsWith('dSYM'))
|
||||
.map((FileSystemEntity entity) => <String>['-debug-symbols', entity.path])
|
||||
.expand<String>((List<String> parameter) => parameter),
|
||||
],
|
||||
@ -421,7 +421,6 @@ end
|
||||
defines: <String, String>{
|
||||
kTargetFile: targetFile,
|
||||
kTargetPlatform: getNameForTargetPlatform(TargetPlatform.ios),
|
||||
kBitcodeFlag: 'true',
|
||||
kIosArchs: defaultIOSArchsForEnvironment(sdkType, globals.artifacts!)
|
||||
.map(getNameForDarwinArch)
|
||||
.join(' '),
|
||||
@ -480,9 +479,6 @@ end
|
||||
' ├─Building plugins...'
|
||||
);
|
||||
try {
|
||||
final String bitcodeGenerationMode = mode == BuildMode.release ?
|
||||
'bitcode' : 'marker'; // In release, force bitcode embedding without archiving.
|
||||
|
||||
List<String> pluginsBuildCommand = <String>[
|
||||
...globals.xcode!.xcrunCommand(),
|
||||
'xcodebuild',
|
||||
@ -492,7 +488,6 @@ end
|
||||
'-configuration',
|
||||
xcodeBuildConfiguration,
|
||||
'SYMROOT=${iPhoneBuildOutput.path}',
|
||||
'BITCODE_GENERATION_MODE=$bitcodeGenerationMode',
|
||||
'ONLY_ACTIVE_ARCH=NO', // No device targeted, so build all valid architectures.
|
||||
'BUILD_LIBRARY_FOR_DISTRIBUTION=YES',
|
||||
if (boolArg('static') ?? false)
|
||||
@ -519,7 +514,6 @@ end
|
||||
'-configuration',
|
||||
simulatorConfiguration,
|
||||
'SYMROOT=${simulatorBuildOutput.path}',
|
||||
'ENABLE_BITCODE=YES', // Support host apps with bitcode enabled.
|
||||
'ONLY_ACTIVE_ARCH=NO', // No device targeted, so build all valid architectures.
|
||||
'BUILD_LIBRARY_FOR_DISTRIBUTION=YES',
|
||||
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 {
|
||||
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 Directory frameworkA = parentA.childDirectory('FrameworkA.framework')..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 Directory frameworkB = parentB.childDirectory('FrameworkB.framework')..createSync();
|
||||
final Directory output = fileSystem.directory('output');
|
||||
@ -557,14 +555,10 @@ void main() {
|
||||
'-framework',
|
||||
frameworkA.path,
|
||||
'-debug-symbols',
|
||||
bcsymbolmapA.path,
|
||||
'-debug-symbols',
|
||||
dSYMA.path,
|
||||
'-framework',
|
||||
frameworkB.path,
|
||||
'-debug-symbols',
|
||||
bcsymbolmapB.path,
|
||||
'-debug-symbols',
|
||||
dSYMB.path,
|
||||
'-output',
|
||||
output.childDirectory('Combine.xcframework').path,
|
||||
|
@ -444,42 +444,6 @@ void main() {
|
||||
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 {
|
||||
final BuildCommand command = BuildCommand();
|
||||
fakeProcessManager.addCommands(<FakeCommand>[
|
||||
|
@ -165,7 +165,6 @@ void main() {
|
||||
buildMode: BuildMode.debug,
|
||||
mainPath: 'main.dill',
|
||||
outputPath: outputPath,
|
||||
bitcode: false,
|
||||
dartObfuscation: false,
|
||||
), isNot(equals(0)));
|
||||
});
|
||||
@ -178,7 +177,6 @@ void main() {
|
||||
buildMode: BuildMode.debug,
|
||||
mainPath: 'main.dill',
|
||||
outputPath: outputPath,
|
||||
bitcode: false,
|
||||
dartObfuscation: false,
|
||||
), isNot(0));
|
||||
});
|
||||
@ -191,99 +189,10 @@ void main() {
|
||||
buildMode: BuildMode.debug,
|
||||
mainPath: 'main.dill',
|
||||
outputPath: outputPath,
|
||||
bitcode: false,
|
||||
dartObfuscation: false,
|
||||
), 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 {
|
||||
final String outputPath = fileSystem.path.join('build', 'foo');
|
||||
final String assembly = fileSystem.path.join(outputPath, 'snapshot_assembly.S');
|
||||
@ -349,7 +258,6 @@ void main() {
|
||||
outputPath: outputPath,
|
||||
darwinArch: DarwinArch.arm64,
|
||||
sdkRoot: 'path/to/sdk',
|
||||
bitcode: false,
|
||||
splitDebugInfo: 'foo',
|
||||
dartObfuscation: false,
|
||||
);
|
||||
@ -421,7 +329,6 @@ void main() {
|
||||
outputPath: outputPath,
|
||||
darwinArch: DarwinArch.arm64,
|
||||
sdkRoot: 'path/to/sdk',
|
||||
bitcode: false,
|
||||
dartObfuscation: true,
|
||||
);
|
||||
|
||||
@ -490,7 +397,6 @@ void main() {
|
||||
outputPath: outputPath,
|
||||
darwinArch: DarwinArch.arm64,
|
||||
sdkRoot: 'path/to/sdk',
|
||||
bitcode: false,
|
||||
dartObfuscation: false,
|
||||
);
|
||||
|
||||
@ -518,7 +424,6 @@ void main() {
|
||||
buildMode: BuildMode.release,
|
||||
mainPath: 'main.dill',
|
||||
outputPath: outputPath,
|
||||
bitcode: false,
|
||||
dartObfuscation: false,
|
||||
);
|
||||
|
||||
@ -549,7 +454,6 @@ void main() {
|
||||
buildMode: BuildMode.release,
|
||||
mainPath: 'main.dill',
|
||||
outputPath: outputPath,
|
||||
bitcode: false,
|
||||
splitDebugInfo: 'foo',
|
||||
dartObfuscation: false,
|
||||
);
|
||||
@ -579,7 +483,6 @@ void main() {
|
||||
buildMode: BuildMode.release,
|
||||
mainPath: 'main.dill',
|
||||
outputPath: outputPath,
|
||||
bitcode: false,
|
||||
dartObfuscation: true,
|
||||
);
|
||||
|
||||
@ -607,7 +510,6 @@ void main() {
|
||||
buildMode: BuildMode.release,
|
||||
mainPath: 'main.dill',
|
||||
outputPath: outputPath,
|
||||
bitcode: false,
|
||||
splitDebugInfo: '',
|
||||
dartObfuscation: false,
|
||||
);
|
||||
@ -634,7 +536,6 @@ void main() {
|
||||
buildMode: BuildMode.release,
|
||||
mainPath: 'main.dill',
|
||||
outputPath: outputPath,
|
||||
bitcode: false,
|
||||
dartObfuscation: false,
|
||||
);
|
||||
|
||||
@ -659,7 +560,6 @@ void main() {
|
||||
buildMode: BuildMode.release,
|
||||
mainPath: 'main.dill',
|
||||
outputPath: outputPath,
|
||||
bitcode: false,
|
||||
dartObfuscation: false,
|
||||
extraGenSnapshotOptions: const <String>['--no-strip'],
|
||||
);
|
||||
|
@ -465,98 +465,10 @@ void main() {
|
||||
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 {
|
||||
iosEnvironment.defines[kCodeSizeDirectory] = 'code_size_1';
|
||||
iosEnvironment.defines[kIosArchs] = 'arm64';
|
||||
iosEnvironment.defines[kSdkRoot] = 'path/to/iPhoneOS.sdk';
|
||||
iosEnvironment.defines[kBitcodeFlag] = 'true';
|
||||
final String build = iosEnvironment.buildDir.path;
|
||||
processManager.addCommands(<FakeCommand>[
|
||||
FakeCommand(command: <String>[
|
||||
@ -577,8 +489,6 @@ void main() {
|
||||
'-miphoneos-version-min=11.0',
|
||||
'-isysroot',
|
||||
'path/to/iPhoneOS.sdk',
|
||||
// Contains bitcode flag.
|
||||
'-fembed-bitcode',
|
||||
'-c',
|
||||
'$build/arm64/snapshot_assembly.S',
|
||||
'-o',
|
||||
@ -603,8 +513,6 @@ void main() {
|
||||
'@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',
|
||||
|
@ -22,7 +22,6 @@ final Platform macPlatform = FakePlatform(operatingSystem: 'macos', environment:
|
||||
|
||||
const List<String> _kSharedConfig = <String>[
|
||||
'-dynamiclib',
|
||||
'-fembed-bitcode-marker',
|
||||
'-miphoneos-version-min=11.0',
|
||||
'-Xlinker',
|
||||
'-rpath',
|
||||
@ -87,7 +86,6 @@ void main() {
|
||||
fileSystem.path.absolute(fileSystem.path.join(
|
||||
'.tmp_rand0', 'flutter_tools_stub_source.rand0', 'debug_app.cc')),
|
||||
'-dynamiclib',
|
||||
'-fembed-bitcode-marker',
|
||||
'-miphonesimulator-version-min=11.0',
|
||||
'-Xlinker',
|
||||
'-rpath',
|
||||
@ -393,7 +391,6 @@ void main() {
|
||||
late FakeCommand copyPhysicalFrameworkCommand;
|
||||
late FakeCommand lipoCommandNonFatResult;
|
||||
late FakeCommand lipoVerifyArm64Command;
|
||||
late FakeCommand bitcodeStripCommand;
|
||||
late FakeCommand adHocCodesignCommand;
|
||||
|
||||
setUp(() {
|
||||
@ -423,15 +420,6 @@ void main() {
|
||||
'arm64',
|
||||
]);
|
||||
|
||||
bitcodeStripCommand = FakeCommand(command: <String>[
|
||||
'xcrun',
|
||||
'bitcode_strip',
|
||||
binary.path,
|
||||
'-m',
|
||||
'-o',
|
||||
binary.path,
|
||||
]);
|
||||
|
||||
adHocCodesignCommand = FakeCommand(command: <String>[
|
||||
'codesign',
|
||||
'--force',
|
||||
@ -453,7 +441,6 @@ void main() {
|
||||
defines: <String, String>{
|
||||
kIosArchs: 'x86_64',
|
||||
kSdkRoot: 'path/to/iPhoneSimulator.sdk',
|
||||
kBitcodeFlag: 'true',
|
||||
},
|
||||
);
|
||||
|
||||
@ -495,7 +482,6 @@ void main() {
|
||||
defines: <String, String>{
|
||||
kIosArchs: 'arm64',
|
||||
kSdkRoot: 'path/to/iPhoneOS.sdk',
|
||||
kBitcodeFlag: '',
|
||||
},
|
||||
);
|
||||
processManager.addCommand(copyPhysicalFrameworkCommand);
|
||||
@ -521,7 +507,6 @@ void main() {
|
||||
defines: <String, String>{
|
||||
kIosArchs: 'arm64 armv7',
|
||||
kSdkRoot: 'path/to/iPhoneOS.sdk',
|
||||
kBitcodeFlag: '',
|
||||
},
|
||||
);
|
||||
|
||||
@ -564,7 +549,6 @@ void main() {
|
||||
defines: <String, String>{
|
||||
kIosArchs: 'arm64 armv7',
|
||||
kSdkRoot: 'path/to/iPhoneOS.sdk',
|
||||
kBitcodeFlag: '',
|
||||
},
|
||||
);
|
||||
|
||||
@ -618,7 +602,6 @@ void main() {
|
||||
defines: <String, String>{
|
||||
kIosArchs: 'arm64',
|
||||
kSdkRoot: 'path/to/iPhoneOS.sdk',
|
||||
kBitcodeFlag: 'true',
|
||||
},
|
||||
);
|
||||
|
||||
@ -648,7 +631,6 @@ void main() {
|
||||
defines: <String, String>{
|
||||
kIosArchs: 'arm64 armv7',
|
||||
kSdkRoot: 'path/to/iPhoneOS.sdk',
|
||||
kBitcodeFlag: 'true',
|
||||
},
|
||||
);
|
||||
|
||||
@ -696,26 +678,33 @@ void main() {
|
||||
defines: <String, String>{
|
||||
kIosArchs: 'arm64',
|
||||
kSdkRoot: 'path/to/iPhoneOS.sdk',
|
||||
kBitcodeFlag: '',
|
||||
},
|
||||
);
|
||||
|
||||
processManager.addCommands(<FakeCommand>[
|
||||
copyPhysicalFrameworkCommand,
|
||||
FakeCommand(command: <String>[
|
||||
'rsync',
|
||||
'-av',
|
||||
'--delete',
|
||||
'--filter',
|
||||
'- .DS_Store/',
|
||||
'Artifact.flutterFramework.TargetPlatform.ios.release.EnvironmentType.physical',
|
||||
outputDir.path,
|
||||
]),
|
||||
lipoCommandNonFatResult,
|
||||
lipoVerifyArm64Command,
|
||||
FakeCommand(command: <String>[
|
||||
'xcrun',
|
||||
'bitcode_strip',
|
||||
binary.path,
|
||||
'-m',
|
||||
'-r',
|
||||
'-o',
|
||||
binary.path,
|
||||
], exitCode: 1, stderr: 'bitcode_strip error'),
|
||||
]);
|
||||
|
||||
await expectLater(
|
||||
const DebugUnpackIOS().build(environment),
|
||||
const ReleaseUnpackIOS().build(environment),
|
||||
throwsA(isException.having(
|
||||
(Exception exception) => exception.toString(),
|
||||
'description',
|
||||
@ -739,7 +728,6 @@ void main() {
|
||||
defines: <String, String>{
|
||||
kIosArchs: 'arm64',
|
||||
kSdkRoot: 'path/to/iPhoneOS.sdk',
|
||||
kBitcodeFlag: '',
|
||||
},
|
||||
);
|
||||
|
||||
@ -747,7 +735,6 @@ void main() {
|
||||
copyPhysicalFrameworkCommand,
|
||||
lipoCommandNonFatResult,
|
||||
lipoVerifyArm64Command,
|
||||
bitcodeStripCommand,
|
||||
adHocCodesignCommand,
|
||||
]);
|
||||
await const DebugUnpackIOS().build(environment);
|
||||
@ -768,7 +755,6 @@ void main() {
|
||||
defines: <String, String>{
|
||||
kIosArchs: 'arm64',
|
||||
kSdkRoot: 'path/to/iPhoneOS.sdk',
|
||||
kBitcodeFlag: '',
|
||||
kCodesignIdentity: 'ABC123',
|
||||
},
|
||||
);
|
||||
@ -777,7 +763,6 @@ void main() {
|
||||
copyPhysicalFrameworkCommand,
|
||||
lipoCommandNonFatResult,
|
||||
lipoVerifyArm64Command,
|
||||
bitcodeStripCommand,
|
||||
FakeCommand(command: <String>[
|
||||
'codesign',
|
||||
'--force',
|
||||
@ -813,7 +798,6 @@ void main() {
|
||||
defines: <String, String>{
|
||||
kIosArchs: 'arm64',
|
||||
kSdkRoot: 'path/to/iPhoneOS.sdk',
|
||||
kBitcodeFlag: '',
|
||||
kCodesignIdentity: 'ABC123',
|
||||
},
|
||||
);
|
||||
@ -822,7 +806,6 @@ void main() {
|
||||
copyPhysicalFrameworkCommand,
|
||||
lipoCommandNonFatResult,
|
||||
lipoVerifyArm64Command,
|
||||
bitcodeStripCommand,
|
||||
FakeCommand(command: <String>[
|
||||
'codesign',
|
||||
'--force',
|
||||
|
@ -31,7 +31,6 @@ void main() {
|
||||
<String, String>{
|
||||
'ACTION': 'build',
|
||||
'BUILT_PRODUCTS_DIR': buildDir.path,
|
||||
'ENABLE_BITCODE': 'YES',
|
||||
'FLUTTER_ROOT': flutterRoot.path,
|
||||
'INFOPLIST_PATH': 'Info.plist',
|
||||
},
|
||||
@ -51,7 +50,6 @@ void main() {
|
||||
'-dTreeShakeIcons=',
|
||||
'-dTrackWidgetCreation=',
|
||||
'-dDartObfuscation=',
|
||||
'-dEnableBitcode=',
|
||||
'-dAction=build',
|
||||
'--ExtraGenSnapshotOptions=',
|
||||
'--DartDefines=',
|
||||
@ -85,7 +83,6 @@ void main() {
|
||||
<String, String>{
|
||||
'BUILT_PRODUCTS_DIR': buildDir.path,
|
||||
'CONFIGURATION': buildMode,
|
||||
'ENABLE_BITCODE': 'YES',
|
||||
'FLUTTER_ROOT': flutterRoot.path,
|
||||
'INFOPLIST_PATH': 'Info.plist',
|
||||
},
|
||||
@ -105,7 +102,6 @@ void main() {
|
||||
'-dTreeShakeIcons=',
|
||||
'-dTrackWidgetCreation=',
|
||||
'-dDartObfuscation=',
|
||||
'-dEnableBitcode=',
|
||||
'-dAction=',
|
||||
'--ExtraGenSnapshotOptions=',
|
||||
'--DartDefines=',
|
||||
@ -154,7 +150,6 @@ void main() {
|
||||
'CONFIGURATION': buildMode,
|
||||
'DART_DEFINES': dartDefines,
|
||||
'DART_OBFUSCATION': dartObfuscation,
|
||||
'ENABLE_BITCODE': 'YES',
|
||||
'EXPANDED_CODE_SIGN_IDENTITY': expandedCodeSignIdentity,
|
||||
'EXTRA_FRONT_END_OPTIONS': extraFrontEndOptions,
|
||||
'EXTRA_GEN_SNAPSHOT_OPTIONS': extraGenSnapshotOptions,
|
||||
@ -181,7 +176,6 @@ void main() {
|
||||
'-dTreeShakeIcons=$treeShake',
|
||||
'-dTrackWidgetCreation=$trackWidgetCreation',
|
||||
'-dDartObfuscation=$dartObfuscation',
|
||||
'-dEnableBitcode=true',
|
||||
'-dAction=install',
|
||||
'--ExtraGenSnapshotOptions=$extraGenSnapshotOptions',
|
||||
'--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/utils.dart';
|
||||
import 'package:flutter_tools/src/build_info.dart';
|
||||
import 'package:flutter_tools/src/convert.dart';
|
||||
|
||||
import '../integration.shard/test_utils.dart';
|
||||
import '../src/common.dart';
|
||||
import '../src/darwin_common.dart';
|
||||
import '../src/fake_process_manager.dart';
|
||||
|
||||
void main() {
|
||||
group('iOS app validation', () {
|
||||
@ -152,10 +153,8 @@ void main() {
|
||||
|
||||
expect(vmSnapshot.existsSync(), buildMode == BuildMode.debug);
|
||||
|
||||
// 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.
|
||||
expect(containsBitcode(outputFlutterFrameworkBinary.path, processManager), isFalse);
|
||||
// Builds should not contain deprecated bitcode.
|
||||
expect(_containsBitcode(outputFlutterFrameworkBinary.path, processManager), isFalse);
|
||||
});
|
||||
|
||||
testWithoutContext('Info.plist dart observatory Bonjour service', () {
|
||||
@ -358,3 +357,46 @@ void main() {
|
||||
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 '../src/common.dart';
|
||||
import '../src/darwin_common.dart';
|
||||
|
||||
void main() {
|
||||
final String flutterBin = fileSystem.path.join(
|
||||
@ -150,18 +149,6 @@ void main() {
|
||||
expect(outputFlutterFramework.childLink('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.
|
||||
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