diff --git a/dev/devicelab/bin/tasks/build_ios_framework_module_test.dart b/dev/devicelab/bin/tasks/build_ios_framework_module_test.dart index 706ae3fd511..1607113b205 100644 --- a/dev/devicelab/bin/tasks/build_ios_framework_module_test.dart +++ b/dev/devicelab/bin/tasks/build_ios_framework_module_test.dart @@ -171,7 +171,6 @@ Future _testBuildIosFramework(Directory projectDir, { bool isModule = fals ); await _checkDylib(appFrameworkPath); - await _checkBitcode(appFrameworkPath, mode); final String aotSymbols = await _dylibSymbols(appFrameworkPath); @@ -228,15 +227,14 @@ Future _testBuildIosFramework(Directory projectDir, { bool isModule = fals section("Check all modes' engine dylib"); for (final String mode in ['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 _checkStatic(String pathToLibrary) async { } } -Future _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 _dylibSymbols(String pathToDylib) { return eval('nm', [ '-g', diff --git a/dev/devicelab/lib/framework/ios.dart b/dev/devicelab/lib/framework/ios.dart index dca47df98bb..90d1d1e897c 100644 --- a/dev/devicelab/lib/framework/ios.dart +++ b/dev/devicelab/lib/framework/ios.dart @@ -47,43 +47,6 @@ Future minPhoneOSVersion(String pathToBinary) async { return minVersion; } -Future 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', [ - '-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 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`. /// diff --git a/packages/flutter_tools/bin/podhelper.rb b/packages/flutter_tools/bin/podhelper.rb index 1bd5112a756..35f7cfd69bb 100644 --- a/packages/flutter_tools/bin/podhelper.rb +++ b/packages/flutter_tools/bin/podhelper.rb @@ -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| diff --git a/packages/flutter_tools/bin/xcode_backend.dart b/packages/flutter_tools/bin/xcode_backend.dart index 0f9de8c8e72..0d81840df95 100644 --- a/packages/flutter_tools/bin/xcode_backend.dart +++ b/packages/flutter_tools/bin/xcode_backend.dart @@ -333,11 +333,6 @@ class Context { ); } - String bitcodeFlag = ''; - if (environment['ENABLE_BITCODE'] == 'YES' && environment['ACTION'] == 'install') { - bitcodeFlag = 'true'; - } - final List flutterArgs = []; 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'] ?? ''}', diff --git a/packages/flutter_tools/lib/src/base/build.dart b/packages/flutter_tools/lib/src/base/build.dart index 037c8f1dbc2..105e435c043 100644 --- a/packages/flutter_tools/lib/src/base/build.dart +++ b/packages/flutter_tools/lib/src/base/build.dart @@ -116,16 +116,11 @@ class AOTSnapshotter { DarwinArch? darwinArch, String? sdkRoot, List extraGenSnapshotOptions = const [], - 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([ ...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, ]; diff --git a/packages/flutter_tools/lib/src/build_info.dart b/packages/flutter_tools/lib/src/build_info.dart index 7fcfe4483f5..8af32e1db5a 100644 --- a/packages/flutter_tools/lib/src/build_info.dart +++ b/packages/flutter_tools/lib/src/build_info.dart @@ -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'; diff --git a/packages/flutter_tools/lib/src/build_system/targets/android.dart b/packages/flutter_tools/lib/src/build_system/targets/android.dart index aa60e47a8a5..6ff4cc0bc26 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/android.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/android.dart @@ -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, diff --git a/packages/flutter_tools/lib/src/build_system/targets/common.dart b/packages/flutter_tools/lib/src/build_system/targets/common.dart index 753fe683e5b..91a39e6c20c 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/common.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/common.dart @@ -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, diff --git a/packages/flutter_tools/lib/src/build_system/targets/ios.dart b/packages/flutter_tools/lib/src/build_system/targets/ios.dart index 2bcb7668cd5..644d48aff06 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/ios.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/ios.dart @@ -56,7 +56,6 @@ abstract class AotAssemblyBase extends Target { } final List 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([ 'xcrun', 'bitcode_strip', frameworkBinaryPath, - '-m', // leave the bitcode marker. + '-r', // Delete the bitcode segment. '-o', frameworkBinaryPath, ]); @@ -669,7 +664,6 @@ Future _createStubAppFramework(File outputFile, Environment environment, for (String arch in iosArchNames ?? {}) ...['-arch', arch], stubSource.path, '-dynamiclib', - '-fembed-bitcode-marker', // Keep version in sync with AOTSnapshotter flag if (environmentType == EnvironmentType.physical) '-miphoneos-version-min=11.0' diff --git a/packages/flutter_tools/lib/src/build_system/targets/macos.dart b/packages/flutter_tools/lib/src/build_system/targets/macos.dart index e88f883242d..a107f2f8347 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/macos.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/macos.dart @@ -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)), diff --git a/packages/flutter_tools/lib/src/commands/build_ios.dart b/packages/flutter_tools/lib/src/commands/build_ios.dart index 967990759c4..250188dceed 100644 --- a/packages/flutter_tools/lib/src/commands/build_ios.dart +++ b/packages/flutter_tools/lib/src/commands/build_ios.dart @@ -238,25 +238,12 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand { method -'''); - - plistContents.write(''' ${stringArgDeprecated('export-method')} - '''); - if (xcodeBuildResult?.xcodeBuildExecution?.buildSettings['ENABLE_BITCODE'] != 'YES') { - // Bitcode is off by default in Flutter iOS apps. - plistContents.write(''' - uploadBitcode + uploadBitcode '''); - } else { - plistContents.write(''' - - -'''); - } final File tempPlist = globals.fs.systemTempDirectory .createTempSync('flutter_build_ios.').childFile('ExportOptions.plist'); diff --git a/packages/flutter_tools/lib/src/commands/build_ios_framework.dart b/packages/flutter_tools/lib/src/commands/build_ios_framework.dart index 75b11e80b33..60e81bb275d 100644 --- a/packages/flutter_tools/lib/src/commands/build_ios_framework.dart +++ b/packages/flutter_tools/lib/src/commands/build_ios_framework.dart @@ -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) => ['-debug-symbols', entity.path]) .expand((List parameter) => parameter), ], @@ -421,7 +421,6 @@ end defines: { 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 pluginsBuildCommand = [ ...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) diff --git a/packages/flutter_tools/lib/src/ios/bitcode.dart b/packages/flutter_tools/lib/src/ios/bitcode.dart deleted file mode 100644 index 1914ee258f8..00000000000 --- a/packages/flutter_tools/lib/src/ios/bitcode.dart +++ /dev/null @@ -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 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(); - - final RunResult? clangResult = await xcode?.clang(['--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; -} diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_darwin_framework_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_darwin_framework_test.dart index b830640caf2..9710fb968ee 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_darwin_framework_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_darwin_framework_test.dart @@ -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, diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_ipa_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_ipa_test.dart index 4599e7f55fc..e82a2b14fc1 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_ipa_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_ipa_test.dart @@ -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([ - xattrCommand, - setUpFakeXcodeBuildHandler(), - exportArchiveCommand(exportOptionsPlist: _exportOptionsPlist, cachePlist: cachedExportOptionsPlist), - ]); - createMinimalMockProjectFiles(); - - await createTestCommandRunner(command).run( - const ['build', 'ipa', '--no-pub',] - ); - - const String expectedIpaPlistContents = ''' - - - - - method - app-store - - -'''; - - final String actualIpaPlistContents = fileSystem.file(cachedExportOptionsPlist).readAsStringSync(); - expect(actualIpaPlistContents, expectedIpaPlistContents); - }, overrides: { - FileSystem: () => fileSystem, - ProcessManager: () => fakeProcessManager, - Platform: () => macosPlatform, - XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings( - overrides: {'ENABLE_BITCODE': 'YES'}, - ), - }); - testUsingContext('ipa build invokes xcode build with verbosity', () async { final BuildCommand command = BuildCommand(); fakeProcessManager.addCommands([ diff --git a/packages/flutter_tools/test/general.shard/base/build_test.dart b/packages/flutter_tools/test/general.shard/base/build_test.dart index 2221dee3b55..80ce4ff4dde 100644 --- a/packages/flutter_tools/test/general.shard/base/build_test.dart +++ b/packages/flutter_tools/test/general.shard/base/build_test.dart @@ -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(command: [ - '${genSnapshotPath}_arm64', - '--deterministic', - '--snapshot_kind=app-aot-assembly', - '--assembly=$assembly', - 'main.dill', - ]), - kWhichSysctlCommand, - kARMCheckCommand, - const FakeCommand(command: [ - '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: [ - '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: [ - 'xcrun', - 'dsymutil', - '-o', - 'build/foo/App.framework.dSYM', - 'build/foo/App.framework/App', - ]), - const FakeCommand(command: [ - '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 ['--no-strip'], ); diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/common_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/common_test.dart index 1ddb400beb3..a6c0e748a85 100644 --- a/packages/flutter_tools/test/general.shard/build_system/targets/common_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/targets/common_test.dart @@ -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(command: [ - // 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: [ - '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: [ - '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: [ - 'xcrun', - 'dsymutil', - '-o', - '$build/arm64/App.framework.dSYM', - '$build/arm64/App.framework/App', - ]), - FakeCommand(command: [ - 'xcrun', - 'strip', - '-x', - '$build/arm64/App.framework/App', - '-o', - '$build/arm64/App.framework/App', - ]), - FakeCommand(command: [ - 'lipo', - '$build/arm64/App.framework/App', - '-create', - '-output', - '$build/App.framework/App', - ]), - ]); - - await const AotAssemblyProfile().build(iosEnvironment); - - expect(processManager, hasNoRemainingExpectations); - }, overrides: { - 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(command: [ @@ -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', diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/ios_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/ios_test.dart index cd2d81a3cad..d84b0d8063b 100644 --- a/packages/flutter_tools/test/general.shard/build_system/targets/ios_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/targets/ios_test.dart @@ -22,7 +22,6 @@ final Platform macPlatform = FakePlatform(operatingSystem: 'macos', environment: const List _kSharedConfig = [ '-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: [ - 'xcrun', - 'bitcode_strip', - binary.path, - '-m', - '-o', - binary.path, - ]); - adHocCodesignCommand = FakeCommand(command: [ 'codesign', '--force', @@ -453,7 +441,6 @@ void main() { defines: { kIosArchs: 'x86_64', kSdkRoot: 'path/to/iPhoneSimulator.sdk', - kBitcodeFlag: 'true', }, ); @@ -495,7 +482,6 @@ void main() { defines: { kIosArchs: 'arm64', kSdkRoot: 'path/to/iPhoneOS.sdk', - kBitcodeFlag: '', }, ); processManager.addCommand(copyPhysicalFrameworkCommand); @@ -521,7 +507,6 @@ void main() { defines: { kIosArchs: 'arm64 armv7', kSdkRoot: 'path/to/iPhoneOS.sdk', - kBitcodeFlag: '', }, ); @@ -564,7 +549,6 @@ void main() { defines: { kIosArchs: 'arm64 armv7', kSdkRoot: 'path/to/iPhoneOS.sdk', - kBitcodeFlag: '', }, ); @@ -618,7 +602,6 @@ void main() { defines: { kIosArchs: 'arm64', kSdkRoot: 'path/to/iPhoneOS.sdk', - kBitcodeFlag: 'true', }, ); @@ -648,7 +631,6 @@ void main() { defines: { kIosArchs: 'arm64 armv7', kSdkRoot: 'path/to/iPhoneOS.sdk', - kBitcodeFlag: 'true', }, ); @@ -696,26 +678,33 @@ void main() { defines: { kIosArchs: 'arm64', kSdkRoot: 'path/to/iPhoneOS.sdk', - kBitcodeFlag: '', }, ); processManager.addCommands([ - copyPhysicalFrameworkCommand, + FakeCommand(command: [ + 'rsync', + '-av', + '--delete', + '--filter', + '- .DS_Store/', + 'Artifact.flutterFramework.TargetPlatform.ios.release.EnvironmentType.physical', + outputDir.path, + ]), lipoCommandNonFatResult, lipoVerifyArm64Command, FakeCommand(command: [ '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: { 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: { kIosArchs: 'arm64', kSdkRoot: 'path/to/iPhoneOS.sdk', - kBitcodeFlag: '', kCodesignIdentity: 'ABC123', }, ); @@ -777,7 +763,6 @@ void main() { copyPhysicalFrameworkCommand, lipoCommandNonFatResult, lipoVerifyArm64Command, - bitcodeStripCommand, FakeCommand(command: [ 'codesign', '--force', @@ -813,7 +798,6 @@ void main() { defines: { kIosArchs: 'arm64', kSdkRoot: 'path/to/iPhoneOS.sdk', - kBitcodeFlag: '', kCodesignIdentity: 'ABC123', }, ); @@ -822,7 +806,6 @@ void main() { copyPhysicalFrameworkCommand, lipoCommandNonFatResult, lipoVerifyArm64Command, - bitcodeStripCommand, FakeCommand(command: [ 'codesign', '--force', diff --git a/packages/flutter_tools/test/general.shard/xcode_backend_test.dart b/packages/flutter_tools/test/general.shard/xcode_backend_test.dart index d746239b304..626db261daa 100644 --- a/packages/flutter_tools/test/general.shard/xcode_backend_test.dart +++ b/packages/flutter_tools/test/general.shard/xcode_backend_test.dart @@ -31,7 +31,6 @@ void main() { { '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() { { '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', diff --git a/packages/flutter_tools/test/host_cross_arch.shard/ios_content_validation_test.dart b/packages/flutter_tools/test/host_cross_arch.shard/ios_content_validation_test.dart index 32fbc4b9c2d..6b0081f72a0 100644 --- a/packages/flutter_tools/test/host_cross_arch.shard/ios_content_validation_test.dart +++ b/packages/flutter_tools/test/host_cross_arch.shard/ios_content_validation_test.dart @@ -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([ + '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 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; +} diff --git a/packages/flutter_tools/test/host_cross_arch.shard/macos_content_validation_test.dart b/packages/flutter_tools/test/host_cross_arch.shard/macos_content_validation_test.dart index db0d5c65d69..cfa61f72dab 100644 --- a/packages/flutter_tools/test/host_cross_arch.shard/macos_content_validation_test.dart +++ b/packages/flutter_tools/test/host_cross_arch.shard/macos_content_validation_test.dart @@ -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); diff --git a/packages/flutter_tools/test/src/darwin_common.dart b/packages/flutter_tools/test/src/darwin_common.dart deleted file mode 100644 index 790d58674bc..00000000000 --- a/packages/flutter_tools/test/src/darwin_common.dart +++ /dev/null @@ -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([ - '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 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; -}