| // Copyright 2019 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 '../../artifacts.dart'; |
| import '../../base/build.dart'; |
| import '../../base/file_system.dart'; |
| import '../../base/platform.dart'; |
| import '../../build_info.dart'; |
| import '../../compile.dart'; |
| import '../../dart/package_map.dart'; |
| import '../../globals.dart'; |
| import '../../project.dart'; |
| import '../build_system.dart'; |
| import '../exceptions.dart'; |
| |
| /// The define to pass a [BuildMode]. |
| const String kBuildMode= 'BuildMode'; |
| |
| /// The define to pass whether we compile 64-bit android-arm code. |
| const String kTargetPlatform = 'TargetPlatform'; |
| |
| /// The define to control what target file is used. |
| const String kTargetFile = 'TargetFile'; |
| |
| /// The define to control whether the AOT snapshot is built with bitcode. |
| const String kBitcodeFlag = 'EnableBitcode'; |
| |
| /// The define to control what iOS architectures are built for. |
| /// |
| /// This is expected to be a comma-separated list of architectures. If not |
| /// provided, defaults to arm64. |
| /// |
| /// The other supported value is armv7, the 32-bit iOS architecture. |
| const String kIosArchs = 'IosArchs'; |
| |
| /// Finds the locations of all dart files within the project. |
| /// |
| /// This does not attempt to determine if a file is used or imported, so it |
| /// may otherwise report more files than strictly necessary. |
| List<File> listDartSources(Environment environment) { |
| final Map<String, Uri> packageMap = PackageMap(environment.projectDir.childFile('.packages').path).map; |
| final List<File> dartFiles = <File>[]; |
| for (Uri uri in packageMap.values) { |
| final Directory libDirectory = fs.directory(uri.toFilePath(windows: platform.isWindows)); |
| if (!libDirectory.existsSync()) { |
| continue; |
| } |
| for (FileSystemEntity entity in libDirectory.listSync(recursive: true)) { |
| if (entity is File && entity.path.endsWith('.dart')) { |
| dartFiles.add(entity); |
| } |
| } |
| } |
| return dartFiles; |
| } |
| |
| /// Generate a snapshot of the dart code used in the program. |
| class KernelSnapshot extends Target { |
| const KernelSnapshot(); |
| |
| @override |
| String get name => 'kernel_snapshot'; |
| |
| @override |
| List<Source> get inputs => const <Source>[ |
| Source.pattern('{PROJECT_DIR}/.packages'), |
| Source.pattern('{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/dart.dart'), |
| Source.function(listDartSources), // <- every dart file under {PROJECT_DIR}/lib and in .packages |
| Source.artifact(Artifact.platformKernelDill), |
| Source.artifact(Artifact.engineDartBinary), |
| Source.artifact(Artifact.frontendServerSnapshotForEngineDartSdk), |
| ]; |
| |
| @override |
| List<Source> get outputs => const <Source>[ |
| Source.pattern('{BUILD_DIR}/app.dill'), |
| ]; |
| |
| @override |
| List<Target> get dependencies => <Target>[]; |
| |
| @override |
| Future<void> build(List<File> inputFiles, Environment environment) async { |
| final KernelCompiler compiler = await kernelCompilerFactory.create( |
| FlutterProject.fromDirectory(environment.projectDir), |
| ); |
| if (environment.defines[kBuildMode] == null) { |
| throw MissingDefineException(kBuildMode, 'kernel_snapshot'); |
| } |
| final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]); |
| final String targetFile = environment.defines[kTargetFile] ?? fs.path.join('lib', 'main.dart'); |
| final String packagesPath = environment.projectDir.childFile('.packages').path; |
| final PackageUriMapper packageUriMapper = PackageUriMapper(targetFile, |
| packagesPath, null, null); |
| |
| final CompilerOutput output = await compiler.compile( |
| sdkRoot: artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath, mode: buildMode), |
| aot: buildMode != BuildMode.debug, |
| trackWidgetCreation: buildMode == BuildMode.debug, |
| targetModel: TargetModel.flutter, |
| targetProductVm: buildMode == BuildMode.release, |
| outputFilePath: environment.buildDir.childFile('app.dill').path, |
| depFilePath: null, |
| packagesPath: packagesPath, |
| linkPlatformKernelIn: buildMode == BuildMode.release, |
| mainPath: packageUriMapper.map(targetFile)?.toString() ?? targetFile, |
| ); |
| if (output.errorCount != 0) { |
| throw Exception('Errors during snapshot creation: $output'); |
| } |
| } |
| } |
| |
| |
| /// Supports compiling a dart kernel file to an ELF binary. |
| abstract class AotElfBase extends Target { |
| const AotElfBase(); |
| |
| @override |
| Future<void> build(List<File> inputFiles, Environment environment) async { |
| final AOTSnapshotter snapshotter = AOTSnapshotter(reportTimings: false); |
| final String outputPath = environment.buildDir.path; |
| if (environment.defines[kBuildMode] == null) { |
| throw MissingDefineException(kBuildMode, 'aot_elf'); |
| } |
| if (environment.defines[kTargetPlatform] == null) { |
| throw MissingDefineException(kTargetPlatform, 'aot_elf'); |
| } |
| final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]); |
| final TargetPlatform targetPlatform = getTargetPlatformForName(environment.defines[kTargetPlatform]); |
| final int snapshotExitCode = await snapshotter.build( |
| platform: targetPlatform, |
| buildMode: buildMode, |
| mainPath: environment.buildDir.childFile('app.dill').path, |
| packagesPath: environment.projectDir.childFile('.packages').path, |
| outputPath: outputPath, |
| bitcode: false, |
| ); |
| if (snapshotExitCode != 0) { |
| throw Exception('AOT snapshotter exited with code $snapshotExitCode'); |
| } |
| } |
| } |
| |
| /// Generate an ELF binary from a dart kernel file in profile mode. |
| class AotElfProfile extends AotElfBase { |
| const AotElfProfile(); |
| |
| @override |
| String get name => 'aot_elf_profile'; |
| |
| @override |
| List<Source> get inputs => const <Source>[ |
| Source.pattern('{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/dart.dart'), |
| Source.pattern('{BUILD_DIR}/app.dill'), |
| Source.pattern('{PROJECT_DIR}/.packages'), |
| Source.artifact(Artifact.engineDartBinary), |
| Source.artifact(Artifact.skyEnginePath), |
| Source.artifact(Artifact.genSnapshot, |
| platform: TargetPlatform.android_arm, |
| mode: BuildMode.profile, |
| ), |
| ]; |
| |
| @override |
| List<Source> get outputs => const <Source>[ |
| Source.pattern('{BUILD_DIR}/app.so'), |
| ]; |
| |
| @override |
| List<Target> get dependencies => const <Target>[ |
| KernelSnapshot(), |
| ]; |
| } |
| |
| /// Generate an ELF binary from a dart kernel file in release mode. |
| class AotElfRelease extends AotElfBase { |
| const AotElfRelease(); |
| |
| @override |
| String get name => 'aot_elf_release'; |
| |
| @override |
| List<Source> get inputs => const <Source>[ |
| Source.pattern('{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/dart.dart'), |
| Source.pattern('{BUILD_DIR}/app.dill'), |
| Source.pattern('{PROJECT_DIR}/.packages'), |
| Source.artifact(Artifact.engineDartBinary), |
| Source.artifact(Artifact.skyEnginePath), |
| Source.artifact(Artifact.genSnapshot, |
| platform: TargetPlatform.android_arm, |
| mode: BuildMode.release, |
| ), |
| ]; |
| |
| @override |
| List<Source> get outputs => const <Source>[ |
| Source.pattern('{BUILD_DIR}/app.so'), |
| ]; |
| |
| @override |
| List<Target> get dependencies => const <Target>[ |
| KernelSnapshot(), |
| ]; |
| } |