| // Copyright 2014 The Flutter 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 'package:meta/meta.dart'; |
| |
| import 'base/common.dart'; |
| import 'base/logger.dart'; |
| import 'build_info.dart'; |
| import 'build_system/build_system.dart'; |
| import 'build_system/targets/common.dart'; |
| import 'build_system/targets/icon_tree_shaker.dart'; |
| import 'build_system/targets/ios.dart'; |
| import 'cache.dart'; |
| import 'globals.dart' as globals; |
| import 'ios/bitcode.dart'; |
| import 'macos/xcode.dart'; |
| import 'project.dart'; |
| |
| /// Builds AOT snapshots given a platform, build mode and a path to a Dart |
| /// library. |
| class AotBuilder { |
| Future<void> build({ |
| @required TargetPlatform platform, |
| @required String outputPath, |
| @required BuildInfo buildInfo, |
| @required String mainDartFile, |
| bool bitcode = kBitcodeEnabledDefault, |
| bool quiet = true, |
| Iterable<DarwinArch> iosBuildArchs, |
| bool reportTimings = false, |
| }) async { |
| if (platform == null) { |
| throwToolExit('No AOT build platform specified'); |
| } |
| iosBuildArchs ??= defaultIOSArchsForSdk(SdkType.iPhone); |
| Target target; |
| bool expectSo = false; |
| switch (platform) { |
| case TargetPlatform.android: |
| case TargetPlatform.darwin_x64: |
| case TargetPlatform.linux_x64: |
| case TargetPlatform.windows_x64: |
| case TargetPlatform.fuchsia_arm64: |
| case TargetPlatform.tester: |
| case TargetPlatform.web_javascript: |
| case TargetPlatform.android_x86: |
| throwToolExit('$platform is not supported in AOT.'); |
| break; |
| case TargetPlatform.fuchsia_x64: |
| throwToolExit( |
| "To build release for fuchsia, use 'flutter build fuchsia --release'" |
| ); |
| break; |
| case TargetPlatform.ios: |
| target = buildInfo.isRelease |
| ? const AotAssemblyRelease() |
| : const AotAssemblyProfile(); |
| break; |
| case TargetPlatform.android_arm: |
| case TargetPlatform.android_arm64: |
| case TargetPlatform.android_x64: |
| expectSo = true; |
| target = buildInfo.isRelease |
| ? const AotElfRelease(TargetPlatform.android_arm) |
| : const AotElfProfile(TargetPlatform.android_arm); |
| } |
| |
| Status status; |
| if (!quiet) { |
| final String typeName = globals.artifacts.getEngineType(platform, buildInfo.mode); |
| status = globals.logger.startProgress( |
| 'Building AOT snapshot in ${getFriendlyModeName(buildInfo.mode)} mode ($typeName)...', |
| ); |
| } |
| |
| final Environment environment = Environment( |
| projectDir: globals.fs.currentDirectory, |
| outputDir: globals.fs.directory(outputPath), |
| buildDir: FlutterProject.current().dartTool.childDirectory('flutter_build'), |
| cacheDir: null, |
| flutterRootDir: globals.fs.directory(Cache.flutterRoot), |
| engineVersion: globals.artifacts.isLocalEngine |
| ? null |
| : globals.flutterVersion.engineRevision, |
| defines: <String, String>{ |
| kTargetFile: mainDartFile ?? globals.fs.path.join('lib', 'main.dart'), |
| kBuildMode: getNameForBuildMode(buildInfo.mode), |
| kTargetPlatform: getNameForTargetPlatform(platform), |
| kIconTreeShakerFlag: buildInfo.treeShakeIcons.toString(), |
| kDartDefines: buildInfo.dartDefines.join(','), |
| kBitcodeFlag: bitcode.toString(), |
| if (buildInfo?.extraGenSnapshotOptions?.isNotEmpty ?? false) |
| kExtraGenSnapshotOptions: buildInfo.extraGenSnapshotOptions.join(','), |
| if (buildInfo?.extraFrontEndOptions?.isNotEmpty ?? false) |
| kExtraFrontEndOptions: buildInfo.extraFrontEndOptions.join(','), |
| if (platform == TargetPlatform.ios) |
| kIosArchs: iosBuildArchs.map(getNameForDarwinArch).join(' ') |
| }, |
| artifacts: globals.artifacts, |
| fileSystem: globals.fs, |
| logger: globals.logger, |
| processManager: globals.processManager, |
| ); |
| final BuildResult result = await globals.buildSystem.build(target, environment); |
| status?.stop(); |
| |
| if (!result.success) { |
| for (final ExceptionMeasurement measurement in result.exceptions.values) { |
| globals.printError(measurement.exception.toString()); |
| } |
| throwToolExit('The aot build failed.'); |
| } |
| |
| // This print output is used by the dart team for build benchmarks. |
| if (reportTimings) { |
| final PerformanceMeasurement kernel = result.performance['kernel_snapshot']; |
| PerformanceMeasurement aot; |
| if (expectSo) { |
| aot = result.performance.values.firstWhere( |
| (PerformanceMeasurement measurement) => measurement.analyticsName == 'android_aot'); |
| } else { |
| aot = result.performance.values.firstWhere( |
| (PerformanceMeasurement measurement) => measurement.analyticsName == 'ios_aot'); |
| } |
| globals.printStatus('frontend(CompileTime): ${kernel.elapsedMilliseconds} ms.'); |
| globals.printStatus('snapshot(CompileTime): ${aot.elapsedMilliseconds} ms.'); |
| } |
| |
| if (expectSo) { |
| environment.buildDir.childFile('app.so') |
| .copySync(globals.fs.path.join(outputPath, 'app.so')); |
| } else { |
| globals.fs.directory(globals.fs.path.join(outputPath, 'App.framework')) |
| .createSync(recursive: true); |
| environment.buildDir.childDirectory('App.framework').childFile('App') |
| .copySync(globals.fs.path.join(outputPath, 'App.framework', 'App')); |
| } |
| |
| final String builtMessage = 'Built to $outputPath${globals.fs.path.separator}.'; |
| if (quiet) { |
| globals.printTrace(builtMessage); |
| } else { |
| globals.printStatus(builtMessage); |
| } |
| return; |
| } |
| } |