Unverified Commit 202c1b42 authored by Dan Field's avatar Dan Field Committed by GitHub

Relax requirements around local engine, build hello_world with bitcode (#39357)

parent 31bd0d36
......@@ -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",
......
......@@ -114,7 +114,6 @@ BuildApp() {
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 @@ BuildApp() {
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
......
......@@ -179,13 +179,14 @@ class AOTSnapshotter {
// 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 @@ class AOTSnapshotter {
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 @@ class AOTSnapshotter {
/// 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 @@ class AOTSnapshotter {
'-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.
......
......@@ -83,7 +83,7 @@ class BuildAotCommand extends BuildSubCommand with TargetPlatformBasedDevelopmen
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 @@ class BuildAotCommand extends BuildSubCommand with TargetPlatformBasedDevelopmen
'-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 @@ class BuildAotCommand extends BuildSubCommand with TargetPlatformBasedDevelopmen
}
}
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(
......
......@@ -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 @@ class Xcode {
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() {
......
......@@ -116,13 +116,6 @@ void main() {
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 @@ void main() {
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 @@ void main() {
]);
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');
......
......@@ -248,14 +248,12 @@ flutter_tools:lib/''');
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 @@ flutter_tools:lib/''');
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,
......
......@@ -179,9 +179,6 @@ void main() {
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()
......
......@@ -6,6 +6,7 @@ import 'package:file/memory.dart';
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 @@ void main() {
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 @@ void main() {
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 @@ void main() {
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 @@ void main() {
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>{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment