blob: e8222409251b7ad1987d134a2bfc11031afb7cfb [file] [log] [blame]
// 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/io.dart';
import '../../base/process_manager.dart';
import '../../build_info.dart';
import '../build_system.dart';
import '../exceptions.dart';
import 'dart.dart';
/// Supports compiling a dart kernel file to an assembly file.
///
/// If more than one iOS arch is provided, then this rule will
/// produce a univeral binary.
abstract class AotAssemblyBase extends Target {
const AotAssemblyBase();
@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_assembly');
}
if (environment.defines[kTargetPlatform] == null) {
throw MissingDefineException(kTargetPlatform, 'aot_assembly');
}
final bool bitcode = environment.defines[kBitcodeFlag] == 'true';
final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]);
final TargetPlatform targetPlatform = getTargetPlatformForName(environment.defines[kTargetPlatform]);
final List<DarwinArch> iosArchs = environment.defines[kIosArchs]?.split(',')?.map(getIOSArchForName)?.toList()
?? <DarwinArch>[DarwinArch.arm64];
if (targetPlatform != TargetPlatform.ios) {
throw Exception('aot_assembly is only supported for iOS applications');
}
// If we're building for a single architecture (common), then skip the lipo.
if (iosArchs.length == 1) {
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,
darwinArch: iosArchs.single,
bitcode: bitcode,
);
if (snapshotExitCode != 0) {
throw Exception('AOT snapshotter exited with code $snapshotExitCode');
}
} else {
// If we're building multiple iOS archs the binaries need to be lipo'd
// together.
final List<Future<int>> pending = <Future<int>>[];
for (DarwinArch iosArch in iosArchs) {
pending.add(snapshotter.build(
platform: targetPlatform,
buildMode: buildMode,
mainPath: environment.buildDir.childFile('app.dill').path,
packagesPath: environment.projectDir.childFile('.packages').path,
outputPath: fs.path.join(outputPath, getNameForDarwinArch(iosArch)),
darwinArch: iosArch,
bitcode: bitcode,
));
}
final List<int> results = await Future.wait(pending);
if (results.any((int result) => result != 0)) {
throw Exception('AOT snapshotter exited with code ${results.join()}');
}
final ProcessResult result = await processManager.run(<String>[
'lipo',
...iosArchs.map((DarwinArch iosArch) =>
fs.path.join(outputPath, getNameForDarwinArch(iosArch), 'App.framework', 'App')),
'-create',
'-output',
fs.path.join(outputPath, 'App.framework', 'App'),
]);
if (result.exitCode != 0) {
throw Exception('lipo exited with code ${result.exitCode}');
}
}
}
}
/// Generate an assembly target from a dart kernel file in release mode.
class AotAssemblyRelease extends AotAssemblyBase {
const AotAssemblyRelease();
@override
String get name => 'aot_assembly_release';
@override
List<Source> get inputs => const <Source>[
Source.pattern('{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/ios.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.ios,
mode: BuildMode.release,
),
];
@override
List<Source> get outputs => const <Source>[
Source.pattern('{BUILD_DIR}/App.framework/App'),
];
@override
List<Target> get dependencies => const <Target>[
KernelSnapshot(),
];
}
/// Generate an assembly target from a dart kernel file in profile mode.
class AotAssemblyProfile extends AotAssemblyBase {
const AotAssemblyProfile();
@override
String get name => 'aot_assembly_profile';
@override
List<Source> get inputs => const <Source>[
Source.pattern('{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/ios.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.ios,
mode: BuildMode.profile,
),
];
@override
List<Source> get outputs => const <Source>[
Source.pattern('{BUILD_DIR}/App.framework/App'),
];
@override
List<Target> get dependencies => const <Target>[
KernelSnapshot(),
];
}