Relax requirements around local engine, build hello_world with bitcode (#39357)
diff --git a/examples/hello_world/ios/Runner.xcodeproj/project.pbxproj b/examples/hello_world/ios/Runner.xcodeproj/project.pbxproj
index df9d159..46c35dd 100644
--- a/examples/hello_world/ios/Runner.xcodeproj/project.pbxproj
+++ b/examples/hello_world/ios/Runner.xcodeproj/project.pbxproj
@@ -317,7 +317,6 @@
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
- ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
@@ -444,7 +443,6 @@
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
- ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
@@ -465,7 +463,6 @@
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
- ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
diff --git a/packages/flutter_tools/bin/xcode_backend.sh b/packages/flutter_tools/bin/xcode_backend.sh
index 876dd75..e49eb2b 100755
--- a/packages/flutter_tools/bin/xcode_backend.sh
+++ b/packages/flutter_tools/bin/xcode_backend.sh
@@ -114,7 +114,6 @@
flutter_engine_flag="--local-engine-src-path=${FLUTTER_ENGINE}"
fi
- local bitcode_flag=""
if [[ -n "$LOCAL_ENGINE" ]]; then
if [[ $(echo "$LOCAL_ENGINE" | tr "[:upper:]" "[:lower:]") != *"$build_mode"* ]]; then
EchoError "========================================================================"
@@ -131,9 +130,12 @@
local_engine_flag="--local-engine=${LOCAL_ENGINE}"
flutter_framework="${FLUTTER_ENGINE}/out/${LOCAL_ENGINE}/Flutter.framework"
flutter_podspec="${FLUTTER_ENGINE}/out/${LOCAL_ENGINE}/Flutter.podspec"
- if [[ $ENABLE_BITCODE == "YES" ]]; then
- bitcode_flag="--bitcode"
- fi
+ fi
+
+ local bitcode_flag=""
+ if [[ $ENABLE_BITCODE == "YES" ]]; then
+ bitcode_flag="--bitcode"
+ echo "Set Bitcode!"
fi
if [[ -e "${project_path}/.ios" ]]; then
diff --git a/packages/flutter_tools/lib/src/base/build.dart b/packages/flutter_tools/lib/src/base/build.dart
index 270c95a..09d46d0 100644
--- a/packages/flutter_tools/lib/src/base/build.dart
+++ b/packages/flutter_tools/lib/src/base/build.dart
@@ -179,13 +179,14 @@
// The DWARF section confuses Xcode tooling, so this strips it. Ideally,
// gen_snapshot would provide an argument to do this automatically.
if (platform == TargetPlatform.ios && bitcode) {
- final IOSink sink = fs.file('$assembly.bitcode').openWrite();
+ final IOSink sink = fs.file('$assembly.stripped.S').openWrite();
for (String line in fs.file(assembly).readAsLinesSync()) {
if (line.startsWith('.section __DWARF')) {
break;
}
sink.writeln(line);
}
+ await sink.flush();
await sink.close();
}
@@ -199,7 +200,8 @@
if (platform == TargetPlatform.ios || platform == TargetPlatform.darwin_x64) {
final RunResult result = await _buildFramework(
appleArch: darwinArch,
- assemblyPath: bitcode ? '$assembly.bitcode' : assembly,
+ isIOS: platform == TargetPlatform.ios,
+ assemblyPath: bitcode ? '$assembly.stripped.S' : assembly,
outputPath: outputDir.path,
bitcode: bitcode,
);
@@ -213,26 +215,29 @@
/// source at [assemblyPath].
Future<RunResult> _buildFramework({
@required DarwinArch appleArch,
+ @required bool isIOS,
@required String assemblyPath,
@required String outputPath,
@required bool bitcode,
}) async {
final String targetArch = getNameForDarwinArch(appleArch);
printStatus('Building App.framework for $targetArch...');
+
final List<String> commonBuildOptions = <String>[
'-arch', targetArch,
- if (appleArch == DarwinArch.arm64 || appleArch == DarwinArch.armv7)
+ if (isIOS)
'-miphoneos-version-min=8.0',
];
+ const String embedBitcodeArg = '-fembed-bitcode';
final String assemblyO = fs.path.join(outputPath, 'snapshot_assembly.o');
final RunResult compileResult = await xcode.cc(<String>[
- ...commonBuildOptions,
+ '-arch', targetArch,
+ if (bitcode) embedBitcodeArg,
'-c',
assemblyPath,
'-o',
assemblyO,
- if (bitcode) '-fembed-bitcode',
]);
if (compileResult.exitCode != 0) {
printError('Failed to compile AOT snapshot. Compiler terminated with exit code ${compileResult.exitCode}');
@@ -248,26 +253,16 @@
'-Xlinker', '-rpath', '-Xlinker', '@executable_path/Frameworks',
'-Xlinker', '-rpath', '-Xlinker', '@loader_path/Frameworks',
'-install_name', '@rpath/App.framework/App',
- if (bitcode) '-fembed-bitcode',
+ if (bitcode) embedBitcodeArg,
+ if (bitcode && isIOS) ...<String>[embedBitcodeArg, '-isysroot', await xcode.iPhoneSdkLocation()],
'-o', appLib,
assemblyO,
];
final RunResult linkResult = await xcode.clang(linkArgs);
if (linkResult.exitCode != 0) {
printError('Failed to link AOT snapshot. Linker terminated with exit code ${compileResult.exitCode}');
- return linkResult;
}
- // See https://github.com/flutter/flutter/issues/22560
- // These have to be placed in a .noindex folder to prevent Xcode from
- // using Spotlight to find them and potentially attach the wrong ones.
- final RunResult dsymResult = await xcode.dsymutil(<String>[
- appLib,
- '-o', fs.path.join(outputPath, 'App.framework.dSYM.noindex'),
- ]);
- if (dsymResult.exitCode != 0) {
- printError('Failed to extract dSYM out of dynamic lib');
- }
- return dsymResult;
+ return linkResult;
}
/// Compiles a Dart file to kernel.
diff --git a/packages/flutter_tools/lib/src/commands/build_aot.dart b/packages/flutter_tools/lib/src/commands/build_aot.dart
index bbb03f2..18b7ab5 100644
--- a/packages/flutter_tools/lib/src/commands/build_aot.dart
+++ b/packages/flutter_tools/lib/src/commands/build_aot.dart
@@ -83,7 +83,7 @@
if (platform != TargetPlatform.ios) {
throwToolExit('Bitcode is only supported on iOS (TargetPlatform is $targetPlatform).');
}
- await validateBitcode();
+ await validateBitcode(buildMode, platform);
}
Status status;
@@ -150,14 +150,6 @@
'-create',
'-output', fs.path.join(outputPath, 'App.framework', 'App'),
]);
- final Iterable<String> dSYMs = iosBuilds.values.map<String>((String outputDir) => fs.path.join(outputDir, 'App.framework.dSYM.noindex'));
- fs.directory(fs.path.join(outputPath, 'App.framework.dSYM.noindex', 'Contents', 'Resources', 'DWARF'))..createSync(recursive: true);
- await runCheckedAsync(<String>[
- 'lipo',
- '-create',
- '-output', fs.path.join(outputPath, 'App.framework.dSYM.noindex', 'Contents', 'Resources', 'DWARF', 'App'),
- ...dSYMs.map((String path) => fs.path.join(path, 'Contents', 'Resources', 'DWARF', 'App'))
- ]);
} else {
status?.cancel();
exitCodes.forEach((DarwinArch iosArch, Future<int> exitCodeFuture) async {
@@ -202,24 +194,18 @@
}
}
-Future<void> validateBitcode() async {
+Future<void> validateBitcode(BuildMode buildMode, TargetPlatform targetPlatform) async {
final Artifacts artifacts = Artifacts.instance;
- if (artifacts is! LocalEngineArtifacts) {
- throwToolExit('Bitcode is only supported with a local engine built with --bitcode.');
- }
- final String flutterFrameworkPath = artifacts.getArtifactPath(Artifact.flutterFramework);
+ final String flutterFrameworkPath = artifacts.getArtifactPath(
+ Artifact.flutterFramework,
+ mode: buildMode,
+ platform: targetPlatform,
+ );
if (!fs.isDirectorySync(flutterFrameworkPath)) {
throwToolExit('Flutter.framework not found at $flutterFrameworkPath');
}
final Xcode xcode = context.get<Xcode>();
- // Check for bitcode in Flutter binary.
- final RunResult otoolResult = await xcode.otool(<String>[
- '-l', fs.path.join(flutterFrameworkPath, 'Flutter'),
- ]);
- if (!otoolResult.stdout.contains('__LLVM')) {
- throwToolExit('The Flutter.framework at $flutterFrameworkPath does not contain bitcode.');
- }
final RunResult clangResult = await xcode.clang(<String>['--version']);
final String clangVersion = clangResult.stdout.split('\n').first;
final String engineClangVersion = PlistParser.instance.getValueFromFile(
diff --git a/packages/flutter_tools/lib/src/macos/xcode.dart b/packages/flutter_tools/lib/src/macos/xcode.dart
index 6fea9ad..8888f8d 100644
--- a/packages/flutter_tools/lib/src/macos/xcode.dart
+++ b/packages/flutter_tools/lib/src/macos/xcode.dart
@@ -4,6 +4,7 @@
import 'dart:async';
+import '../base/common.dart';
import '../base/context.dart';
import '../base/file_system.dart';
import '../base/io.dart';
@@ -100,16 +101,14 @@
return runCheckedAsync(<String>['xcrun', 'clang', ...args]);
}
- Future<RunResult> dsymutil(List<String> args) {
- return runCheckedAsync(<String>['xcrun', 'dsymutil', ...args]);
- }
-
- Future<RunResult> strip(List<String> args) {
- return runCheckedAsync(<String>['xcrun', 'strip', ...args]);
- }
-
- Future<RunResult> otool(List<String> args) {
- return runCheckedAsync(<String>['xcrun', 'otool', ...args]);
+ Future<String> iPhoneSdkLocation() async {
+ final RunResult runResult = await runCheckedAsync(
+ <String>['xcrun', '--sdk', 'iphoneos', '--show-sdk-path'],
+ );
+ if (runResult.exitCode != 0) {
+ throwToolExit('Could not find iPhone SDK location: ${runResult.stderr}');
+ }
+ return runResult.stdout.trim();
}
String getSimulatorPath() {
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 32d78a4..be3556c 100644
--- a/packages/flutter_tools/test/general.shard/base/build_test.dart
+++ b/packages/flutter_tools/test/general.shard/base/build_test.dart
@@ -116,13 +116,6 @@
when(mockArtifacts.getArtifactPath(Artifact.snapshotDart,
platform: anyNamed('platform'), mode: mode)).thenReturn(kSnapshotDart);
}
-
- when(mockXcode.dsymutil(any)).thenAnswer((_) => Future<RunResult>.value(
- RunResult(
- ProcessResult(1, 0, '', ''),
- <String>['command name', 'arguments...']),
- ),
- );
});
final Map<Type, Generator> contextOverrides = <Type, Generator>{
@@ -210,14 +203,9 @@
verify(xcode.cc(argThat(contains('-fembed-bitcode')))).called(1);
verify(xcode.clang(argThat(contains('-fembed-bitcode')))).called(1);
- verify(xcode.dsymutil(<String>[
- 'build/foo/App.framework/App',
- '-o',
- 'build/foo/App.framework.dSYM.noindex',
- ])).called(1);
final File assemblyFile = fs.file(assembly);
- final File assemblyBitcodeFile = fs.file('$assembly.bitcode');
+ final File assemblyBitcodeFile = fs.file('$assembly.stripped.S');
expect(assemblyFile.existsSync(), true);
expect(assemblyBitcodeFile.existsSync(), true);
expect(assemblyFile.readAsStringSync().contains('.section __DWARF'), true);
@@ -263,7 +251,6 @@
]);
verifyNever(xcode.cc(argThat(contains('-fembed-bitcode'))));
verifyNever(xcode.clang(argThat(contains('-fembed-bitcode'))));
- verify(xcode.dsymutil(any)).called(1);
final File assemblyFile = fs.file(assembly);
final File assemblyBitcodeFile = fs.file('$assembly.bitcode');
diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/dart_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/dart_test.dart
index 7b18e6f..d30377a 100644
--- a/packages/flutter_tools/test/general.shard/build_system/targets/dart_test.dart
+++ b/packages/flutter_tools/test/general.shard/build_system/targets/dart_test.dart
@@ -248,14 +248,12 @@
when(mockXcode.cc(any)).thenAnswer((_) => Future<RunResult>.value(fakeRunResult));
when(mockXcode.clang(any)).thenAnswer((_) => Future<RunResult>.value(fakeRunResult));
- when(mockXcode.dsymutil(any)).thenAnswer((_) => Future<RunResult>.value(fakeRunResult));
final BuildResult result = await buildSystem.build(const AotAssemblyProfile(), iosEnvironment);
expect(result.success, true);
verify(mockXcode.cc(argThat(contains('-fembed-bitcode')))).called(1);
verify(mockXcode.clang(argThat(contains('-fembed-bitcode')))).called(1);
- verify(mockXcode.dsymutil(any)).called(1);
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
Xcode: () => mockXcode,
@@ -278,14 +276,12 @@
when(mockXcode.cc(any)).thenAnswer((_) => Future<RunResult>.value(fakeRunResult));
when(mockXcode.clang(any)).thenAnswer((_) => Future<RunResult>.value(fakeRunResult));
- when(mockXcode.dsymutil(any)).thenAnswer((_) => Future<RunResult>.value(fakeRunResult));
final BuildResult result = await buildSystem.build(const AotAssemblyProfile(), iosEnvironment);
expect(result.success, true);
verify(mockXcode.cc(argThat(contains('-fembed-bitcode')))).called(2);
verify(mockXcode.clang(argThat(contains('-fembed-bitcode')))).called(2);
- verify(mockXcode.dsymutil(any)).called(2);
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
Xcode: () => mockXcode,
diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/macos_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/macos_test.dart
index 344bbc1..398c0e8 100644
--- a/packages/flutter_tools/test/general.shard/build_system/targets/macos_test.dart
+++ b/packages/flutter_tools/test/general.shard/build_system/targets/macos_test.dart
@@ -179,9 +179,6 @@
when(xcode.clang(any)).thenAnswer((Invocation invocation) {
return Future<RunResult>.value(RunResult(FakeProcessResult()..exitCode = 0, <String>['test']));
});
- when(xcode.dsymutil(any)).thenAnswer((Invocation invocation) {
- return Future<RunResult>.value(RunResult(FakeProcessResult()..exitCode = 0, <String>['test']));
- });
environment.buildDir.childFile('app.dill').createSync(recursive: true);
fs.file('.packages')
..createSync()
diff --git a/packages/flutter_tools/test/general.shard/commands/build_aot_test.dart b/packages/flutter_tools/test/general.shard/commands/build_aot_test.dart
index f12e63b..bcda514 100644
--- a/packages/flutter_tools/test/general.shard/commands/build_aot_test.dart
+++ b/packages/flutter_tools/test/general.shard/commands/build_aot_test.dart
@@ -6,6 +6,7 @@
import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/process.dart';
+import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/commands/build_aot.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/ios/plist_parser.dart';
@@ -32,16 +33,9 @@
mockPlistUtils = MockPlistUtils();
});
- testUsingContext('build aot validates building with bitcode requires a local engine', () async {
- await expectToolExitLater(
- validateBitcode(),
- equals('Bitcode is only supported with a local engine built with --bitcode.'),
- );
- });
-
testUsingContext('build aot validates existence of Flutter.framework in engine', () async {
await expectToolExitLater(
- validateBitcode(),
+ validateBitcode(BuildMode.release, TargetPlatform.ios),
equals('Flutter.framework not found at ios_profile/Flutter.framework'),
);
}, overrides: <Type, Generator>{
@@ -49,48 +43,21 @@
FileSystem: () => memoryFileSystem,
});
- testUsingContext('build aot validates Flutter.framework/Flutter contains bitcode', () async {
- final Directory flutterFramework = memoryFileSystem.directory('ios_profile/Flutter.framework')
- ..createSync(recursive: true);
- flutterFramework.childFile('Flutter').createSync();
- flutterFramework.childFile('Info.plist').createSync();
-
- final RunResult otoolResult = RunResult(
- FakeProcessResult(stdout: '', stderr: ''),
- const <String>['foo'],
- );
- when(mockXcode.otool(any)).thenAnswer((_) => Future<RunResult>.value(otoolResult));
- await expectToolExitLater(
- validateBitcode(),
- equals('The Flutter.framework at ios_profile/Flutter.framework does not contain bitcode.'),
- );
- }, overrides: <Type, Generator>{
- Artifacts: () => LocalEngineArtifacts('/engine', 'ios_profile', 'host_profile'),
- FileSystem: () => memoryFileSystem,
- ProcessManager: () => mockProcessManager,
- Xcode: () => mockXcode,
- });
-
testUsingContext('build aot validates Flutter.framework/Flutter was built with same toolchain', () async {
final Directory flutterFramework = memoryFileSystem.directory('ios_profile/Flutter.framework')
..createSync(recursive: true);
flutterFramework.childFile('Flutter').createSync();
final File infoPlist = flutterFramework.childFile('Info.plist')..createSync();
- final RunResult otoolResult = RunResult(
- FakeProcessResult(stdout: '__LLVM', stderr: ''),
- const <String>['foo'],
- );
final RunResult clangResult = RunResult(
FakeProcessResult(stdout: 'Apple LLVM version 10.0.0 (clang-4567.1.1.1)\nBlahBlah\n', stderr: ''),
const <String>['foo'],
);
- when(mockXcode.otool(any)).thenAnswer((_) => Future<RunResult>.value(otoolResult));
when(mockXcode.clang(any)).thenAnswer((_) => Future<RunResult>.value(clangResult));
when(mockPlistUtils.getValueFromFile(infoPlist.path, 'ClangVersion')).thenReturn('Apple LLVM version 10.0.1 (clang-1234.1.12.1)');
await expectToolExitLater(
- validateBitcode(),
+ validateBitcode(BuildMode.release, TargetPlatform.ios),
equals('The Flutter.framework at ios_profile/Flutter.framework was built with "Apple LLVM version 10.0.1 '
'(clang-1234.1.12.1)", but the current version of clang is "Apple LLVM version 10.0.0 (clang-4567.1.1.1)". '
'This will result in failures when trying toarchive an IPA. To resolve this issue, update your version '
@@ -111,19 +78,14 @@
flutterFramework.childFile('Flutter').createSync();
final File infoPlist = flutterFramework.childFile('Info.plist')..createSync();
- final RunResult otoolResult = RunResult(
- FakeProcessResult(stdout: '__LLVM', stderr: ''),
- const <String>['foo'],
- );
final RunResult clangResult = RunResult(
FakeProcessResult(stdout: 'Apple LLVM version 10.0.1 (clang-1234.1.12.1)\nBlahBlah\n', stderr: ''),
const <String>['foo'],
);
- when(mockXcode.otool(any)).thenAnswer((_) => Future<RunResult>.value(otoolResult));
when(mockXcode.clang(any)).thenAnswer((_) => Future<RunResult>.value(clangResult));
when(mockPlistUtils.getValueFromFile(infoPlist.path, 'ClangVersion')).thenReturn('Apple LLVM version 10.0.1 (clang-1234.1.12.1)');
- await validateBitcode();
+ await validateBitcode(BuildMode.release, TargetPlatform.ios);
expect(bufferLogger.statusText, '');
}, overrides: <Type, Generator>{
@@ -141,19 +103,14 @@
flutterFramework.childFile('Flutter').createSync();
final File infoPlist = flutterFramework.childFile('Info.plist')..createSync();
- final RunResult otoolResult = RunResult(
- FakeProcessResult(stdout: '__LLVM', stderr: ''),
- const <String>['foo'],
- );
final RunResult clangResult = RunResult(
FakeProcessResult(stdout: 'Apple LLVM version 11.0.1 (clang-1234.1.12.1)\nBlahBlah\n', stderr: ''),
const <String>['foo'],
);
- when(mockXcode.otool(any)).thenAnswer((_) => Future<RunResult>.value(otoolResult));
when(mockXcode.clang(any)).thenAnswer((_) => Future<RunResult>.value(clangResult));
when(mockPlistUtils.getValueFromFile(infoPlist.path, 'ClangVersion')).thenReturn('Apple LLVM version 10.0.1 (clang-1234.1.12.1)');
- await validateBitcode();
+ await validateBitcode(BuildMode.release, TargetPlatform.ios);
expect(bufferLogger.statusText, '');
}, overrides: <Type, Generator>{