
Disallow calling stop() or cancel() multiple times. This means that when you use startProgress you have to more carefully think about what exactly is going on. Properly cancel startProgress in non-ANSI situations, so that back-to-back startProgress calls all render to the console.
181 lines
6.4 KiB
Dart
181 lines
6.4 KiB
Dart
// Copyright 2016 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
import 'dart:async';
|
|
|
|
import '../base/build.dart';
|
|
import '../base/common.dart';
|
|
import '../base/file_system.dart';
|
|
import '../base/logger.dart';
|
|
import '../base/process.dart';
|
|
import '../build_info.dart';
|
|
import '../dart/package_map.dart';
|
|
import '../globals.dart';
|
|
import '../resident_runner.dart';
|
|
import '../runner/flutter_command.dart';
|
|
import 'build.dart';
|
|
|
|
class BuildAotCommand extends BuildSubCommand {
|
|
BuildAotCommand({bool verboseHelp = false}) {
|
|
usesTargetOption();
|
|
addBuildModeFlags();
|
|
usesPubOption();
|
|
argParser
|
|
..addOption('output-dir', defaultsTo: getAotBuildDirectory())
|
|
..addOption('target-platform',
|
|
defaultsTo: 'android-arm',
|
|
allowed: <String>['android-arm', 'android-arm64', 'ios']
|
|
)
|
|
..addFlag('quiet', defaultsTo: false)
|
|
..addFlag('preview-dart-2',
|
|
defaultsTo: true,
|
|
hide: !verboseHelp,
|
|
help: 'Preview Dart 2.0 functionality.',
|
|
)
|
|
..addFlag('build-shared-library',
|
|
negatable: false,
|
|
defaultsTo: false,
|
|
help: 'Compile to a *.so file (requires NDK when building for Android).'
|
|
)
|
|
..addMultiOption('ios-arch',
|
|
splitCommas: true,
|
|
defaultsTo: defaultIOSArchs.map(getNameForIOSArch),
|
|
allowed: IOSArch.values.map(getNameForIOSArch),
|
|
help: 'iOS architectures to build.',
|
|
)
|
|
..addMultiOption(FlutterOptions.kExtraFrontEndOptions,
|
|
splitCommas: true,
|
|
hide: true,
|
|
)
|
|
..addMultiOption(FlutterOptions.kExtraGenSnapshotOptions,
|
|
splitCommas: true,
|
|
hide: true,
|
|
);
|
|
}
|
|
|
|
@override
|
|
final String name = 'aot';
|
|
|
|
@override
|
|
final String description = "Build an ahead-of-time compiled snapshot of your app's Dart code.";
|
|
|
|
@override
|
|
Future<Null> runCommand() async {
|
|
await super.runCommand();
|
|
|
|
final String targetPlatform = argResults['target-platform'];
|
|
final TargetPlatform platform = getTargetPlatformForName(targetPlatform);
|
|
if (platform == null)
|
|
throwToolExit('Unknown platform: $targetPlatform');
|
|
|
|
final BuildMode buildMode = getBuildMode();
|
|
|
|
Status status;
|
|
if (!argResults['quiet']) {
|
|
final String typeName = artifacts.getEngineType(platform, buildMode);
|
|
status = logger.startProgress(
|
|
'Building AOT snapshot in ${getModeName(getBuildMode())} mode ($typeName)...',
|
|
expectSlowOperation: true,
|
|
);
|
|
}
|
|
final String outputPath = argResults['output-dir'] ?? getAotBuildDirectory();
|
|
try {
|
|
final bool previewDart2 = argResults['preview-dart-2'];
|
|
String mainPath = findMainDartFile(targetFile);
|
|
final AOTSnapshotter snapshotter = new AOTSnapshotter();
|
|
|
|
// Compile to kernel, if Dart 2.
|
|
if (previewDart2) {
|
|
mainPath = await snapshotter.compileKernel(
|
|
platform: platform,
|
|
buildMode: buildMode,
|
|
mainPath: mainPath,
|
|
outputPath: outputPath,
|
|
extraFrontEndOptions: argResults[FlutterOptions.kExtraFrontEndOptions],
|
|
);
|
|
if (mainPath == null) {
|
|
throwToolExit('Compiler terminated unexpectedly.');
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Build AOT snapshot.
|
|
if (platform == TargetPlatform.ios) {
|
|
// Determine which iOS architectures to build for.
|
|
final Iterable<IOSArch> buildArchs = argResults['ios-arch'].map<IOSArch>(getIOSArchForName);
|
|
final Map<IOSArch, String> iosBuilds = <IOSArch, String>{};
|
|
for (IOSArch arch in buildArchs)
|
|
iosBuilds[arch] = fs.path.join(outputPath, getNameForIOSArch(arch));
|
|
|
|
// Generate AOT snapshot and compile to arch-specific App.framework.
|
|
final Map<IOSArch, Future<int>> exitCodes = <IOSArch, Future<int>>{};
|
|
iosBuilds.forEach((IOSArch iosArch, String outputPath) {
|
|
exitCodes[iosArch] = snapshotter.build(
|
|
platform: platform,
|
|
iosArch: iosArch,
|
|
buildMode: buildMode,
|
|
mainPath: mainPath,
|
|
packagesPath: PackageMap.globalPackagesPath,
|
|
outputPath: outputPath,
|
|
previewDart2: previewDart2,
|
|
buildSharedLibrary: false,
|
|
extraGenSnapshotOptions: argResults[FlutterOptions.kExtraGenSnapshotOptions],
|
|
).then((int buildExitCode) {
|
|
return buildExitCode;
|
|
});
|
|
});
|
|
|
|
// Merge arch-specific App.frameworks into a multi-arch App.framework.
|
|
if ((await Future.wait(exitCodes.values)).every((int buildExitCode) => buildExitCode == 0)) {
|
|
final Iterable<String> dylibs = iosBuilds.values.map((String outputDir) => fs.path.join(outputDir, 'App.framework', 'App'));
|
|
fs.directory(fs.path.join(outputPath, 'App.framework'))..createSync();
|
|
await runCheckedAsync(<String>['lipo']
|
|
..addAll(dylibs)
|
|
..addAll(<String>['-create', '-output', fs.path.join(outputPath, 'App.framework', 'App')]),
|
|
);
|
|
} else {
|
|
status?.cancel();
|
|
exitCodes.forEach((IOSArch iosArch, Future<int> exitCodeFuture) async {
|
|
final int buildExitCode = await exitCodeFuture;
|
|
printError('Snapshotting ($iosArch) exited with non-zero exit code: $buildExitCode');
|
|
});
|
|
}
|
|
} else {
|
|
// Android AOT snapshot.
|
|
final int snapshotExitCode = await snapshotter.build(
|
|
platform: platform,
|
|
buildMode: buildMode,
|
|
mainPath: mainPath,
|
|
packagesPath: PackageMap.globalPackagesPath,
|
|
outputPath: outputPath,
|
|
previewDart2: previewDart2,
|
|
buildSharedLibrary: argResults['build-shared-library'],
|
|
extraGenSnapshotOptions: argResults[FlutterOptions.kExtraGenSnapshotOptions],
|
|
);
|
|
if (snapshotExitCode != 0) {
|
|
status?.cancel();
|
|
printError('Snapshotting exited with non-zero exit code: $snapshotExitCode');
|
|
return;
|
|
}
|
|
}
|
|
} on String catch (error) {
|
|
// Catch the String exceptions thrown from the `runCheckedSync` methods below.
|
|
status?.cancel();
|
|
printError(error);
|
|
return;
|
|
}
|
|
status?.stop();
|
|
|
|
if (outputPath == null)
|
|
throwToolExit(null);
|
|
|
|
final String builtMessage = 'Built to $outputPath${fs.path.separator}.';
|
|
if (argResults['quiet']) {
|
|
printTrace(builtMessage);
|
|
} else {
|
|
printStatus(builtMessage);
|
|
}
|
|
}
|
|
}
|