Unverified Commit 68a1e2f7 authored by Chris Bracken's avatar Chris Bracken Committed by GitHub

Simplify iOS debug build (#17145)

iOS debug builds always run in interpreted mode whether on device or on
simulator. In both cases, we can skip snapshotting and link against an
empty App.framework. Previously, we did this for iOS simulator builds.
This does the same for device builds.

Previously, debug iOS builds used gen_snapshot to generate a core
snapshot, then used 'xxd' to generate C files containing the snapshot
data in buffers named kDartVmSnapshotData and kDartIsolateSnapshotData,
which are then compiled/linked into App.framework. This is unnecessary
since the VM compiled into Flutter.framework already contains this data.
parent c3d43ef4
......@@ -109,7 +109,7 @@ BuildApp() {
preview_dart_2_flag="--no-preview-dart-2"
fi
if [[ "$CURRENT_ARCH" != "x86_64" ]]; then
if [[ "${build_mode}" != "debug" ]]; then
StreamOutput " ├─Building Dart code..."
RunCommand "${FLUTTER_ROOT}/bin/flutter" --suppress-analytics \
${verbose_flag} \
......@@ -131,6 +131,7 @@ BuildApp() {
else
RunCommand mkdir -p -- "${derived_dir}/App.framework"
RunCommand eval "$(echo "static const int Moo = 88;" | xcrun clang -x c \
-arch "$CURRENT_ARCH" \
-dynamiclib \
-Xlinker -rpath -Xlinker '@executable_path/Frameworks' \
-Xlinker -rpath -Xlinker '@loader_path/Frameworks' \
......
......@@ -221,14 +221,10 @@ class Snapshotter {
outputDir.createSync(recursive: true);
printTrace('Compiling Dart to kernel: $mainPath');
final bool aot = !_isInterpreted(platform, buildMode);
final List<String> entryPointsJsonFiles = <String>[];
if (aot) {
entryPointsJsonFiles.addAll(<String>[
artifacts.getArtifactPath(Artifact.entryPointsJson, platform, buildMode),
artifacts.getArtifactPath(Artifact.entryPointsExtraJson, platform, buildMode),
]);
}
final List<String> entryPointsJsonFiles = <String>[
artifacts.getArtifactPath(Artifact.entryPointsJson, platform, buildMode),
artifacts.getArtifactPath(Artifact.entryPointsExtraJson, platform, buildMode),
];
if ((extraFrontEndOptions != null) && extraFrontEndOptions.isNotEmpty)
printTrace('Extra front-end options: $extraFrontEndOptions');
......@@ -241,7 +237,7 @@ class Snapshotter {
depFilePath: depfilePath,
extraFrontEndOptions: extraFrontEndOptions,
linkPlatformKernelIn: true,
aot: aot,
aot: true,
entryPointsJsonFiles: entryPointsJsonFiles,
trackWidgetCreation: false,
);
......@@ -264,9 +260,9 @@ class Snapshotter {
@required bool preferSharedLibrary,
List<String> extraGenSnapshotOptions: const <String>[],
}) async {
if (!_isValidAotPlatform(platform)) {
if (!_isValidAotPlatform(platform, buildMode)) {
printError('${getNameForTargetPlatform(platform)} does not support AOT compilation.');
return -2;
return -1;
}
final bool compileToSharedLibrary = preferSharedLibrary && androidSdk.ndkCompiler != null;
......@@ -278,7 +274,7 @@ class Snapshotter {
final String packageMapError = packageMap.checkValid();
if (packageMapError != null) {
printError(packageMapError);
return -3;
return -2;
}
final Directory outputDir = fs.directory(outputPath);
......@@ -287,8 +283,10 @@ class Snapshotter {
final String skyEnginePkg = _getPackagePath(packageMap, 'sky_engine');
final String uiPath = fs.path.join(skyEnginePkg, 'lib', 'ui', 'ui.dart');
final String vmServicePath = fs.path.join(skyEnginePkg, 'sdk_ext', 'vmservice_io.dart');
final String vmEntryPoints = artifacts.getArtifactPath(Artifact.dartVmEntryPointsTxt, platform, buildMode);
final String ioEntryPoints = artifacts.getArtifactPath(Artifact.dartIoEntriesTxt, platform, buildMode);
final List<String> inputPaths = <String>[uiPath, vmServicePath, mainPath];
final List<String> inputPaths = <String>[uiPath, vmServicePath, vmEntryPoints, ioEntryPoints, mainPath];
final Set<String> outputPaths = new Set<String>();
final String vmSnapshotData = fs.path.join(outputDir.path, 'vm_snapshot_data');
......@@ -299,6 +297,8 @@ class Snapshotter {
'--isolate_snapshot_data=$isolateSnapshotData',
'--url_mapping=dart:ui,$uiPath',
'--url_mapping=dart:vmservice_io,$vmServicePath',
'--embedder_entry_points_manifest=$vmEntryPoints',
'--embedder_entry_points_manifest=$ioEntryPoints',
'--dependencies=$depfilePath',
];
if (previewDart2) {
......@@ -318,21 +318,6 @@ class Snapshotter {
genSnapshotArgs.addAll(extraGenSnapshotOptions);
}
final bool interpreter = _isInterpreted(platform, buildMode);
if (!interpreter) {
final String vmEntryPoints = artifacts.getArtifactPath(Artifact.dartVmEntryPointsTxt, platform, buildMode);
final String ioEntryPoints = artifacts.getArtifactPath(Artifact.dartIoEntriesTxt, platform, buildMode);
genSnapshotArgs.add('--embedder_entry_points_manifest=$vmEntryPoints');
genSnapshotArgs.add('--embedder_entry_points_manifest=$ioEntryPoints');
inputPaths..addAll(<String>[vmEntryPoints, ioEntryPoints]);
}
// iOS snapshot generated files, compiled object files.
const String kVmSnapshotData = 'kDartVmSnapshotData';
const String kIsolateSnapshotData = 'kDartIsolateSnapshotData';
final String kVmSnapshotDataO = fs.path.join(outputDir.path, '$kVmSnapshotData.o');
final String kIsolateSnapshotDataO = fs.path.join(outputDir.path, '$kIsolateSnapshotData.o');
// Compile-to-assembly outputs.
final String assembly = fs.path.join(outputDir.path, 'snapshot_assembly.S');
final String assemblyO = fs.path.join(outputDir.path, 'snapshot_assembly.o');
......@@ -365,14 +350,9 @@ class Snapshotter {
}
break;
case TargetPlatform.ios:
if (interpreter) {
genSnapshotArgs.add('--snapshot_kind=core');
outputPaths.addAll(<String>[kVmSnapshotDataO, kIsolateSnapshotDataO]);
} else {
genSnapshotArgs.add('--snapshot_kind=app-aot-assembly');
genSnapshotArgs.add('--assembly=$assembly');
outputPaths.add(assemblyO);
}
genSnapshotArgs.add('--snapshot_kind=app-aot-assembly');
genSnapshotArgs.add('--assembly=$assembly');
outputPaths.add(assemblyO);
break;
case TargetPlatform.darwin_x64:
case TargetPlatform.linux_x64:
......@@ -382,19 +362,13 @@ class Snapshotter {
assert(false);
}
if (interpreter) {
final String snapshotDartIOS = artifacts.getArtifactPath(Artifact.snapshotDart, platform, buildMode);
inputPaths.add(snapshotDartIOS);
genSnapshotArgs.add(snapshotDartIOS);
} else {
genSnapshotArgs.add(mainPath);
}
genSnapshotArgs.add(mainPath);
// Verify that all required inputs exist.
final Iterable<String> missingInputs = inputPaths.where((String p) => !fs.isFileSync(p));
if (missingInputs.isNotEmpty) {
printError('Missing input files: $missingInputs from $inputPaths');
return -4;
return -3;
}
// If inputs and outputs have not changed since last run, skip the build.
......@@ -413,7 +387,7 @@ class Snapshotter {
);
if (genSnapshotExitCode != 0) {
printError('Dart snapshot generator failed with exit code $genSnapshotExitCode');
return -6;
return -4;
}
// Write path to gen_snapshot, since snapshots have to be re-generated when we roll
......@@ -426,26 +400,7 @@ class Snapshotter {
printStatus('Building App.framework...');
const List<String> commonBuildOptions = const <String>['-arch', 'arm64', '-miphoneos-version-min=8.0'];
if (interpreter) {
final String kVmSnapshotDataC = fs.path.join(outputDir.path, '$kVmSnapshotData.c');
final String kIsolateSnapshotDataC = fs.path.join(outputDir.path, '$kIsolateSnapshotData.c');
await fs.file(vmSnapshotData).rename(fs.path.join(outputDir.path, kVmSnapshotData));
await fs.file(isolateSnapshotData).rename(fs.path.join(outputDir.path, kIsolateSnapshotData));
await xxd.run(
<String>['--include', kVmSnapshotData, fs.path.basename(kVmSnapshotDataC)],
workingDirectory: outputDir.path,
);
await xxd.run(
<String>['--include', kIsolateSnapshotData, fs.path.basename(kIsolateSnapshotDataC)],
workingDirectory: outputDir.path,
);
await xcode.cc(commonBuildOptions.toList()..addAll(<String>['-c', kVmSnapshotDataC, '-o', kVmSnapshotDataO]));
await xcode.cc(commonBuildOptions.toList()..addAll(<String>['-c', kIsolateSnapshotDataC, '-o', kIsolateSnapshotDataO]));
} else {
await xcode.cc(commonBuildOptions.toList()..addAll(<String>['-c', assembly, '-o', assemblyO]));
}
await xcode.cc(commonBuildOptions.toList()..addAll(<String>['-c', assembly, '-o', assemblyO]));
final String frameworkDir = fs.path.join(outputDir.path, 'App.framework');
fs.directory(frameworkDir).createSync(recursive: true);
......@@ -456,13 +411,8 @@ class Snapshotter {
'-Xlinker', '-rpath', '-Xlinker', '@loader_path/Frameworks',
'-install_name', '@rpath/App.framework/App',
'-o', appLib,
assemblyO,
]);
if (interpreter) {
linkArgs.add(kVmSnapshotDataO);
linkArgs.add(kIsolateSnapshotDataO);
} else {
linkArgs.add(assemblyO);
}
await xcode.clang(linkArgs);
} else {
if (compileToSharedLibrary) {
......@@ -484,7 +434,9 @@ class Snapshotter {
return 0;
}
bool _isValidAotPlatform(TargetPlatform platform) {
bool _isValidAotPlatform(TargetPlatform platform, BuildMode buildMode) {
if (platform == TargetPlatform.ios && buildMode == BuildMode.debug)
return false;
return const <TargetPlatform>[
TargetPlatform.android_arm,
TargetPlatform.android_arm64,
......@@ -492,11 +444,6 @@ class Snapshotter {
].contains(platform);
}
/// Returns true if the specified platform and build mode require running in interpreted mode.
bool _isInterpreted(TargetPlatform platform, BuildMode buildMode) {
return platform == TargetPlatform.ios && buildMode == BuildMode.debug;
}
String _getPackagePath(PackageMap packageMap, String package) {
return fs.path.dirname(fs.path.fromUri(packageMap.map[package]));
}
......
......@@ -74,7 +74,6 @@ Future<T> runInContext<T>(
Usage: () => new Usage(),
Xcode: () => new Xcode(),
XcodeProjectInterpreter: () => new XcodeProjectInterpreter(),
Xxd: () => new Xxd(),
},
);
}
......@@ -39,8 +39,6 @@ IMobileDevice get iMobileDevice => context[IMobileDevice];
Xcode get xcode => context[Xcode];
Xxd get xxd => context[Xxd];
class PythonModule {
const PythonModule(this.name);
......@@ -105,12 +103,6 @@ class IMobileDevice {
}
}
class Xxd {
Future<RunResult> run(List<String> args, {String workingDirectory}) {
return runCheckedAsync(<String>['xxd']..addAll(args), workingDirectory: workingDirectory);
}
}
class Xcode {
bool get isInstalledAndMeetsVersionCheck => isInstalled && isVersionSatisfactory;
......
......@@ -22,7 +22,6 @@ import '../src/context.dart';
class MockFlutterVersion extends Mock implements FlutterVersion {}
class MockArtifacts extends Mock implements Artifacts {}
class MockXcode extends Mock implements Xcode {}
class MockXxd extends Mock implements Xxd {}
class _FakeGenSnapshot implements GenSnapshot {
_FakeGenSnapshot({
......@@ -586,7 +585,6 @@ void main() {
Snapshotter snapshotter;
MockArtifacts mockArtifacts;
MockXcode mockXcode;
MockXxd mockXxd;
setUp(() async {
fs = new MemoryFileSystem();
......@@ -608,7 +606,6 @@ void main() {
snapshotter = new Snapshotter();
mockArtifacts = new MockArtifacts();
mockXcode = new MockXcode();
mockXxd = new MockXxd();
for (BuildMode mode in BuildMode.values) {
when(mockArtifacts.getArtifactPath(Artifact.dartVmEntryPointsTxt, TargetPlatform.ios, mode)).thenReturn(kVmEntrypoints);
when(mockArtifacts.getArtifactPath(Artifact.dartIoEntriesTxt, TargetPlatform.ios, mode)).thenReturn(kIoEntries);
......@@ -623,25 +620,11 @@ void main() {
FileSystem: () => fs,
GenSnapshot: () => genSnapshot,
Xcode: () => mockXcode,
Xxd: () => mockXxd,
};
testUsingContext('builds iOS debug AOT snapshot', () async {
fs.file('main.dill').writeAsStringSync('binary magic');
testUsingContext('iOS debug AOT snapshot is invalid', () async {
final String outputPath = fs.path.join('build', 'foo');
fs.directory(outputPath).createSync(recursive: true);
genSnapshot.outputs = <String, String>{
fs.path.join(outputPath, 'vm_snapshot_data'): '',
fs.path.join(outputPath, 'vm_snapshot_instr'): '',
fs.path.join(outputPath, 'isolate_snapshot_data'): '',
fs.path.join(outputPath, 'isolate_snapshot_instr'): '',
fs.path.join(outputPath, 'snapshot.d'): '',
fs.path.join(outputPath, 'snapshot_assembly.S'): '',
};
final int genSnapshotExitCode = await snapshotter.buildAotSnapshot(
expect(await snapshotter.buildAotSnapshot(
platform: TargetPlatform.ios,
buildMode: BuildMode.debug,
mainPath: 'main.dill',
......@@ -649,26 +632,7 @@ void main() {
outputPath: outputPath,
preferSharedLibrary: false,
previewDart2: true,
);
expect(genSnapshotExitCode, 0);
expect(genSnapshot.callCount, 1);
expect(genSnapshot.snapshotType.platform, TargetPlatform.ios);
expect(genSnapshot.snapshotType.mode, BuildMode.debug);
expect(genSnapshot.packagesPath, '.packages');
expect(genSnapshot.additionalArgs, <String>[
'--vm_snapshot_data=${fs.path.join(outputPath, 'vm_snapshot_data')}',
'--isolate_snapshot_data=${fs.path.join(outputPath, 'isolate_snapshot_data')}',
'--url_mapping=dart:ui,${fs.path.join(skyEnginePath, 'lib', 'ui', 'ui.dart')}',
'--url_mapping=dart:vmservice_io,${fs.path.join(skyEnginePath, 'sdk_ext', 'vmservice_io.dart')}',
'--dependencies=${fs.path.join(outputPath, 'snapshot.d')}',
'--reify-generic-functions',
'--strong',
'--no-checked',
'--conditional_directives',
'--snapshot_kind=core',
'snapshot.dart',
]);
), isNot(equals(0)));
}, overrides: contextOverrides);
testUsingContext('builds iOS profile AOT snapshot', () async {
......@@ -702,13 +666,13 @@ void main() {
'--isolate_snapshot_data=${fs.path.join(outputPath, 'isolate_snapshot_data')}',
'--url_mapping=dart:ui,${fs.path.join(skyEnginePath, 'lib', 'ui', 'ui.dart')}',
'--url_mapping=dart:vmservice_io,${fs.path.join(skyEnginePath, 'sdk_ext', 'vmservice_io.dart')}',
'--embedder_entry_points_manifest=$kVmEntrypoints',
'--embedder_entry_points_manifest=$kIoEntries',
'--dependencies=${fs.path.join(outputPath, 'snapshot.d')}',
'--reify-generic-functions',
'--strong',
'--no-checked',
'--conditional_directives',
'--embedder_entry_points_manifest=$kVmEntrypoints',
'--embedder_entry_points_manifest=$kIoEntries',
'--snapshot_kind=app-aot-assembly',
'--assembly=${fs.path.join(outputPath, 'snapshot_assembly.S')}',
'main.dill',
......@@ -746,11 +710,11 @@ void main() {
'--isolate_snapshot_data=${fs.path.join(outputPath, 'isolate_snapshot_data')}',
'--url_mapping=dart:ui,${fs.path.join(skyEnginePath, 'lib', 'ui', 'ui.dart')}',
'--url_mapping=dart:vmservice_io,${fs.path.join(skyEnginePath, 'sdk_ext', 'vmservice_io.dart')}',
'--embedder_entry_points_manifest=$kVmEntrypoints',
'--embedder_entry_points_manifest=$kIoEntries',
'--dependencies=${fs.path.join(outputPath, 'snapshot.d')}',
'--reify-generic-functions',
'--strong',
'--embedder_entry_points_manifest=$kVmEntrypoints',
'--embedder_entry_points_manifest=$kIoEntries',
'--snapshot_kind=app-aot-assembly',
'--assembly=${fs.path.join(outputPath, 'snapshot_assembly.S')}',
'main.dill',
......
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