mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Move AOT snapshotting to Snapshotter class (#17015)
This moves AOT snapshotting out of build_aot.dart and into the Snapshotter class. It also adds unit tests for iOS debug, profile, and release builds.
This commit is contained in:
parent
adf97fb58f
commit
82f969ff05
@ -9,13 +9,18 @@ import 'package:crypto/crypto.dart' show md5;
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:quiver/core.dart' show hash2;
|
||||
|
||||
import '../android/android_sdk.dart';
|
||||
import '../artifacts.dart';
|
||||
import '../build_info.dart';
|
||||
import '../compile.dart';
|
||||
import '../dart/package_map.dart';
|
||||
import '../globals.dart';
|
||||
import '../ios/mac.dart';
|
||||
import '../version.dart';
|
||||
import 'context.dart';
|
||||
import 'file_system.dart';
|
||||
import 'process.dart';
|
||||
import 'utils.dart' show toTitleCase;
|
||||
|
||||
GenSnapshot get genSnapshot => context[GenSnapshot];
|
||||
|
||||
@ -203,8 +208,349 @@ class Snapshotter {
|
||||
}
|
||||
|
||||
/// Builds an architecture-specific ahead-of-time compiled snapshot of the specified script.
|
||||
Future<Null> buildAotSnapshot() async {
|
||||
throw new UnimplementedError('AOT snapshotting not yet implemented');
|
||||
Future<int> buildAotSnapshot({
|
||||
@required TargetPlatform platform,
|
||||
@required BuildMode buildMode,
|
||||
@required String mainPath,
|
||||
@required String depfilePath,
|
||||
@required String packagesPath,
|
||||
@required String outputPath,
|
||||
@required bool interpreter,
|
||||
@required bool previewDart2,
|
||||
@required bool preferSharedLibrary,
|
||||
List<String> extraFrontEndOptions: const <String>[],
|
||||
List<String> extraGenSnapshotOptions: const <String>[],
|
||||
}) async {
|
||||
if (!isAotBuildMode(buildMode) && !interpreter) {
|
||||
printError('${toTitleCase(getModeName(buildMode))} mode does not support AOT compilation.');
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(platform == TargetPlatform.android_arm ||
|
||||
platform == TargetPlatform.android_arm64 ||
|
||||
platform == TargetPlatform.ios)) {
|
||||
printError('${getNameForTargetPlatform(platform)} does not support AOT compilation.');
|
||||
return -2;
|
||||
}
|
||||
|
||||
final Directory outputDir = fs.directory(outputPath);
|
||||
outputDir.createSync(recursive: true);
|
||||
final String vmSnapshotData = fs.path.join(outputDir.path, 'vm_snapshot_data');
|
||||
final String vmSnapshotInstructions = fs.path.join(outputDir.path, 'vm_snapshot_instr');
|
||||
final String isolateSnapshotData = fs.path.join(outputDir.path, 'isolate_snapshot_data');
|
||||
final String isolateSnapshotInstructions = fs.path.join(outputDir.path, 'isolate_snapshot_instr');
|
||||
final String dependencies = fs.path.join(outputDir.path, 'snapshot.d');
|
||||
final String assembly = fs.path.join(outputDir.path, 'snapshot_assembly.S');
|
||||
final String assemblyO = fs.path.join(outputDir.path, 'snapshot_assembly.o');
|
||||
final String assemblySo = fs.path.join(outputDir.path, 'app.so');
|
||||
final bool compileToSharedLibrary =
|
||||
preferSharedLibrary && androidSdk.ndkCompiler != null;
|
||||
|
||||
if (preferSharedLibrary && !compileToSharedLibrary) {
|
||||
printStatus(
|
||||
'Could not find NDK compiler. Not building in shared library mode');
|
||||
}
|
||||
|
||||
final String vmEntryPoints = artifacts.getArtifactPath(Artifact.dartVmEntryPointsTxt, platform, buildMode);
|
||||
assert(vmEntryPoints != null);
|
||||
|
||||
final String ioEntryPoints = artifacts.getArtifactPath(Artifact.dartIoEntriesTxt, platform, buildMode);
|
||||
assert(ioEntryPoints != null);
|
||||
|
||||
final List<String> entryPointsJsonFiles = <String>[];
|
||||
if (previewDart2 && !interpreter) {
|
||||
entryPointsJsonFiles.addAll(<String>[
|
||||
artifacts.getArtifactPath(Artifact.entryPointsJson, platform, buildMode),
|
||||
artifacts.getArtifactPath(Artifact.entryPointsExtraJson, platform, buildMode),
|
||||
]);
|
||||
}
|
||||
|
||||
final PackageMap packageMap = new PackageMap(packagesPath);
|
||||
final String packageMapError = packageMap.checkValid();
|
||||
if (packageMapError != null) {
|
||||
printError(packageMapError);
|
||||
return -3;
|
||||
}
|
||||
|
||||
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 List<String> inputPaths = <String>[
|
||||
vmEntryPoints,
|
||||
ioEntryPoints,
|
||||
uiPath,
|
||||
vmServicePath,
|
||||
mainPath,
|
||||
];
|
||||
|
||||
inputPaths.addAll(entryPointsJsonFiles);
|
||||
|
||||
final Set<String> outputPaths = new Set<String>();
|
||||
|
||||
// These paths are used only on iOS.
|
||||
String snapshotDartIOS;
|
||||
|
||||
switch (platform) {
|
||||
case TargetPlatform.android_arm:
|
||||
case TargetPlatform.android_arm64:
|
||||
case TargetPlatform.android_x64:
|
||||
case TargetPlatform.android_x86:
|
||||
if (compileToSharedLibrary) {
|
||||
outputPaths.add(assemblySo);
|
||||
} else {
|
||||
outputPaths.addAll(<String>[
|
||||
vmSnapshotData,
|
||||
isolateSnapshotData,
|
||||
]);
|
||||
}
|
||||
break;
|
||||
case TargetPlatform.ios:
|
||||
snapshotDartIOS = artifacts.getArtifactPath(Artifact.snapshotDart, platform, buildMode);
|
||||
inputPaths.add(snapshotDartIOS);
|
||||
break;
|
||||
case TargetPlatform.darwin_x64:
|
||||
case TargetPlatform.linux_x64:
|
||||
case TargetPlatform.windows_x64:
|
||||
case TargetPlatform.fuchsia:
|
||||
case TargetPlatform.tester:
|
||||
assert(false);
|
||||
}
|
||||
|
||||
final Iterable<String> missingInputs = inputPaths.where((String p) => !fs.isFileSync(p));
|
||||
if (missingInputs.isNotEmpty) {
|
||||
printError('Missing input files: $missingInputs');
|
||||
return -4;
|
||||
}
|
||||
|
||||
final List<String> genSnapshotArgs = <String>[
|
||||
'--vm_snapshot_data=$vmSnapshotData',
|
||||
'--isolate_snapshot_data=$isolateSnapshotData',
|
||||
'--url_mapping=dart:ui,$uiPath',
|
||||
'--url_mapping=dart:vmservice_io,$vmServicePath',
|
||||
'--dependencies=$dependencies',
|
||||
];
|
||||
|
||||
if ((extraFrontEndOptions != null) && extraFrontEndOptions.isNotEmpty)
|
||||
printTrace('Extra front-end options: $extraFrontEndOptions');
|
||||
|
||||
if ((extraGenSnapshotOptions != null) && extraGenSnapshotOptions.isNotEmpty) {
|
||||
printTrace('Extra gen-snapshot options: $extraGenSnapshotOptions');
|
||||
genSnapshotArgs.addAll(extraGenSnapshotOptions);
|
||||
}
|
||||
|
||||
if (!interpreter) {
|
||||
genSnapshotArgs.add('--embedder_entry_points_manifest=$vmEntryPoints');
|
||||
genSnapshotArgs.add('--embedder_entry_points_manifest=$ioEntryPoints');
|
||||
}
|
||||
|
||||
// iOS symbols used to load snapshot data in the engine.
|
||||
const String kVmSnapshotData = 'kDartVmSnapshotData';
|
||||
const String kIsolateSnapshotData = 'kDartIsolateSnapshotData';
|
||||
|
||||
// iOS snapshot generated files, compiled object files.
|
||||
final String kVmSnapshotDataC = fs.path.join(outputDir.path, '$kVmSnapshotData.c');
|
||||
final String kIsolateSnapshotDataC = fs.path.join(outputDir.path, '$kIsolateSnapshotData.c');
|
||||
final String kVmSnapshotDataO = fs.path.join(outputDir.path, '$kVmSnapshotData.o');
|
||||
final String kIsolateSnapshotDataO = fs.path.join(outputDir.path, '$kIsolateSnapshotData.o');
|
||||
final String kApplicationKernelPath = fs.path.join(getBuildDirectory(), 'app.dill');
|
||||
|
||||
switch (platform) {
|
||||
case TargetPlatform.android_arm:
|
||||
case TargetPlatform.android_arm64:
|
||||
case TargetPlatform.android_x64:
|
||||
case TargetPlatform.android_x86:
|
||||
if (compileToSharedLibrary) {
|
||||
genSnapshotArgs.add('--snapshot_kind=app-aot-assembly');
|
||||
genSnapshotArgs.add('--assembly=$assembly');
|
||||
outputPaths.add(assemblySo);
|
||||
} else {
|
||||
genSnapshotArgs.addAll(<String>[
|
||||
'--snapshot_kind=app-aot-blobs',
|
||||
'--vm_snapshot_instructions=$vmSnapshotInstructions',
|
||||
'--isolate_snapshot_instructions=$isolateSnapshotInstructions',
|
||||
]);
|
||||
}
|
||||
if (platform == TargetPlatform.android_arm) {
|
||||
genSnapshotArgs.addAll(<String>[
|
||||
'--no-sim-use-hardfp', // Android uses the softfloat ABI.
|
||||
'--no-use-integer-division', // Not supported by the Pixel in 32-bit mode.
|
||||
]);
|
||||
}
|
||||
break;
|
||||
case TargetPlatform.ios:
|
||||
if (interpreter) {
|
||||
genSnapshotArgs.add('--snapshot_kind=core');
|
||||
genSnapshotArgs.add(snapshotDartIOS);
|
||||
outputPaths.addAll(<String>[
|
||||
kVmSnapshotDataO,
|
||||
kIsolateSnapshotDataO,
|
||||
]);
|
||||
} else {
|
||||
genSnapshotArgs.add('--snapshot_kind=app-aot-assembly');
|
||||
genSnapshotArgs.add('--assembly=$assembly');
|
||||
outputPaths.add(assemblyO);
|
||||
}
|
||||
break;
|
||||
case TargetPlatform.darwin_x64:
|
||||
case TargetPlatform.linux_x64:
|
||||
case TargetPlatform.windows_x64:
|
||||
case TargetPlatform.fuchsia:
|
||||
case TargetPlatform.tester:
|
||||
assert(false);
|
||||
}
|
||||
|
||||
if (buildMode != BuildMode.release) {
|
||||
genSnapshotArgs.addAll(<String>[
|
||||
'--no-checked',
|
||||
'--conditional_directives',
|
||||
]);
|
||||
}
|
||||
|
||||
final String entryPoint = mainPath;
|
||||
final SnapshotType snapshotType = new SnapshotType(platform, buildMode);
|
||||
Future<Fingerprint> makeFingerprint() async {
|
||||
final Set<String> snapshotInputPaths = await readDepfile(dependencies)
|
||||
..add(entryPoint)
|
||||
..addAll(outputPaths);
|
||||
return Snapshotter.createFingerprint(snapshotType, entryPoint, snapshotInputPaths);
|
||||
}
|
||||
|
||||
final File fingerprintFile = fs.file('$dependencies.fingerprint');
|
||||
final List<File> fingerprintFiles = <File>[fingerprintFile, fs.file(dependencies)]
|
||||
..addAll(inputPaths.map(fs.file))
|
||||
..addAll(outputPaths.map(fs.file));
|
||||
if (fingerprintFiles.every((File file) => file.existsSync())) {
|
||||
try {
|
||||
final String json = await fingerprintFile.readAsString();
|
||||
final Fingerprint oldFingerprint = new Fingerprint.fromJson(json);
|
||||
if (oldFingerprint == await makeFingerprint()) {
|
||||
printStatus('Skipping AOT snapshot build. Fingerprint match.');
|
||||
return 0;
|
||||
}
|
||||
} catch (e) {
|
||||
// Log exception and continue, this step is a performance improvement only.
|
||||
printTrace('Rebuilding snapshot due to fingerprint check error: $e');
|
||||
}
|
||||
}
|
||||
|
||||
if (previewDart2) {
|
||||
final CompilerOutput compilerOutput = await kernelCompiler.compile(
|
||||
sdkRoot: artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath),
|
||||
mainPath: mainPath,
|
||||
outputFilePath: kApplicationKernelPath,
|
||||
depFilePath: dependencies,
|
||||
extraFrontEndOptions: extraFrontEndOptions,
|
||||
linkPlatformKernelIn: true,
|
||||
aot: !interpreter,
|
||||
entryPointsJsonFiles: entryPointsJsonFiles,
|
||||
trackWidgetCreation: false,
|
||||
);
|
||||
mainPath = compilerOutput?.outputFilename;
|
||||
if (mainPath == null) {
|
||||
printError('Compiler terminated unexpectedly.');
|
||||
return -5;
|
||||
}
|
||||
// Write path to frontend_server, since things need to be re-generated when
|
||||
// that changes.
|
||||
await outputDir.childFile('frontend_server.d')
|
||||
.writeAsString('frontend_server.d: ${artifacts.getArtifactPath(Artifact.frontendServerSnapshotForEngineDartSdk)}\n');
|
||||
|
||||
genSnapshotArgs.addAll(<String>[
|
||||
'--reify-generic-functions',
|
||||
'--strong',
|
||||
]);
|
||||
}
|
||||
|
||||
genSnapshotArgs.add(mainPath);
|
||||
|
||||
final int genSnapshotExitCode = await genSnapshot.run(
|
||||
snapshotType: new SnapshotType(platform, buildMode),
|
||||
packagesPath: packageMap.packagesPath,
|
||||
depfilePath: dependencies,
|
||||
additionalArgs: genSnapshotArgs,
|
||||
);
|
||||
if (genSnapshotExitCode != 0) {
|
||||
printError('Dart snapshot generator failed with exit code $genSnapshotExitCode');
|
||||
return -6;
|
||||
}
|
||||
|
||||
// Write path to gen_snapshot, since snapshots have to be re-generated when we roll
|
||||
// the Dart SDK.
|
||||
await outputDir.childFile('gen_snapshot.d').writeAsString('snapshot.d: $genSnapshot\n');
|
||||
|
||||
// On iOS, we use Xcode to compile the snapshot into a dynamic library that the
|
||||
// end-developer can link into their app.
|
||||
if (platform == TargetPlatform.ios) {
|
||||
printStatus('Building App.framework...');
|
||||
|
||||
const List<String> commonBuildOptions = const <String>['-arch', 'arm64', '-miphoneos-version-min=8.0'];
|
||||
|
||||
if (interpreter) {
|
||||
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]));
|
||||
}
|
||||
|
||||
final String frameworkDir = fs.path.join(outputDir.path, 'App.framework');
|
||||
fs.directory(frameworkDir).createSync(recursive: true);
|
||||
final String appLib = fs.path.join(frameworkDir, 'App');
|
||||
final List<String> linkArgs = commonBuildOptions.toList()..addAll(<String>[
|
||||
'-dynamiclib',
|
||||
'-Xlinker', '-rpath', '-Xlinker', '@executable_path/Frameworks',
|
||||
'-Xlinker', '-rpath', '-Xlinker', '@loader_path/Frameworks',
|
||||
'-install_name', '@rpath/App.framework/App',
|
||||
'-o', appLib,
|
||||
]);
|
||||
if (interpreter) {
|
||||
linkArgs.add(kVmSnapshotDataO);
|
||||
linkArgs.add(kIsolateSnapshotDataO);
|
||||
} else {
|
||||
linkArgs.add(assemblyO);
|
||||
}
|
||||
await xcode.clang(linkArgs);
|
||||
} else {
|
||||
if (compileToSharedLibrary) {
|
||||
// A word of warning: Instead of compiling via two steps, to a .o file and
|
||||
// then to a .so file we use only one command. When using two commands
|
||||
// gcc will end up putting a .eh_frame and a .debug_frame into the shared
|
||||
// library. Without stripping .debug_frame afterwards, unwinding tools
|
||||
// based upon libunwind use just one and ignore the contents of the other
|
||||
// (which causes it to not look into the other section and therefore not
|
||||
// find the correct unwinding information).
|
||||
await runCheckedAsync(<String>[androidSdk.ndkCompiler]
|
||||
..addAll(androidSdk.ndkCompilerArgs)
|
||||
..addAll(<String>[ '-shared', '-nostdlib', '-o', assemblySo, assembly ]));
|
||||
}
|
||||
}
|
||||
|
||||
// Compute and record build fingerprint.
|
||||
try {
|
||||
final Fingerprint fingerprint = await makeFingerprint();
|
||||
await fingerprintFile.writeAsString(fingerprint.toJson());
|
||||
} catch (e, s) {
|
||||
// Log exception and continue, this step is a performance improvement only.
|
||||
printStatus('Error during AOT snapshot fingerprinting: $e\n$s');
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
String _getPackagePath(PackageMap packageMap, String package) {
|
||||
return fs.path.dirname(fs.path.fromUri(packageMap.map[package]));
|
||||
}
|
||||
|
||||
Future<bool> _isBuildRequired(SnapshotType type, String outputSnapshotPath, String depfilePath, String mainPath, String fingerprintPath) async {
|
||||
|
@ -4,28 +4,17 @@
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import '../android/android_sdk.dart';
|
||||
import '../artifacts.dart';
|
||||
import '../base/build.dart';
|
||||
import '../base/common.dart';
|
||||
import '../base/file_system.dart';
|
||||
import '../base/logger.dart';
|
||||
import '../base/process.dart';
|
||||
import '../base/utils.dart';
|
||||
import '../build_info.dart';
|
||||
import '../compile.dart';
|
||||
import '../dart/package_map.dart';
|
||||
import '../globals.dart';
|
||||
import '../ios/mac.dart' show xcode, xxd;
|
||||
import '../resident_runner.dart';
|
||||
import '../runner/flutter_command.dart';
|
||||
import 'build.dart';
|
||||
|
||||
// Files generated by the ahead-of-time snapshot builder.
|
||||
const List<String> kAotSnapshotFiles = const <String>[
|
||||
'vm_snapshot_data', 'vm_snapshot_instr', 'isolate_snapshot_data', 'isolate_snapshot_instr',
|
||||
];
|
||||
|
||||
class BuildAotCommand extends BuildSubCommand {
|
||||
BuildAotCommand({bool verboseHelp: false}) {
|
||||
usesTargetOption();
|
||||
@ -102,10 +91,6 @@ class BuildAotCommand extends BuildSubCommand {
|
||||
}
|
||||
}
|
||||
|
||||
String _getPackagePath(PackageMap packageMap, String package) {
|
||||
return fs.path.dirname(packageMap.map[package].toFilePath());
|
||||
}
|
||||
|
||||
/// Build an AOT snapshot. Return null (and log to `printError`) if the method
|
||||
/// fails.
|
||||
Future<String> buildAotSnapshot(
|
||||
@ -121,362 +106,28 @@ Future<String> buildAotSnapshot(
|
||||
}) async {
|
||||
outputPath ??= getAotBuildDirectory();
|
||||
try {
|
||||
return _buildAotSnapshot(
|
||||
mainPath,
|
||||
platform,
|
||||
buildMode,
|
||||
final Snapshotter snapshotter = new Snapshotter();
|
||||
final int snapshotExitCode = await snapshotter.buildAotSnapshot(
|
||||
platform: platform,
|
||||
buildMode: buildMode,
|
||||
mainPath: mainPath,
|
||||
depfilePath: 'depFilePathGoesHere',
|
||||
packagesPath: PackageMap.globalPackagesPath,
|
||||
outputPath: outputPath,
|
||||
interpreter: interpreter,
|
||||
previewDart2: previewDart2,
|
||||
preferSharedLibrary: preferSharedLibrary,
|
||||
extraFrontEndOptions: extraFrontEndOptions,
|
||||
extraGenSnapshotOptions: extraGenSnapshotOptions,
|
||||
preferSharedLibrary: preferSharedLibrary,
|
||||
);
|
||||
if (snapshotExitCode != 0) {
|
||||
printError('Snapshotting exited with non-zero exit code: $snapshotExitCode');
|
||||
return null;
|
||||
}
|
||||
return outputPath;
|
||||
} on String catch (error) {
|
||||
// Catch the String exceptions thrown from the `runCheckedSync` methods below.
|
||||
printError(error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(cbracken): split AOT and Assembly AOT snapshotting logic and migrate to Snapshotter class.
|
||||
Future<String> _buildAotSnapshot(
|
||||
String mainPath,
|
||||
TargetPlatform platform,
|
||||
BuildMode buildMode, {
|
||||
String outputPath,
|
||||
bool interpreter: false,
|
||||
bool previewDart2: false,
|
||||
List<String> extraFrontEndOptions,
|
||||
List<String> extraGenSnapshotOptions,
|
||||
bool preferSharedLibrary: false,
|
||||
}) async {
|
||||
outputPath ??= getAotBuildDirectory();
|
||||
if (!isAotBuildMode(buildMode) && !interpreter) {
|
||||
printError('${toTitleCase(getModeName(buildMode))} mode does not support AOT compilation.');
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!(platform == TargetPlatform.android_arm ||
|
||||
platform == TargetPlatform.android_arm64 ||
|
||||
platform == TargetPlatform.ios)) {
|
||||
printError('${getNameForTargetPlatform(platform)} does not support AOT compilation.');
|
||||
return null;
|
||||
}
|
||||
|
||||
final Directory outputDir = fs.directory(outputPath);
|
||||
outputDir.createSync(recursive: true);
|
||||
final String vmSnapshotData = fs.path.join(outputDir.path, 'vm_snapshot_data');
|
||||
final String vmSnapshotInstructions = fs.path.join(outputDir.path, 'vm_snapshot_instr');
|
||||
final String isolateSnapshotData = fs.path.join(outputDir.path, 'isolate_snapshot_data');
|
||||
final String isolateSnapshotInstructions = fs.path.join(outputDir.path, 'isolate_snapshot_instr');
|
||||
final String dependencies = fs.path.join(outputDir.path, 'snapshot.d');
|
||||
final String assembly = fs.path.join(outputDir.path, 'snapshot_assembly.S');
|
||||
final String assemblyO = fs.path.join(outputDir.path, 'snapshot_assembly.o');
|
||||
final String assemblySo = fs.path.join(outputDir.path, 'app.so');
|
||||
final bool compileToSharedLibrary =
|
||||
preferSharedLibrary && androidSdk.ndkCompiler != null;
|
||||
|
||||
if (preferSharedLibrary && !compileToSharedLibrary) {
|
||||
printStatus(
|
||||
'Could not find NDK compiler. Not building in shared library mode');
|
||||
}
|
||||
|
||||
final String vmEntryPoints = artifacts.getArtifactPath(
|
||||
Artifact.dartVmEntryPointsTxt,
|
||||
platform,
|
||||
buildMode,
|
||||
);
|
||||
final String ioEntryPoints = artifacts.getArtifactPath(Artifact.dartIoEntriesTxt, platform, buildMode);
|
||||
|
||||
final List<String> entryPointsJsonFiles = <String>[];
|
||||
if (previewDart2 && !interpreter) {
|
||||
entryPointsJsonFiles.addAll(<String>[
|
||||
artifacts.getArtifactPath(Artifact.entryPointsJson, platform, buildMode),
|
||||
artifacts.getArtifactPath(Artifact.entryPointsExtraJson, platform, buildMode),
|
||||
]);
|
||||
}
|
||||
|
||||
final PackageMap packageMap = new PackageMap(PackageMap.globalPackagesPath);
|
||||
final String packageMapError = packageMap.checkValid();
|
||||
if (packageMapError != null) {
|
||||
printError(packageMapError);
|
||||
return null;
|
||||
}
|
||||
|
||||
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 List<String> inputPaths = <String>[
|
||||
vmEntryPoints,
|
||||
ioEntryPoints,
|
||||
uiPath,
|
||||
vmServicePath,
|
||||
mainPath,
|
||||
];
|
||||
|
||||
inputPaths.addAll(entryPointsJsonFiles);
|
||||
|
||||
final Set<String> outputPaths = new Set<String>();
|
||||
|
||||
// These paths are used only on iOS.
|
||||
String snapshotDartIOS;
|
||||
|
||||
switch (platform) {
|
||||
case TargetPlatform.android_arm:
|
||||
case TargetPlatform.android_arm64:
|
||||
case TargetPlatform.android_x64:
|
||||
case TargetPlatform.android_x86:
|
||||
if (compileToSharedLibrary) {
|
||||
outputPaths.add(assemblySo);
|
||||
} else {
|
||||
outputPaths.addAll(<String>[
|
||||
vmSnapshotData,
|
||||
isolateSnapshotData,
|
||||
]);
|
||||
}
|
||||
break;
|
||||
case TargetPlatform.ios:
|
||||
snapshotDartIOS = artifacts.getArtifactPath(Artifact.snapshotDart, platform, buildMode);
|
||||
inputPaths.add(snapshotDartIOS);
|
||||
break;
|
||||
case TargetPlatform.darwin_x64:
|
||||
case TargetPlatform.linux_x64:
|
||||
case TargetPlatform.windows_x64:
|
||||
case TargetPlatform.fuchsia:
|
||||
case TargetPlatform.tester:
|
||||
assert(false);
|
||||
}
|
||||
|
||||
final Iterable<String> missingInputs = inputPaths.where((String p) => !fs.isFileSync(p));
|
||||
if (missingInputs.isNotEmpty) {
|
||||
printError('Missing input files: $missingInputs');
|
||||
return null;
|
||||
}
|
||||
|
||||
final List<String> genSnapshotArgs = <String>[
|
||||
'--vm_snapshot_data=$vmSnapshotData',
|
||||
'--isolate_snapshot_data=$isolateSnapshotData',
|
||||
'--url_mapping=dart:ui,$uiPath',
|
||||
'--url_mapping=dart:vmservice_io,$vmServicePath',
|
||||
'--dependencies=$dependencies',
|
||||
];
|
||||
|
||||
if ((extraFrontEndOptions != null) && extraFrontEndOptions.isNotEmpty)
|
||||
printTrace('Extra front-end options: $extraFrontEndOptions');
|
||||
|
||||
if ((extraGenSnapshotOptions != null) && extraGenSnapshotOptions.isNotEmpty) {
|
||||
printTrace('Extra gen-snapshot options: $extraGenSnapshotOptions');
|
||||
genSnapshotArgs.addAll(extraGenSnapshotOptions);
|
||||
}
|
||||
|
||||
if (!interpreter) {
|
||||
genSnapshotArgs.add('--embedder_entry_points_manifest=$vmEntryPoints');
|
||||
genSnapshotArgs.add('--embedder_entry_points_manifest=$ioEntryPoints');
|
||||
}
|
||||
|
||||
// iOS symbols used to load snapshot data in the engine.
|
||||
const String kVmSnapshotData = 'kDartVmSnapshotData';
|
||||
const String kIsolateSnapshotData = 'kDartIsolateSnapshotData';
|
||||
|
||||
// iOS snapshot generated files, compiled object files.
|
||||
final String kVmSnapshotDataC = fs.path.join(outputDir.path, '$kVmSnapshotData.c');
|
||||
final String kIsolateSnapshotDataC = fs.path.join(outputDir.path, '$kIsolateSnapshotData.c');
|
||||
final String kVmSnapshotDataO = fs.path.join(outputDir.path, '$kVmSnapshotData.o');
|
||||
final String kIsolateSnapshotDataO = fs.path.join(outputDir.path, '$kIsolateSnapshotData.o');
|
||||
final String kApplicationKernelPath = fs.path.join(getBuildDirectory(), 'app.dill');
|
||||
|
||||
switch (platform) {
|
||||
case TargetPlatform.android_arm:
|
||||
case TargetPlatform.android_arm64:
|
||||
case TargetPlatform.android_x64:
|
||||
case TargetPlatform.android_x86:
|
||||
if (compileToSharedLibrary) {
|
||||
genSnapshotArgs.add('--snapshot_kind=app-aot-assembly');
|
||||
genSnapshotArgs.add('--assembly=$assembly');
|
||||
outputPaths.add(assemblySo);
|
||||
} else {
|
||||
genSnapshotArgs.addAll(<String>[
|
||||
'--snapshot_kind=app-aot-blobs',
|
||||
'--vm_snapshot_instructions=$vmSnapshotInstructions',
|
||||
'--isolate_snapshot_instructions=$isolateSnapshotInstructions',
|
||||
]);
|
||||
}
|
||||
if (platform == TargetPlatform.android_arm) {
|
||||
genSnapshotArgs.addAll(<String>[
|
||||
'--no-sim-use-hardfp', // Android uses the softfloat ABI.
|
||||
'--no-use-integer-division', // Not supported by the Pixel in 32-bit mode.
|
||||
]);
|
||||
}
|
||||
break;
|
||||
case TargetPlatform.ios:
|
||||
if (interpreter) {
|
||||
genSnapshotArgs.add('--snapshot_kind=core');
|
||||
genSnapshotArgs.add(snapshotDartIOS);
|
||||
outputPaths.addAll(<String>[
|
||||
kVmSnapshotDataO,
|
||||
kIsolateSnapshotDataO,
|
||||
]);
|
||||
} else {
|
||||
genSnapshotArgs.add('--snapshot_kind=app-aot-assembly');
|
||||
genSnapshotArgs.add('--assembly=$assembly');
|
||||
outputPaths.add(assemblyO);
|
||||
}
|
||||
break;
|
||||
case TargetPlatform.darwin_x64:
|
||||
case TargetPlatform.linux_x64:
|
||||
case TargetPlatform.windows_x64:
|
||||
case TargetPlatform.fuchsia:
|
||||
case TargetPlatform.tester:
|
||||
assert(false);
|
||||
}
|
||||
|
||||
if (buildMode != BuildMode.release) {
|
||||
genSnapshotArgs.addAll(<String>[
|
||||
'--no-checked',
|
||||
'--conditional_directives',
|
||||
]);
|
||||
}
|
||||
|
||||
final String entryPoint = mainPath;
|
||||
final SnapshotType snapshotType = new SnapshotType(platform, buildMode);
|
||||
Future<Fingerprint> makeFingerprint() async {
|
||||
final Set<String> snapshotInputPaths = await readDepfile(dependencies)
|
||||
..add(entryPoint)
|
||||
..addAll(outputPaths);
|
||||
return Snapshotter.createFingerprint(snapshotType, entryPoint, snapshotInputPaths);
|
||||
}
|
||||
|
||||
final File fingerprintFile = fs.file('$dependencies.fingerprint');
|
||||
final List<File> fingerprintFiles = <File>[fingerprintFile, fs.file(dependencies)]
|
||||
..addAll(inputPaths.map(fs.file))
|
||||
..addAll(outputPaths.map(fs.file));
|
||||
if (fingerprintFiles.every((File file) => file.existsSync())) {
|
||||
try {
|
||||
final String json = await fingerprintFile.readAsString();
|
||||
final Fingerprint oldFingerprint = new Fingerprint.fromJson(json);
|
||||
if (oldFingerprint == await makeFingerprint()) {
|
||||
printStatus('Skipping AOT snapshot build. Fingerprint match.');
|
||||
return outputPath;
|
||||
}
|
||||
} catch (e) {
|
||||
// Log exception and continue, this step is a performance improvement only.
|
||||
printTrace('Rebuilding snapshot due to fingerprint check error: $e');
|
||||
}
|
||||
}
|
||||
|
||||
if (previewDart2) {
|
||||
final CompilerOutput compilerOutput = await kernelCompiler.compile(
|
||||
sdkRoot: artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath),
|
||||
mainPath: mainPath,
|
||||
outputFilePath: kApplicationKernelPath,
|
||||
depFilePath: dependencies,
|
||||
extraFrontEndOptions: extraFrontEndOptions,
|
||||
linkPlatformKernelIn : true,
|
||||
aot : !interpreter,
|
||||
entryPointsJsonFiles: entryPointsJsonFiles,
|
||||
trackWidgetCreation: false,
|
||||
);
|
||||
mainPath = compilerOutput?.outputFilename;
|
||||
if (mainPath == null) {
|
||||
printError('Compiler terminated unexpectedly.');
|
||||
return null;
|
||||
}
|
||||
// Write path to frontend_server, since things need to be re-generated when
|
||||
// that changes.
|
||||
await outputDir.childFile('frontend_server.d')
|
||||
.writeAsString('frontend_server.d: ${artifacts.getArtifactPath(Artifact.frontendServerSnapshotForEngineDartSdk)}\n');
|
||||
|
||||
genSnapshotArgs.addAll(<String>[
|
||||
'--reify-generic-functions',
|
||||
'--strong',
|
||||
]);
|
||||
}
|
||||
|
||||
genSnapshotArgs.add(mainPath);
|
||||
|
||||
final int genSnapshotExitCode = await genSnapshot.run(
|
||||
snapshotType: new SnapshotType(platform, buildMode),
|
||||
packagesPath: packageMap.packagesPath,
|
||||
depfilePath: dependencies,
|
||||
additionalArgs: genSnapshotArgs,
|
||||
);
|
||||
if (genSnapshotExitCode != 0) {
|
||||
printError('Dart snapshot generator failed with exit code $genSnapshotExitCode');
|
||||
return null;
|
||||
}
|
||||
|
||||
// Write path to gen_snapshot, since snapshots have to be re-generated when we roll
|
||||
// the Dart SDK.
|
||||
await outputDir.childFile('gen_snapshot.d').writeAsString('snapshot.d: $genSnapshot\n');
|
||||
|
||||
// On iOS, we use Xcode to compile the snapshot into a dynamic library that the
|
||||
// end-developer can link into their app.
|
||||
if (platform == TargetPlatform.ios) {
|
||||
printStatus('Building App.framework...');
|
||||
|
||||
const List<String> commonBuildOptions = const <String>['-arch', 'arm64', '-miphoneos-version-min=8.0'];
|
||||
|
||||
if (interpreter) {
|
||||
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]));
|
||||
}
|
||||
|
||||
final String frameworkDir = fs.path.join(outputDir.path, 'App.framework');
|
||||
fs.directory(frameworkDir).createSync(recursive: true);
|
||||
final String appLib = fs.path.join(frameworkDir, 'App');
|
||||
final List<String> linkArgs = commonBuildOptions.toList()..addAll(<String>[
|
||||
'-dynamiclib',
|
||||
'-Xlinker', '-rpath', '-Xlinker', '@executable_path/Frameworks',
|
||||
'-Xlinker', '-rpath', '-Xlinker', '@loader_path/Frameworks',
|
||||
'-install_name', '@rpath/App.framework/App',
|
||||
'-o', appLib,
|
||||
]);
|
||||
if (interpreter) {
|
||||
linkArgs.add(kVmSnapshotDataO);
|
||||
linkArgs.add(kIsolateSnapshotDataO);
|
||||
} else {
|
||||
linkArgs.add(assemblyO);
|
||||
}
|
||||
await xcode.clang(linkArgs);
|
||||
} else {
|
||||
if (compileToSharedLibrary) {
|
||||
// A word of warning: Instead of compiling via two steps, to a .o file and
|
||||
// then to a .so file we use only one command. When using two commands
|
||||
// gcc will end up putting a .eh_frame and a .debug_frame into the shared
|
||||
// library. Without stripping .debug_frame afterwards, unwinding tools
|
||||
// based upon libunwind use just one and ignore the contents of the other
|
||||
// (which causes it to not look into the other section and therefore not
|
||||
// find the correct unwinding information).
|
||||
await runCheckedAsync(<String>[androidSdk.ndkCompiler]
|
||||
..addAll(androidSdk.ndkCompilerArgs)
|
||||
..addAll(<String>[ '-shared', '-nostdlib', '-o', assemblySo, assembly ]));
|
||||
}
|
||||
}
|
||||
|
||||
// Compute and record build fingerprint.
|
||||
try {
|
||||
final Fingerprint fingerprint = await makeFingerprint();
|
||||
await fingerprintFile.writeAsString(fingerprint.toJson());
|
||||
} catch (e, s) {
|
||||
// Log exception and continue, this step is a performance improvement only.
|
||||
printStatus('Error during AOT snapshot fingerprinting: $e\n$s');
|
||||
}
|
||||
|
||||
return outputPath;
|
||||
}
|
||||
|
@ -9,9 +9,11 @@ import 'dart:convert' show json;
|
||||
import 'package:file/memory.dart';
|
||||
import 'package:flutter_tools/src/artifacts.dart';
|
||||
import 'package:flutter_tools/src/build_info.dart';
|
||||
import 'package:flutter_tools/src/compile.dart';
|
||||
import 'package:flutter_tools/src/base/build.dart';
|
||||
import 'package:flutter_tools/src/base/context.dart';
|
||||
import 'package:flutter_tools/src/base/file_system.dart';
|
||||
import 'package:flutter_tools/src/ios/mac.dart';
|
||||
import 'package:flutter_tools/src/version.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:test/test.dart';
|
||||
@ -20,6 +22,8 @@ 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({
|
||||
@ -66,6 +70,29 @@ class _FakeGenSnapshot implements GenSnapshot {
|
||||
}
|
||||
}
|
||||
|
||||
class _FakeKernelCompiler implements KernelCompiler {
|
||||
CompilerOutput output;
|
||||
|
||||
@override
|
||||
Future<CompilerOutput> compile({
|
||||
String sdkRoot,
|
||||
String mainPath,
|
||||
String outputFilePath,
|
||||
String depFilePath,
|
||||
bool linkPlatformKernelIn: false,
|
||||
bool aot: false,
|
||||
List<String> entryPointsJsonFiles,
|
||||
bool trackWidgetCreation: false,
|
||||
List<String> extraFrontEndOptions,
|
||||
String incrementalCompilerByteStorePath,
|
||||
String packagesPath,
|
||||
List<String> fileSystemRoots,
|
||||
String fileSystemScheme,
|
||||
}) async {
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
group('SnapshotType', () {
|
||||
test('throws, if build mode is null', () {
|
||||
@ -325,7 +352,7 @@ void main() {
|
||||
}, overrides: contextOverrides);
|
||||
});
|
||||
|
||||
group('Snapshotter', () {
|
||||
group('Snapshotter - Script Snapshots', () {
|
||||
const String kVersion = '123456abcdef';
|
||||
const String kIsolateSnapshotData = 'isolate_snapshot.bin';
|
||||
const String kVmSnapshotData = 'vm_isolate_snapshot.bin';
|
||||
@ -382,8 +409,8 @@ void main() {
|
||||
final Map<String, dynamic> jsonObject = json.decode(fs.file('output.snapshot.d.fingerprint').readAsStringSync());
|
||||
expect(jsonObject['properties']['entryPoint'], entryPoint);
|
||||
expect(jsonObject['files'], hasLength(checksums.length + 2));
|
||||
checksums.forEach((String path, String checksum) {
|
||||
expect(jsonObject['files'][path], checksum);
|
||||
checksums.forEach((String filePath, String checksum) {
|
||||
expect(jsonObject['files'][filePath], checksum);
|
||||
});
|
||||
expect(jsonObject['files'][kVmSnapshotData], '2ec34912477a46c03ddef07e8b909b46');
|
||||
expect(jsonObject['files'][kIsolateSnapshotData], '621b3844bb7d4d17d2cfc5edf9a91c4c');
|
||||
@ -569,4 +596,205 @@ void main() {
|
||||
}, overrides: contextOverrides);
|
||||
});
|
||||
});
|
||||
|
||||
group('Snapshotter - iOS AOT', () {
|
||||
const String kVmEntrypoints = 'dart_vm_entry_points.txt';
|
||||
const String kIoEntries = 'dart_io_entries.txt';
|
||||
const String kSnapshotDart = 'snapshot.dart';
|
||||
const String kEntrypointsJson = 'entry_points.json';
|
||||
const String kEntrypointsExtraJson = 'entry_points_extra.json';
|
||||
String skyEnginePath;
|
||||
|
||||
_FakeGenSnapshot genSnapshot;
|
||||
_FakeKernelCompiler kernelCompiler;
|
||||
MemoryFileSystem fs;
|
||||
Snapshotter snapshotter;
|
||||
MockArtifacts mockArtifacts;
|
||||
MockXcode mockXcode;
|
||||
MockXxd mockXxd;
|
||||
|
||||
setUp(() async {
|
||||
fs = new MemoryFileSystem();
|
||||
fs.file(kVmEntrypoints).createSync();
|
||||
fs.file(kIoEntries).createSync();
|
||||
fs.file(kSnapshotDart).createSync();
|
||||
fs.file(kEntrypointsJson).createSync();
|
||||
fs.file(kEntrypointsExtraJson).createSync();
|
||||
fs.file('.packages').writeAsStringSync('sky_engine:file:///flutter/bin/cache/pkg/sky_engine/lib/');
|
||||
|
||||
skyEnginePath = fs.path.fromUri(new Uri.file('/flutter/bin/cache/pkg/sky_engine'));
|
||||
fs.directory(fs.path.join(skyEnginePath, 'lib', 'ui')).createSync(recursive: true);
|
||||
fs.directory(fs.path.join(skyEnginePath, 'sdk_ext')).createSync(recursive: true);
|
||||
fs.file(fs.path.join(skyEnginePath, '.packages')).createSync();
|
||||
fs.file(fs.path.join(skyEnginePath, 'lib', 'ui', 'ui.dart')).createSync();
|
||||
fs.file(fs.path.join(skyEnginePath, 'sdk_ext', 'vmservice_io.dart')).createSync();
|
||||
|
||||
genSnapshot = new _FakeGenSnapshot();
|
||||
kernelCompiler = new _FakeKernelCompiler();
|
||||
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);
|
||||
when(mockArtifacts.getArtifactPath(Artifact.snapshotDart, TargetPlatform.ios, mode)).thenReturn(kSnapshotDart);
|
||||
when(mockArtifacts.getArtifactPath(Artifact.entryPointsJson, TargetPlatform.ios, mode)).thenReturn(kEntrypointsJson);
|
||||
when(mockArtifacts.getArtifactPath(Artifact.entryPointsExtraJson, TargetPlatform.ios, mode)).thenReturn(kEntrypointsExtraJson);
|
||||
}
|
||||
});
|
||||
|
||||
final Map<Type, Generator> contextOverrides = <Type, Generator>{
|
||||
Artifacts: () => mockArtifacts,
|
||||
FileSystem: () => fs,
|
||||
GenSnapshot: () => genSnapshot,
|
||||
KernelCompiler: () => kernelCompiler,
|
||||
Xcode: () => mockXcode,
|
||||
Xxd: () => mockXxd,
|
||||
};
|
||||
|
||||
testUsingContext('builds iOS debug AOT snapshot', () async {
|
||||
fs.file('main.dart').writeAsStringSync('void main() {}');
|
||||
|
||||
final String outputPath = fs.path.join('build', 'foo');
|
||||
fs.directory(outputPath).createSync(recursive: true);
|
||||
|
||||
kernelCompiler.output = const CompilerOutput('main.dill', 0);
|
||||
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(
|
||||
platform: TargetPlatform.ios,
|
||||
buildMode: BuildMode.debug,
|
||||
mainPath: 'main.dart',
|
||||
depfilePath: fs.path.join(outputPath, 'snapshot.d'),
|
||||
packagesPath: '.packages',
|
||||
outputPath: outputPath,
|
||||
interpreter: true,
|
||||
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.depfilePath, fs.path.join(outputPath, 'snapshot.d'));
|
||||
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')}',
|
||||
'--snapshot_kind=core',
|
||||
'snapshot.dart',
|
||||
'--no-checked',
|
||||
'--conditional_directives',
|
||||
'--reify-generic-functions',
|
||||
'--strong',
|
||||
'main.dill',
|
||||
]);
|
||||
}, overrides: contextOverrides);
|
||||
|
||||
testUsingContext('builds iOS profile AOT snapshot', () async {
|
||||
fs.file('main.dart').writeAsStringSync('void main() {}');
|
||||
|
||||
final String outputPath = fs.path.join('build', 'foo');
|
||||
fs.directory(outputPath).createSync(recursive: true);
|
||||
|
||||
kernelCompiler.output = const CompilerOutput('main.dill', 0);
|
||||
genSnapshot.outputs = <String, String>{
|
||||
fs.path.join(outputPath, 'snapshot_assembly.S'): '',
|
||||
fs.path.join(outputPath, 'snapshot.d'): '',
|
||||
};
|
||||
|
||||
final int genSnapshotExitCode = await snapshotter.buildAotSnapshot(
|
||||
platform: TargetPlatform.ios,
|
||||
buildMode: BuildMode.profile,
|
||||
mainPath: 'main.dart',
|
||||
depfilePath: fs.path.join(outputPath, 'snapshot.d'),
|
||||
packagesPath: '.packages',
|
||||
outputPath: outputPath,
|
||||
interpreter: false,
|
||||
preferSharedLibrary: false,
|
||||
previewDart2: true,
|
||||
);
|
||||
|
||||
expect(genSnapshotExitCode, 0);
|
||||
expect(genSnapshot.callCount, 1);
|
||||
expect(genSnapshot.snapshotType.platform, TargetPlatform.ios);
|
||||
expect(genSnapshot.snapshotType.mode, BuildMode.profile);
|
||||
expect(genSnapshot.packagesPath, '.packages');
|
||||
expect(genSnapshot.depfilePath, fs.path.join(outputPath, 'snapshot.d'));
|
||||
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')}',
|
||||
'--embedder_entry_points_manifest=$kVmEntrypoints',
|
||||
'--embedder_entry_points_manifest=$kIoEntries',
|
||||
'--snapshot_kind=app-aot-assembly',
|
||||
'--assembly=${fs.path.join(outputPath, 'snapshot_assembly.S')}',
|
||||
'--no-checked',
|
||||
'--conditional_directives',
|
||||
'--reify-generic-functions',
|
||||
'--strong',
|
||||
'main.dill',
|
||||
]);
|
||||
}, overrides: contextOverrides);
|
||||
|
||||
testUsingContext('builds iOS release AOT snapshot', () async {
|
||||
fs.file('main.dart').writeAsStringSync('void main() {}');
|
||||
|
||||
final String outputPath = fs.path.join('build', 'foo');
|
||||
fs.directory(outputPath).createSync(recursive: true);
|
||||
|
||||
kernelCompiler.output = const CompilerOutput('main.dill', 0);
|
||||
genSnapshot.outputs = <String, String>{
|
||||
fs.path.join(outputPath, 'snapshot_assembly.S'): '',
|
||||
fs.path.join(outputPath, 'snapshot.d'): '',
|
||||
};
|
||||
|
||||
final int genSnapshotExitCode = await snapshotter.buildAotSnapshot(
|
||||
platform: TargetPlatform.ios,
|
||||
buildMode: BuildMode.release,
|
||||
mainPath: 'main.dart',
|
||||
depfilePath: fs.path.join(outputPath, 'snapshot.d'),
|
||||
packagesPath: '.packages',
|
||||
outputPath: outputPath,
|
||||
interpreter: false,
|
||||
preferSharedLibrary: false,
|
||||
previewDart2: true,
|
||||
);
|
||||
|
||||
expect(genSnapshotExitCode, 0);
|
||||
expect(genSnapshot.callCount, 1);
|
||||
expect(genSnapshot.snapshotType.platform, TargetPlatform.ios);
|
||||
expect(genSnapshot.snapshotType.mode, BuildMode.release);
|
||||
expect(genSnapshot.packagesPath, '.packages');
|
||||
expect(genSnapshot.depfilePath, fs.path.join(outputPath, 'snapshot.d'));
|
||||
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')}',
|
||||
'--embedder_entry_points_manifest=$kVmEntrypoints',
|
||||
'--embedder_entry_points_manifest=$kIoEntries',
|
||||
'--snapshot_kind=app-aot-assembly',
|
||||
'--assembly=${fs.path.join(outputPath, 'snapshot_assembly.S')}',
|
||||
'--reify-generic-functions',
|
||||
'--strong',
|
||||
'main.dill',
|
||||
]);
|
||||
}, overrides: contextOverrides);
|
||||
});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user