blob: 00b801b2c204f4a0cdecace2803ec78bf1963baa [file] [log] [blame]
# Copyright 2013 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.
# This file has rules for making Dart packages and snapshots.
import("//build/compiled_action.gni")
import("//build/module_args/dart.gni")
import("//flutter/common/config.gni")
import("//third_party/dart/build/dart/dart_action.gni")
import("//third_party/dart/sdk_args.gni")
frontend_server_files =
exec_script("//third_party/dart/tools/list_dart_files.py",
[
"absolute",
rebase_path("//flutter/flutter_frontend_server"),
],
"list lines")
frontend_server_files +=
exec_script("//third_party/dart/tools/list_dart_files.py",
[
"absolute",
rebase_path("//third_party/dart/pkg"),
],
"list lines")
# Creates a dart kernel (dill) file suitable for use with gen_snapshot, as well
# as the app-jit, aot-elf, or aot-assembly snapshot for targeting Flutter on
# Android or iOS.
#
# Invoker must supply dart_main and package_config. Invoker may optionally
# supply aot as a boolean and product as a boolean.
#
# On Android, the invoker may provide output_aot_lib as a string to override
# the default filename for the aot-elf snapshot.
template("flutter_snapshot") {
assert(!is_fuchsia)
assert(defined(invoker.main_dart), "main_dart is a required parameter.")
assert(defined(invoker.package_config),
"package_config is a required parameter.")
kernel_target = "_${target_name}_kernel"
snapshot_target = "_${target_name}_snapshot"
is_aot =
flutter_runtime_mode == "profile" || flutter_runtime_mode == "release"
kernel_output = "$target_gen_dir/kernel_blob.bin"
prebuilt_dart_action(kernel_target) {
script = "//flutter/flutter_frontend_server/bin/starter.dart"
main_dart = rebase_path(invoker.main_dart)
package_config = rebase_path(invoker.package_config)
flutter_patched_sdk = rebase_path("$root_out_dir/flutter_patched_sdk")
deps = [ "//flutter/lib/snapshot:strong_platform" ]
inputs = [
main_dart,
package_config,
] + frontend_server_files
outputs = [ kernel_output ]
depfile = "$kernel_output.d"
abs_depfile = rebase_path(depfile)
vm_args = [ "--disable-dart-dev" ]
args = [
"--depfile=$abs_depfile",
"--packages=" + rebase_path(package_config),
"--target=flutter",
"--sdk-root=" + flutter_patched_sdk,
"--output-dill=" + rebase_path(kernel_output, root_build_dir),
]
if (is_aot) {
args += [
"--aot",
"--tfa",
]
} else {
# --no-link-platform is only valid when --aot isn't specified
args += [ "--no-link-platform" ]
}
if (defined(invoker.product) && invoker.product) {
# Setting this flag in a non-product release build for AOT (a "profile"
# build) causes the vm service isolate code to be tree-shaken from an app.
# See the pragma on the entrypoint here:
#
# https://github.com/dart-lang/sdk/blob/main/sdk/lib/_internal/vm/bin/vmservice_io.dart#L240
#
# Also, this define excludes debugging and profiling code from Flutter.
args += [ "-Ddart.vm.product=true" ]
} else {
if (flutter_runtime_mode == "profile") {
# The following define excludes debugging code from Flutter.
args += [ "-Ddart.vm.profile=true" ]
}
}
args += [ rebase_path(main_dart) ]
}
compiled_action(snapshot_target) {
if (target_cpu == "x86" && host_os == "linux") {
# By default Dart will create a 32-bit gen_snapshot host binary if the target
# platform is 32-bit. Override this to create a 64-bit gen_snapshot for x86
# targets because some host platforms may not support 32-bit binaries.
tool = "//third_party/dart/runtime/bin:gen_snapshot_host_targeting_host"
toolchain = "//build/toolchain/$host_os:clang_x64"
} else {
tool = "//third_party/dart/runtime/bin:gen_snapshot"
}
inputs = [ kernel_output ]
deps = [ ":$kernel_target" ]
outputs = []
args = []
if (is_debug && flutter_runtime_mode != "profile" &&
flutter_runtime_mode != "release" &&
flutter_runtime_mode != "jit_release") {
args += [ "--enable_asserts" ]
}
if (is_aot) {
args += [ "--deterministic" ]
if (is_ios) {
snapshot_assembly = "$target_gen_dir/ios/snapshot_assembly.S"
outputs += [ snapshot_assembly ]
args += [
"--snapshot_kind=app-aot-assembly",
"--assembly=" + rebase_path(snapshot_assembly),
]
} else if (is_android) {
if (defined(invoker.output_aot_lib)) {
output_aot_lib = invoker.output_aot_lib
} else {
output_aot_lib = "libapp.so"
}
libapp = "$target_gen_dir/android/libs/$android_app_abi/$output_aot_lib"
outputs += [ libapp ]
args += [
"--snapshot_kind=app-aot-elf",
"--elf=" + rebase_path(libapp),
]
} else {
assert(false)
}
} else {
deps += [ "//flutter/lib/snapshot:generate_snapshot_bin" ]
vm_snapshot_data =
"$root_gen_dir/flutter/lib/snapshot/vm_isolate_snapshot.bin"
snapshot_data = "$root_gen_dir/flutter/lib/snapshot/isolate_snapshot.bin"
isolate_snapshot_data = "$target_gen_dir/isolate_snapshot_data"
isolate_snapshot_instructions = "$target_gen_dir/isolate_snapshot_instr"
inputs += [
vm_snapshot_data,
snapshot_data,
]
outputs += [
isolate_snapshot_data,
isolate_snapshot_instructions,
]
args += [
"--snapshot_kind=app-jit",
"--load_vm_snapshot_data=" + rebase_path(vm_snapshot_data),
"--load_isolate_snapshot_data=" + rebase_path(snapshot_data),
"--isolate_snapshot_data=" + rebase_path(isolate_snapshot_data),
"--isolate_snapshot_instructions=" +
rebase_path(isolate_snapshot_instructions),
]
}
args += [ rebase_path(kernel_output) ]
}
group(target_name) {
public_deps = [
":$kernel_target",
":$snapshot_target",
]
}
}
# Creates an app-jit snapshot for a command-line Dart program based on a
# training run.
#
# Parameters:
# main_dart (required):
# The entrypoint to the Dart application.
#
# training_args (required):
# Arguments to pass to the Dart application for the training run.
#
# vm_args (optional):
# Additional arguments to the Dart VM.
#
# deps (optional):
# Any build dependencies.
#
# package_config (required):
# The .packages file for the app. Defaults to the $_dart_root/.packages.
#
# output (optional):
# Overrides the full output path.
#
# snapshot_kind (optional)
# Either an "app-jit" snapshot (default) or a "kernel" snapshot
template("application_snapshot") {
assert(defined(invoker.main_dart), "Must specify 'main_dart'")
assert(defined(invoker.training_args), "Must specify 'training_args'")
assert(defined(invoker.package_config), "Must specify 'package_config'")
main_dart = invoker.main_dart
training_args = invoker.training_args
package_config = rebase_path(invoker.package_config)
name = target_name
extra_deps = []
if (defined(invoker.deps)) {
extra_deps += invoker.deps
}
extra_inputs = [ main_dart ]
if (defined(invoker.inputs)) {
extra_inputs += invoker.inputs
}
output = "$root_gen_dir/$name.dart.snapshot"
if (defined(invoker.output)) {
output = invoker.output
}
depfile = output + ".d"
abs_depfile = rebase_path(depfile)
abs_output = rebase_path(output)
rel_output = rebase_path(output, root_build_dir)
snapshot_vm_args = [
"--disable-dart-dev",
"--deterministic",
"--packages=$package_config",
"--snapshot=$abs_output",
"--snapshot-depfile=$abs_depfile",
"--depfile-output-filename=$rel_output",
]
if (defined(invoker.vm_args)) {
snapshot_vm_args += invoker.vm_args
}
snapshot_kind = "app-jit"
if (target_cpu != host_cpu) {
snapshot_kind = "kernel"
}
if (defined(invoker.snapshot_kind)) {
snapshot_kind = invoker.snapshot_kind
}
if (snapshot_kind == "kernel") {
snapshot_vm_args += [ "--snapshot-kind=kernel" ]
} else if (snapshot_kind == "app-jit") {
snapshot_vm_args += [ "--snapshot-kind=app-jit" ]
} else {
assert(false, "Bad snapshot_kind: '$snapshot_kind'")
}
# Ensure the compiled appliation (e.g. frontend-server, ...) will use this
# Dart SDK hash when consuming/producing kernel.
#
# (Instead of ensuring every user of the "application_snapshot" passes it's
# own)
snapshot_vm_args += [ "-Dsdk_hash=$sdk_hash" ]
if (flutter_prebuilt_dart_sdk) {
action(target_name) {
forward_variables_from(invoker,
[
"testonly",
"visibility",
])
deps = extra_deps
script = "//build/gn_run_binary.py"
inputs = extra_inputs
outputs = [ output ]
depfile = depfile
pool = "//flutter/build/dart:dart_pool"
ext = ""
if (is_win) {
ext = ".exe"
}
dart = rebase_path("$host_prebuilt_dart_sdk/bin/dart$ext", root_build_dir)
args = [ dart ]
args += snapshot_vm_args
args += [ rebase_path(main_dart) ]
args += training_args
}
} else {
dart_action(target_name) {
forward_variables_from(invoker,
[
"testonly",
"visibility",
])
script = main_dart
pool = "//flutter/build/dart:dart_pool"
deps = extra_deps
inputs = extra_inputs
outputs = [ output ]
depfile = depfile
vm_args = snapshot_vm_args
args = training_args
}
}
}
template("_dart_pkg_helper") {
assert(defined(invoker.package_name))
package_name = invoker.package_name
pkg_directory = rebase_path("$root_gen_dir/dart-pkg")
package_root = rebase_path("$root_gen_dir/dart-pkg/packages")
stamp_file = "$root_gen_dir/dart-pkg/${package_name}.stamp"
entries_file = "$root_gen_dir/dart-pkg/${package_name}.entries"
assert(defined(invoker.sources) || defined(invoker.apps) ||
defined(invoker.libs) || defined(invoker.pkg_dir))
action(target_name) {
deps = []
if (defined(invoker.deps)) {
deps += invoker.deps
}
datadeps = []
if (defined(invoker.datadeps)) {
datadeps += invoker.datadeps
}
sdk_ext_directory = []
if (defined(invoker.sdk_ext_directory)) {
sdk_ext_directory += [ invoker.sdk_ext_directory ]
}
sdk_ext_files = []
if (defined(invoker.sdk_ext_files)) {
sdk_ext_files += invoker.sdk_ext_files
}
sdk_ext_mappings = []
if (defined(invoker.sdk_ext_mappings)) {
sdk_ext_mappings += invoker.sdk_ext_mappings
}
script = rebase_path("//flutter/build/dart/tools/dart_pkg.py", ".", "//")
entrypoints = []
if (defined(invoker.apps)) {
foreach(app, invoker.apps) {
entrypoints += [ app[1] ]
}
}
if (defined(invoker.libs)) {
entrypoints += invoker.libs
}
sources = entrypoints
extra_flags = []
if (defined(invoker.sources)) {
sources += invoker.sources
} else if (defined(invoker.pkg_dir)) {
list_script = rebase_path("//flutter/build/dart/tools/ls.py", ".", "//")
extra_flags += [ "--read_only" ]
ls_sources = exec_script(list_script,
[
"--target-directory",
rebase_path(invoker.pkg_dir),
],
"list lines")
sources += ls_sources
}
# We have to use foreach to set up outputs instead of rebase_path because
# GN doesn't like assignments to outputs that aren't obviously under
# $root_gen_dir somewhere.
outputs = [
"$root_gen_dir/dart-pkg/${package_name}",
"$root_gen_dir/dart-pkg/${package_name}/pubspec.yaml",
"$root_gen_dir/dart-pkg/packages/${package_name}",
stamp_file,
]
inputs = [ script ] + rebase_path(sources)
args = [
"--package-name",
package_name,
"--dart-sdk",
rebase_path(dart_sdk_root),
"--pkg-directory",
pkg_directory,
"--package-root",
package_root,
"--stamp-file",
rebase_path(stamp_file),
"--entries-file",
rebase_path(entries_file),
"--package-sources",
] + rebase_path(sources) + [ "--package-entrypoints" ] +
rebase_path(entrypoints) + [ "--sdk-ext-directories" ] +
rebase_path(sdk_ext_directory) + [ "--sdk-ext-files" ] +
rebase_path(sdk_ext_files) + [ "--sdk-ext-mappings" ] +
sdk_ext_mappings + extra_flags
}
}
template("dart_pkg") {
if (defined(invoker.pkg_dir)) {
pubspec_yaml_path = rebase_path("pubspec.yaml", "", invoker.pkg_dir)
} else {
pubspec_yaml_path = rebase_path("pubspec.yaml")
}
dart_package_name_script =
rebase_path("//flutter/build/dart/tools/dart_package_name.py", ".", "//")
dart_package_name = exec_script(dart_package_name_script,
[
"--pubspec",
pubspec_yaml_path,
],
"trim string",
[ pubspec_yaml_path ])
dart_pkg_target_name = "${target_name}_pkg_helper"
_dart_pkg_helper(dart_pkg_target_name) {
package_name = dart_package_name
if (defined(invoker.sources)) {
sources = invoker.sources
}
if (defined(invoker.apps)) {
apps = invoker.apps
}
if (defined(invoker.libs)) {
libs = invoker.libs
}
if (defined(invoker.pkg_dir)) {
pkg_dir = invoker.pkg_dir
}
if (defined(invoker.deps)) {
deps = invoker.deps
}
if (defined(invoker.datadeps)) {
datadeps = invoker.datadeps
}
if (defined(invoker.sdk_ext_directory)) {
sdk_ext_directory = invoker.sdk_ext_directory
}
if (defined(invoker.sdk_ext_files)) {
sdk_ext_files = invoker.sdk_ext_files
}
if (defined(invoker.sdk_ext_mappings)) {
sdk_ext_mappings = invoker.sdk_ext_mappings
}
}
if (defined(invoker.apps)) {
pkg_helper_output_dir = "$root_gen_dir/dart-pkg/${dart_package_name}"
foreach(app, invoker.apps) {
app_name = app[0]
app_entrypoint = app[1]
dartx_output_name = app_name
dartx_application("${app_name}_dart_app") {
output_name = dartx_output_name
main_dart = rebase_path(app_entrypoint, "", pkg_helper_output_dir)
sources = [ "$root_gen_dir/dart-pkg/${dart_package_name}.stamp" ]
deps = [ ":$dart_pkg_target_name" ]
deps += invoker.deps
if (defined(invoker.strict)) {
strict = invoker.strict
}
}
}
}
group(target_name) {
public_deps = [ ":$dart_pkg_target_name" ]
if (defined(invoker.apps)) {
foreach(app, invoker.apps) {
app_name = app[0]
dartx_target_name = "${app_name}_dart_app"
deps += [ ":$dartx_target_name" ]
}
}
}
}