GN build rules for tests using Fuchsia SDK Dart libraries and bindings (flutter/engine#27996)

This commit is contained in:
Rich Kadel
2021-08-13 10:52:01 -05:00
committed by GitHub
parent 556ec49def
commit 51a5b01bad
43 changed files with 3861 additions and 571 deletions

View File

@@ -1,251 +0,0 @@
# 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.
import("//build/package.gni")
import("//build/tools/json_merge/json_merge.gni")
import("//third_party/dart/build/dart/dart_action.gni")
import("//topaz/runtime/dart/config.gni")
import("//topaz/runtime/dart/dart_component.gni")
import("//topaz/runtime/dart/dart_kernel.gni")
# Defines JIT runtime components to be further distributed in one package.
#
# Takes a set of dart components and puts them into one fuchsia package with
# the dart_jit_runner as its runtime. Also supports legacy calls where the
# components parameter isn't specified, in which we will create one default
# component for the package.
#
# Parameters
#
# components (required)
# [list of scopes] Defines the components in the package. Either main_dart
# or components must be defined, but not both.
#
# Entries in a scope in the resources list:
#
# component_name (required)
# Name of the component.
#
# main_dart (required)
# File containing the main function of the component.
#
# dart_package_name (optional)
# Name of the dart package for the component. If not provided, it will
# be inferred from the component name.
#
# package_root (optional)
# Path to the dart package for the component. If not provided, it will
# be assumed as ".".
#
# sources (optional)
# Relative path of source files to be included in the dart package for
# the component at $package_root/lib.
#
# main_dart (required)
# File containing the main function of the application. Either main_dart or
# components must be defined, but not both.
#
# package_name (optional)
# Name of the Dart package. This is used as an identifier in code that
# depends on the dart library that the *one and only* component generates.
# Only compatible when components is not specified (use
# components.dart_package_name).
#
template("_dart_jit_component") {
legacy_component = false
pkg_name = target_name
if (!defined(invoker.components)) {
# If components is not specified, we are fitting main_dart into a component
# scope, and using that for the package.
#
# TODO(CP-141): Remove support for legacy_component once all existing calls
# to dart_app() have a components parameter.
legacy_component = true
if (defined(invoker.fuchsia_package_name)) {
legacy_component_name = invoker.fuchsia_package_name
} else {
legacy_component_name = target_name
}
pkg_name = legacy_component_name
pkg_sources = []
if (defined(invoker.sources)) {
pkg_sources = invoker.sources
}
components = [
{
main_dart = invoker.main_dart
component_name = legacy_component_name
component_type = "dart"
package_root = "."
deps = invoker.deps
sources = pkg_sources
},
]
}
flutter_dart_jit_component(target_name) {
forward_variables_from(invoker, "*")
}
}
# Defines AOT runtime components to be further distributed in one package.
#
# Takes a set of dart components and puts them into one fuchsia package with
# the dart_aot_runner as its runtime. Also supports legacy calls where the
# components parameter isn't specified, in which we will create one default
# component for the package.
#
# Parameters
#
# components (required)
# [list of scopes] Defines the components in the package. Either main_dart
# or components must be defined, but not both.
#
# Entries in a scope in the resources list:
#
# component_name (required)
# Name of the component.
#
# main_dart (required)
# File containing the main function of the component.
#
# dart_package_name (optional)
# Name of the dart package for the component. If not provided, it will
# be inferred from the component name.
#
# package_root (optional)
# Path to the dart package for the component. If not provided, it will
# be assumed as ".".
#
# sources (optional)
# Relative path of source files to be included in the dart package for
# the component at $package_root/lib.
#
# main_dart (required)
# File containing the main function of the application. Either main_dart or
# components must be defined, but not both.
#
# package_name (optional)
# Name of the Dart package. This is used as an identifier in code that
# depends on the dart library that the *one and only* component generates.
# Only compatible when components is not specified (use
# components.dart_package_name).
#
template("_dart_aot_component") {
legacy_component = false
pkg_name = target_name
if (!defined(invoker.components)) {
# If components is not specified, we are fitting main_dart into a component
# scope, and using that for the package.
#
# TODO(CP-141): Remove support for legacy_component once all existing calls
# to dart_app() have a components parameter.
legacy_component = true
if (defined(invoker.fuchsia_package_name)) {
legacy_component_name = invoker.fuchsia_package_name
} else {
legacy_component_name = target_name
}
pkg_name = legacy_component_name
pkg_sources = []
if (defined(invoker.sources)) {
pkg_sources = invoker.sources
}
components = [
{
main_dart = invoker.main_dart
component_name = legacy_component_name
component_type = "dart"
package_root = "."
deps = invoker.deps
sources = pkg_sources
},
]
}
flutter_dart_aot_component(target_name) {
forward_variables_from(invoker, "*")
}
}
template("dart_jit_app") {
template_name = "_dart_jit_component"
if (dart_force_product) {
template_name = dart_product_app
}
target(template_name, target_name) {
forward_variables_from(invoker, "*")
}
}
template("dart_aot_app") {
template_name = "_dart_aot_component"
if (dart_force_product) {
template_name = dart_product_app
}
target(template_name, target_name) {
forward_variables_from(invoker, "*")
}
}
# Defines a Dart application that can be run in the Dart content handler
#
# Parameters
#
# main_dart (required)
# Name of the Dart file containing the main function. Either main_dart or
# components must be defined, but not both.
#
# package_name (optional)
# Name of the Dart package.
#
# fuchsia_package_name (optional)
# Name of the Fuchsia package.
#
# deps (optional)
# List of Dart packages the application depends on.
#
# disable_analysis (optional)
# Prevents analysis from being run on this target.
#
# product (optional)
# A boolean. Whether to build/run the app in a stripped-down Dart VM.
# Defaults to !is_debug.
#
# resources (optional)
# Resources for the package (see //build/package.gni)
#
# tests (optional)
# List of tests forwarded for the package. See the definition in //build/package.gni.
#
# components (required)
# [list of scopes] Defines the components in the package. Either main_dart
# or components must be defined, but not both.
#
# Entries in a scope in the resources list:
#
# component_name (required)
# Name of the component.
#
# main_dart (required)
# File containing the main function of the component.
#
# package_root (optional)
# Path to the dart package for the component. If not provided, it will
# be assumed as ".".
#
# sources (optional)
# Relative path of source files to be included in the dart package for
# the component at $package_root/lib.
#
template("dart_app") {
assert((defined(invoker.components) && !defined(invoker.main_dart)) ||
(!defined(invoker.components) && defined(invoker.main_dart)),
"Only one of components or main_dart should be defined")
target(dart_default_app, target_name) {
forward_variables_from(invoker, "*")
}
}

View File

@@ -1,316 +0,0 @@
# 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.
assert(is_fuchsia)
import("//build/package.gni")
import("//build/tools/json_merge/json_merge.gni")
import("//third_party/dart/build/dart/dart_action.gni")
import("//topaz/runtime/dart/config.gni")
import("//topaz/runtime/dart/dart_component.gni")
import("//topaz/runtime/dart/dart_kernel.gni")
# Defines JIT runtime components to be further distributed in one package.
#
# Takes a set of flutter components and puts them into one fuchsia package with
# the flutter_jit_runner as its runtime. Also supports legacy calls where the
# components parameter isn't specified, in which we will create one default
# component for the package.
#
# Parameters
#
# components (required)
# [list of scopes] Defines the components in the package. Either main_dart
# or components must be defined, but not both.
#
# Entries in a scope in the resources list:
#
# component_name (required)
# Name of the component.
#
# main_dart (required)
# File containing the main function of the component.
#
# dart_package_name (optional)
# Name of the dart package for the component. If not provided, it will
# be inferred from the component name.
#
# package_root (optional)
# Path to the dart package for the component. If not provided, it will
# be assumed as ".".
#
# sources (optional)
# Relative path of source files to be included in the dart package for
# the component at $package_root/lib.
#
# main_dart (required)
# File containing the main function of the application. Either main_dart or
# components must be defined, but not both.
#
# package_name (optional)
# Name of the Dart package. This is used as an identifier in code that
# depends on the dart library that the *one and only* component generates.
# Only compatible when components is not specified (use
# components.dart_package_name).
#
template("_flutter_jit_component") {
pkg_name = target_name
legacy_component = false
if (!defined(invoker.components)) {
# If components is not specified, we are fitting main_dart into a component
# scope, and using that for the package.
#
# TODO(CP-140): Remove support for legacy_component once all existing calls
# to flutter_app() have a components parameter.
legacy_component = true
if (defined(invoker.fuchsia_package_name)) {
legacy_component_name = invoker.fuchsia_package_name
} else {
legacy_component_name = target_name
}
pkg_name = legacy_component_name
pkg_sources = []
if (defined(invoker.sources)) {
pkg_sources = invoker.sources
}
components = [
{
main_dart = invoker.main_dart
component_name = legacy_component_name
component_type = "flutter"
package_root = "."
deps = invoker.deps
sources = pkg_sources
},
]
}
flutter_dart_jit_component(target_name) {
forward_variables_from(invoker, "*")
}
}
# Defines AOT runtime components to be further distributed in one package.
#
# Takes a set of flutter components and puts them into one fuchsia package with
# the flutter_aot_runner as its runtime. Also supports legacy calls where the
# components parameter isn't specified, in which we will create one default
# component for the package.
#
# Parameters
#
# components (required)
# [list of scopes] Defines the components in the package. Either main_dart
# or components must be defined, but not both.
#
# Entries in a scope in the resources list:
#
# component_name (required)
# Name of the component.
#
# main_dart (required)
# File containing the main function of the component.
#
# dart_package_name (optional)
# Name of the dart package for the component. If not provided, it will
# be inferred from the component name.
#
# package_root (optional)
# Path to the dart package for the component. If not provided, it will
# be assumed as ".".
#
# sources (optional)
# Relative path of source files to be included in the dart package for
# the component at $package_root/lib.
#
# main_dart (required)
# File containing the main function of the application. Either main_dart or
# components must be defined, but not both.
#
# package_name (optional)
# Name of the Dart package. This is used as an identifier in code that
# depends on the dart library that the *one and only* component generates.
# Only compatible when components is not specified (use
# components.dart_package_name).
#
template("_flutter_aot_component") {
# This variable isn't needed in AOT builds.
if (defined(invoker.flutter_driver_extendable)) {
not_needed(invoker, [ "flutter_driver_extendable" ])
}
pkg_name = target_name
legacy_component = false
if (!defined(invoker.components)) {
# If components is not specified, we are fitting main_dart into a component
# scope, and using that for the package.
#
# TODO(CP-140): Remove support for legacy_component once all existing calls
# to flutter_app() have a components parameter.
legacy_component = true
if (defined(invoker.fuchsia_package_name)) {
legacy_component_name = invoker.fuchsia_package_name
} else {
legacy_component_name = target_name
}
pkg_name = legacy_component_name
pkg_sources = []
if (defined(invoker.sources)) {
pkg_sources = invoker.sources
}
components = [
{
main_dart = invoker.main_dart
component_name = legacy_component_name
component_type = "flutter"
package_root = "."
deps = invoker.deps
sources = pkg_sources
},
]
}
flutter_dart_aot_component(target_name) {
forward_variables_from(invoker, "*")
}
}
template("flutter_jit_app") {
template_name = "_flutter_jit_component"
if (dart_force_product) {
template_name = flutter_product_app
}
target(template_name, target_name) {
forward_variables_from(invoker, "*")
}
}
template("flutter_aot_app") {
template_name = "_flutter_aot_component"
if (dart_force_product) {
template_name = flutter_product_app
}
target(template_name, target_name) {
forward_variables_from(invoker, "*", [ "space_dart" ])
}
}
# Defines a Flutter application
#
# Parameters
#
# main_dart (required)
# Name of the Dart file containing the main function. Either main_dart or
# components must be defined, but not both.
#
# package_name (optional)
# Name of the Dart package.
#
# fuchsia_package_name (optional)
# Name of the Fuchsia package.
#
# deps (optional)
# List of Dart packages the application depends on.
#
# manifest (optional)
# Path to the manifest file
#
# disable_analysis (optional)
# Prevents analysis from being run on this target.
#
# product (optional)
# A boolean. Whether to build/run the app in a stripped-down Dart VM.
# Defaults to !is_debug.
#
# flutter_driver_extendable (optional)
# A boolean. Determines if, in a debug build, this package will be built
# with a wrapper that auto-enables flutter driver extensions when running
# the application in a an environment that includes TestRunner. Does not
# affect AOT or release builds.
#
# components (required)
# [list of scopes] Defines the components in the package. Either main_dart
# or components must be defined, but not both.
#
# Entries in a scope in the resources list:
#
# component_name (required)
# Name of the component.
#
# main_dart (required)
# File containing the main function of the component.
#
# package_root (optional)
# Path to the dart package for the component. If not provided, it will
# be assumed as ".".
#
# sources (optional)
# Relative path of source files to be included in the dart package for
# the component at $package_root/lib.
#
template("flutter_app") {
assert((defined(invoker.components) && !defined(invoker.main_dart)) ||
(!defined(invoker.components) && defined(invoker.main_dart)),
"Only one of components or main_dart should be defined")
target(flutter_default_app, target_name) {
forward_variables_from(invoker, "*", [ "aot" ])
}
}
# Defines multiple Flutter/Dart applications in one fuchsia package
#
# Parameters
#
# components (required)
# [list of scopes] Defines the components in the package. Either main_dart
# or components must be defined, but not both.
#
# Entries in a scope in the resources list:
#
# component_name (required)
# Name of the component.
#
# main_dart (required)
# File containing the main function of the component.
#
# dart_package_name (optional)
# Name of the dart package for the component. If not provided, it will
# be inferred from the component name.
#
# package_root (optional)
# Path to the dart package for the component. If not provided, it will
# be assumed as ".".
#
# sources (optional)
# Relative path of source files to be included in the dart package for
# the component at $package_root/lib.
#
template("flutter_dart_apps") {
assert(defined(invoker.components) && !defined(invoker.main_dart),
"components must be defined. Use main_dart under components instead.")
pkg_name = target_name
legacy_component = false
if (flutter_default_app == "flutter_jit_app") {
template_name = "flutter_dart_jit_component"
if (dart_force_product) {
template_name = flutter_product_app
}
target(template_name, target_name) {
forward_variables_from(invoker, "*", [ "aot" ])
}
} else {
template_name = "flutter_dart_aot_component"
if (dart_force_product) {
template_name = flutter_product_app
}
target(template_name, target_name) {
forward_variables_from(invoker,
"*",
[
"aot",
"space_dart",
])
}
}
}

View File

@@ -0,0 +1,43 @@
# 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.
if (host_os == "win") {
host_executable_suffix = ".exe"
} else {
host_executable_suffix = ""
}
template("executable_action") {
action(target_name) {
assert(defined(invoker.tool), "The executable tool must be specified.")
assert(defined(invoker.args), "The command line args must be specified.")
if (defined(invoker.visibility)) {
visibility = invoker.visibility
}
if (defined(invoker.testonly)) {
testonly = invoker.testonly
}
script = "//build/gn_run_binary.py"
host_executable =
rebase_path("${invoker.tool}${host_executable_suffix}", root_build_dir)
if (defined(invoker.deps)) {
deps = invoker.deps
} else {
deps = []
}
if (defined(invoker.inputs)) {
inputs = invoker.inputs
} else {
inputs = []
}
outputs = invoker.outputs
args = [ host_executable ] + invoker.args
}
}

View File

@@ -99,9 +99,12 @@ def main():
help='Path to read-elf executable.')
args = parser.parse_args()
assert os.path.exists(args.exec_path)
assert os.path.exists(args.dest)
assert os.path.exists(args.read_elf)
assert os.path.exists(args.exec_path), (
'exec_path "%s" does not exist' % args.exec_path)
assert os.path.exists(args.dest), (
'dest "%s" does not exist' % args.dest)
assert os.path.exists(args.read_elf), (
'read_elf "%s" does not exist' % args.read_elf)
parts = GetBuildIdParts(args.exec_path, args.read_elf)
dbg_prefix_base = os.path.join(args.dest, parts['prefix_dir'])

View File

@@ -1,10 +1,12 @@
# Copyright 2018 The Fuchsia Authors. All rights reserved.
# 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.
gen_snapshot = "//third_party/dart/runtime/bin:gen_snapshot"
gen_snapshot_product = "//third_party/dart/runtime/bin:gen_snapshot_product"
prebuilt_dart = "//third_party/dart/tools/sdks/dart-sdk/bin/dart"
observatory_target =
"//third_party/dart/runtime/observatory:observatory_archive"
observatory_archive_dir = get_label_info(observatory_target, "target_gen_dir")

View File

@@ -0,0 +1,27 @@
# 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.
import("//flutter/tools/fuchsia/dart/toolchain.gni")
import("//flutter/tools/fuchsia/python/python_binary.gni")
import("//flutter/tools/fuchsia/sdk/sdk_targets.gni")
import("//flutter/tools/fuchsia/toolchain/basic_toolchain.gni")
python_binary("gen_dart_package_config") {
main_source = "gen_dart_package_config.py"
}
if (current_toolchain == default_toolchain) {
# A toolchain dedicated to processing and analyzing Dart packages.
# The only targets in this toolchain are action() targets, so it
# has no real tools. But every toolchain needs stamp and copy.
basic_toolchain("dartlang") {
expected_label = dart_toolchain
}
}
if (current_toolchain != default_toolchain) {
sdk_targets("dart_library") {
meta = "$fuchsia_sdk_path/meta/manifest.json"
}
}

View File

@@ -0,0 +1,24 @@
# 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.
import("//flutter/tools/fuchsia/dart/dart_build_config.gni")
declare_args() {
# Forces all Dart apps to build in product mode which is a
# stripped down version of the VM running in AOT mode.
dart_force_product = false
# TODO(fxbug.dev/64153) renable aot builds
# if (dart_force_product) {
# Product AOT
# dart_default_build_cfg = dart_release_build_cfg
# } else if (is_debug) {
# Non-product JIT
dart_default_build_cfg = dart_debug_build_cfg
# } else {
# Non-product AOT
# dart_default_build_cfg = dart_profile_build_cfg
# }
}

View File

@@ -0,0 +1,22 @@
# 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.
# NOTE: Generally, the build rules in //flutter/tools/fuchsia/dart/,
# //flutter/tools/fuchsia/dart/kernel/, and similar SUBDIRECTORIES of
# //flutter/tools/fuchsia/ (such as //flutter/tools/fuchsia/flutter/)
# mirror the directory paths and much of the build rule content of fuchsia.git
# //build/...
#
# Most of the fuchsia-derived build rules were implemented after some similar
# build rules already existed in the directory //flutter/tools/fuchsia/
# and several existing build targets use these (legacy) build rules.
# Though some rules and targets in //flutter/tools/fuchsia/ have similar names
# to the fuchsia.git-derived rules, the rule structures and behavior can be
# different. Therefore both are maintained for now.
#
# In the case of this file--dart.gni--some existing definitions from the
# original dart.gni are relevant and useful to the new fuchsia.git-derived
# rules, so these definitions can simply be imported.
import("//flutter/tools/fuchsia/dart.gni")

View File

@@ -0,0 +1,51 @@
# 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.
# Builds the component in a non-product JIT build. This will
# launch the vm service in the runner.
dart_debug_build_cfg = {
runtime_meta = "//flutter/shell/platform/fuchsia/dart_runner/meta/jit_runtime"
runner_dep = "//flutter/shell/platform/fuchsia/dart_runner:dart_jit_runner"
platform_name = "dart_runner"
is_aot = false
is_product = false
enable_asserts = true
}
# Builds the component in a non-product AOT build. This will
# launch the vm service in the runner.
# This configuration is not compatible with a --release build since the
# profile aot runner is built without asserts.
dart_aot_debug_build_cfg = {
runtime_meta = "//flutter/shell/platform/fuchsia/dart_runner/meta/aot_runtime"
runner_dep = "//flutter/shell/platform/fuchsia/dart_runner:dart_aot_runner"
platform_name = "dart_runner"
is_aot = true
is_product = false
enable_asserts = true
}
# Builds the component in a non-product AOT build. This will
# launch the vm service in the runner.
dart_profile_build_cfg = {
runtime_meta = "//flutter/shell/platform/fuchsia/dart_runner/meta/aot_runtime"
runner_dep = "//flutter/shell/platform/fuchsia/dart_runner:dart_aot_runner"
platform_name = "dart_runner"
is_aot = true
is_product = false
enable_asserts = false
}
# Builds the component in a product AOT build. This will
# not launch the vm service in the runner.
dart_release_build_cfg = {
runtime_meta =
"//flutter/shell/platform/fuchsia/dart_runner/meta/aot_product_runtime"
runner_dep =
"//flutter/shell/platform/fuchsia/dart_runner:dart_aot_product_runner"
platform_name = "dart_runner"
is_aot = true
is_product = true
enable_asserts = false
}

View File

@@ -0,0 +1,345 @@
# 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.
import("//flutter/tools/fuchsia/dart/dart.gni")
import("//flutter/tools/fuchsia/dart/dart_package_config.gni")
import("//flutter/tools/fuchsia/dart/toolchain.gni")
import("//flutter/tools/python/python3_action.gni")
# Defines a Dart library
#
# Parameters
#
# sources
# The list of all sources in this library.
# These sources must be within source_dir.
#
# package_root (optional)
# Path to the directory hosting the library.
# This is useful for generated content, and can be ignored otherwise.
# Defaults to ".".
#
# package_name (optional)
# Name of the Dart package. This is used as an identifier in code that
# depends on this library.
#
# language_version (optional)
# Specify the Dart language version to use for this package.
# If language_version is not specified but pubspec is then the language
# version will be read from the pubspec. If no language version can be
# determined then we will default to version "2.8".
# It is recommended to specify a language_version if it is well known
# instead of relying on the pubspec file since this will improve compilation
# times.
#
# infer_package_name (optional)
# Infer the package name based on the path to the package.
#
# NOTE: Exactly one of package_name or infer_package_name must be set.
#
# source_dir (optional)
# Path to the directory containing the package sources, relative to
# package_root. All non third-party dart files under source_dir must be
# included in sources.
# Defaults to "lib".
#
# deps (optional)
# List of labels this library depends on.
#
# TODO(fxb/63133): non_dart_deps is deprecated. Use deps instead.
# non_dart_deps (optional, deprecated)
# List of labels this library depends on that are not Dart libraries. This
# includes things like actions that generate Dart code. It typically doesn't
# need to be set.
# Note that these labels *must* have an explicit toolchain attached.
#
# TODO(fxbug.dev/71902): set up allowlist for disable_source_verification when
# dart_test no longer depends on dart_library.
# NOTE: Do NOT disable source verification unless you are 100% sure it is
# absolutely necessary.
# disable_source_verification (optional)
# Prevents source verification from being run on this target.
#
# extra_sources (optional)
# Additional sources to consider for analysis.
#
# pubspec (optional)
# Path to the pubspec.yaml. If not provided, will default to looking for
# the pubspec.yaml in the package root. It is not common that this value will
# need to be set but can be useful for generated code.
#
# options_file (optional)
# Path to the analysis_options.yaml file. If not provided, will default to
# looking for the analysis_options.yaml in the package root. It is not common
# that this value needs to be set but can be useful for generated code.
#
# disable_metadata_entry (optional)
# Prevents metedata entry from being written to the dart_packag_config json file.
#
# null_safe (optional)
# A flag that enables null safety check in dart libraries.
#
# Example of usage:
#
# dart_library("baz") {
# package_name = "foo.bar.baz"
#
# sources = [
# "blah.dart",
# ]
#
# deps = [
# "//foo/bar/owl",
# ]
# }
if (current_toolchain == dart_toolchain) {
template("dart_library") {
forward_variables_from(invoker,
[
"visibility",
"hermetic_deps",
])
if (defined(invoker.package_name)) {
package_name = invoker.package_name
} else if (defined(invoker.infer_package_name) &&
invoker.infer_package_name) {
# Compute a package name from the label:
# //foo/bar --> foo.bar
# //foo/bar:blah --> foo.bar._blah
# //garnet/public/foo/bar --> foo.bar
# Strip public directories.
full_dir = get_label_info(":$target_name", "dir")
package_name = full_dir
package_name = string_replace(package_name, "//", "")
package_name = string_replace(package_name, "/", ".")
# If the last directory name does not match the target name, add the
# target name to the resulting package name.
name = get_label_info(":$target_name", "name")
last_dir = get_path_info(full_dir, "name")
if (last_dir != name) {
package_name = "$package_name._$name"
}
} else {
assert(false, "Must specify either a package_name or infer_package_name")
}
_dart_deps = []
if (defined(invoker.deps)) {
foreach(dep, invoker.deps) {
_dart_deps += [ get_label_info(dep, "label_no_toolchain") ]
}
}
_non_dart_deps = []
if (defined(invoker.non_dart_deps)) {
_non_dart_deps += invoker.non_dart_deps
}
package_root = "."
if (defined(invoker.package_root)) {
package_root = invoker.package_root
}
source_dir = "$package_root/lib"
if (defined(invoker.source_dir)) {
source_dir = "$package_root/${invoker.source_dir}"
}
assert(defined(invoker.sources), "Sources must be defined")
disable_source_verification =
defined(invoker.disable_source_verification) &&
invoker.disable_source_verification
if (disable_source_verification && invoker.sources == []) {
not_needed([ source_dir ])
}
rebased_sources = []
foreach(source, invoker.sources) {
rebased_source_dir = rebase_path(source_dir)
rebased_sources += [ "$rebased_source_dir/$source" ]
}
if (defined(invoker.extra_sources)) {
foreach(source, invoker.extra_sources) {
rebased_sources += [ rebase_path(source) ]
}
}
source_file = "$target_gen_dir/$target_name.sources"
write_file(source_file, rebased_sources, "list lines")
# Dependencies of the umbrella group for the targets in this file.
group_deps = []
_public_deps = []
if (defined(invoker.public_deps)) {
_public_deps = invoker.public_deps
}
_metadata = {
package_config_entries = [
{
name = package_name
if (defined(invoker.language_version)) {
language_version = invoker.language_version
} else if (defined(invoker.null_safe) && invoker.null_safe) {
language_version = "2.12"
} else if (defined(invoker.pubspec)) {
pubspec_path = rebase_path(invoker.pubspec, root_build_dir)
}
root_uri = rebase_path(package_root, root_build_dir)
if (defined(invoker.source_dir)) {
package_uri = invoker.source_dir
} else {
package_uri = "lib"
}
},
]
dart_build_info = [
{
__is_current_target = false
__package_name = package_name
__deps = _dart_deps + _non_dart_deps
__public_deps = _public_deps
__rebased_sources = rebased_sources
},
]
dart_build_info_barrier = []
}
# When we generate a package_config for the analyzer we need to make sure
# that we are including this library in that file. The dart_package_config
# collects metadata from its dependencies so we create this group to expose
# that data. We also expose this in the group target below so that users of
# the dart_package_config target can just add the targets to the deps list.
_publish_metadata_target_name = "${target_name}_package_metadata"
group(_publish_metadata_target_name) {
metadata = _metadata
}
_dart_package_config_target_name = "${target_name}_dart_package"
_packages_path = "$target_gen_dir/${target_name}_package_config.json"
dart_package_config(_dart_package_config_target_name) {
# Do not publish the metadata to the dart_package_config json file if the
# disable_metadata_entry flag is enabled in the dart_tool. The reason this is here
# is to avoid entries that may have identical rootUris as fxb/58781 has highlighted.
deps = _dart_deps
if (!defined(invoker.disable_metadata_entry) ||
!invoker.disable_metadata_entry) {
deps += [ ":$_publish_metadata_target_name" ]
}
public_deps = _non_dart_deps
outputs = [ _packages_path ]
forward_variables_from(invoker, [ "testonly" ])
}
group_deps += [ ":$_dart_package_config_target_name" ]
################################
# Dart source "verification"
#
# Warn if there are dart sources from the source directory that are
# not explicitly part of sources. This may cause a failure when syncing to
# another repository, as they will be excluded from the resulting BUILD
# file.
#
# Also warn if nonexistent files are included in sources.
if (!disable_source_verification) {
source_verification_target_name = "${target_name}_source_verification"
python3_action(source_verification_target_name) {
script = "//flutter/tools/fuchsia/dart/verify_sources.py"
output_file = "$target_gen_dir/$target_name.missing"
sources = rebased_sources
outputs = [ output_file ]
args = [
"--source_dir",
rebase_path(source_dir),
"--stamp",
rebase_path(output_file),
] + invoker.sources
forward_variables_from(invoker, [ "testonly" ])
# Deps may include codegen dependencies that generate dart sources.
deps = _dart_deps + _non_dart_deps
}
group_deps += [ ":$source_verification_target_name" ]
}
# Generate a file that lists files containing full (including all direct and
# transitive dependencies) sources for this target's dependencies.
_all_deps_sources_list_target = "${target_name}.all_deps_sources.list"
_all_deps_sources_list_file =
"${target_gen_dir}/${target_name}.all_deps_sources.list"
generated_file(_all_deps_sources_list_target) {
forward_variables_from(invoker, [ "testonly" ])
outputs = [ _all_deps_sources_list_file ]
data_keys = [ "all_deps_sources" ]
walk_keys = [ "all_deps_sources_barrier" ]
deps = _dart_deps
}
# Generate full sources for this target by combining sources of this target
# with full sources of all dependencies.
#
# The generated file contains sources of this target and all of its direct
# and transitive dependencies.
#
# The output file is useful when writing depfiles for actions like dart
# analyzer, which recursively reads all sources.
_all_deps_sources_target = "${target_name}.all_deps_sources"
_all_deps_sources_file = "${target_gen_dir}/${target_name}.all_deps_sources"
python3_action(_all_deps_sources_target) {
forward_variables_from(invoker, [ "testonly" ])
script = "//flutter/tools/fuchsia/dart/merge_deps_sources.py"
outputs = [ _all_deps_sources_file ]
depfile = "${_all_deps_sources_file}.d"
args = [
"--output",
rebase_path(outputs[0], root_build_dir),
"--depfile",
rebase_path(depfile, root_build_dir),
"--source_lists",
"@" + rebase_path(_all_deps_sources_list_file, root_build_dir),
"--sources",
] + rebase_path(rebased_sources, root_build_dir)
inputs = [ _all_deps_sources_list_file ]
deps = [ ":${_all_deps_sources_list_target}" ]
metadata = {
all_deps_sources = [ rebase_path(outputs[0], root_build_dir) ]
all_deps_sources_barrier = []
}
}
group_deps += [ ":${_all_deps_sources_target}" ]
not_needed(invoker, [ "options_file" ])
group(target_name) {
# _dart_deps are added here to ensure they are fully built.
# Up to this point, only the targets generating .packages had been
# depended on.
deps = _dart_deps + _non_dart_deps
public_deps = group_deps
metadata = _metadata
forward_variables_from(invoker, [ "testonly" ])
}
}
} else { # Not the Dart toolchain.
template("dart_library") {
group(target_name) {
forward_variables_from(invoker, [ "testonly" ])
not_needed(invoker, "*")
public_deps = [ ":$target_name($dart_toolchain)" ]
}
}
}

View File

@@ -0,0 +1,117 @@
# 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.
# Generates a package_config.json file containing all of the packages used
# to generate a kernel file.
#
# Package configs are files which describe metadata about a dart package.
# This includes information like the name, dart language version, where to
# find the files, etc. The file is required by the dart kernel compiler.
#
# Parameters
#
# deps, public_deps (optional)
# [list of labels] The targets to generate a manifest for.
# See `gn help` for more details.
#
# testonly, visibility, metadata (optional)
# See `gn help`.
#
# outputs (optional)
# Singleton list containing the path to the package_config file.
# Defaults to `[ "$target_gen_dir/${target_name}_package_config.json" ]`.
template("dart_package_config") {
main_target = target_name
generate_target = "${target_name}_generate"
# Build the name of the output file.
if (defined(invoker.outputs)) {
_outputs = invoker.outputs
assert(_outputs != [] && _outputs == [ _outputs[0] ],
"Outputs list must have exactly one element.")
package_config_file = _outputs[0]
} else {
package_config_file = "$target_gen_dir/${target_name}_package_config.json"
}
intermediate_file = "$package_config_file.partial"
# Gather metadata about runtime objects.
generated_file(generate_target) {
forward_variables_from(invoker,
[
"deps",
"public_deps",
"testonly",
])
visibility = [ ":$main_target" ]
data_keys = [
# A list of package configuration entries
#
# Each entry must contain these values:
# - `name`: The name of the package;
# - `root_uri`: Path to the package root relative to root_build_dir;
# - `package_uri`: The path in which the source lives
#
# The following entries may optionally be specified
# - `language_version`: The dart language version.
# - `pubspec_path`: The path to the pubspec file to find the language version
"package_config_entries",
]
walk_keys = [ "package_config_entry_barrier" ]
outputs = [ intermediate_file ]
output_conversion = "json"
}
# Converts the intermediate to a real pacakge_config.json file.
action(main_target) {
forward_variables_from(invoker,
[
"deps",
"public_deps",
"testonly",
"visibility",
])
script =
get_label_info("//flutter/tools/fuchsia/dart:gen_dart_package_config",
"target_out_dir") + "/gen_dart_package_config.pyz"
inputs = [ intermediate_file ]
outputs = [ package_config_file ]
depfile = "${target_gen_dir}/${target_name}.d"
args = [
"--input",
rebase_path(intermediate_file, root_build_dir),
"--output",
rebase_path(package_config_file, root_build_dir),
"--root",
rebase_path("//", root_build_dir),
"--depfile",
rebase_path(depfile, root_build_dir),
]
if (!defined(deps)) {
deps = []
}
deps += [
":$generate_target",
"//flutter/tools/fuchsia/dart:gen_dart_package_config",
]
metadata = {
# Add a barrier here to avoid double of inclusion of elements listed in
# the generated package config.
package_config_entry_barrier = []
if (defined(invoker.metadata)) {
forward_variables_from(invoker.metadata, "*")
}
}
}
}

View File

@@ -0,0 +1,105 @@
# 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.
import("//flutter/tools/fuchsia/dart/dart_library.gni")
import("//flutter/tools/fuchsia/dart/dart_package_config.gni")
import("//flutter/tools/fuchsia/dart/toolchain.gni")
import("//flutter/tools/python/python3_action.gni")
# Wraps a dart snapshot in a script to be invoked by dart
#
# Parameters
#
# dart (required)
# The path to the dart binary
#
# snapshot (required)
# The path to the dart snapshot
#
# deps (optional)
# Dependencies of this application
#
# output_name (optional)
# Name of the output file to generate. Defaults to $target_name.
template("_dart_snapshot_invocation") {
assert(defined(invoker.dart), "Must specify the path to the dart binary")
assert(defined(invoker.snapshot),
"Must specify the path to the dart snapshot")
if (defined(invoker.output_name)) {
app_name = invoker.output_name
} else {
app_name = target_name
}
# Builds a convenience script to invoke the app.
python3_action(target_name) {
forward_variables_from(invoker,
[
"testonly",
"deps",
])
script = "//flutter/tools/fuchsia/dart/gen_app_invocation.py"
app_path = "$root_out_dir/dart-tools/$app_name"
dart_binary = invoker.dart
snapshot = invoker.snapshot
inputs = [
dart_binary,
snapshot,
]
outputs = [ app_path ]
args = [
"--out",
rebase_path(app_path, root_build_dir),
# `--dart` and `--snapshot` are used in the output app script, use
# absolute path so the script would work regardless where it's invoked.
"--dart",
rebase_path(dart_binary),
"--snapshot",
rebase_path(snapshot),
]
metadata = {
# Record metadata for the //:tool_paths build API.
tool_paths = [
{
cpu = current_cpu
label = get_label_info(":$target_name", "label_with_toolchain")
name = app_name
os = current_os
path = rebase_path(app_path, root_build_dir)
},
]
snapshot_path = [ rebase_path(snapshot, root_build_dir) ]
}
}
}
# Defines a Dart application that can be run on the host which is
# compiled from an existing snapshot
#
# Parameters
#
# snapshot (required)
# The path to the dart snapshot
#
# deps (optional)
# Dependencies of this application
#
# output_name (optional)
# Name of the output file to generate. Defaults to $target_name.
template("dart_prebuilt_tool") {
assert(defined(invoker.snapshot),
"Must specify the path to the dart snapshot")
_dart_snapshot_invocation(target_name) {
dart = prebuilt_dart
forward_variables_from(invoker, "*")
}
}

View File

@@ -0,0 +1,95 @@
# 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.
import("//build/fuchsia/sdk.gni")
import("//flutter/tools/executable_action.gni")
import("//flutter/tools/fuchsia/dart/dart_library.gni")
import("//flutter/tools/fuchsia/dart/toolchain.gni")
import("//flutter/tools/fuchsia/fidl/fidl.gni")
import("//flutter/tools/fuchsia/fidl/toolchain.gni")
# Generates some Dart bindings for a FIDL library.
#
# The parameters for this template are defined in //flutter/tools/fuchsia/fidl/fidl.gni. The
# relevant parameters in this template are:
# - name;
template("fidl_dart") {
assert(current_toolchain == dart_toolchain,
"This template can only be used in the $dart_toolchain toolchain.")
not_needed(invoker, [ "sources" ])
main_target_name = target_name
generation_target_name = "${target_name}_dart_generate"
library_name = target_name
root_dir = "$target_gen_dir/${library_name}_package"
if (defined(invoker.name)) {
library_name = invoker.name
root_dir = "$target_gen_dir/${target_name}_${library_name}_package"
}
bindings_dir = "$root_dir/lib"
async_bindings_file = "$bindings_dir/fidl_async.dart"
test_bindings_file = "$bindings_dir/fidl_test.dart"
fidl_target_gen_dir =
get_label_info(":bogus($fidl_toolchain)", "target_gen_dir")
json_representation = "$fidl_target_gen_dir/$target_name.fidl.json"
executable_action(generation_target_name) {
visibility = [ ":*" ]
tool = "${fuchsia_sdk_path}/tools/fidlgen_dart"
inputs = [ json_representation ]
outputs = [
async_bindings_file,
test_bindings_file,
]
args = [
"--json",
rebase_path(json_representation, root_build_dir),
"--output-async",
rebase_path(async_bindings_file, root_build_dir),
"--output-test",
rebase_path(test_bindings_file, root_build_dir),
]
deps = [ ":$main_target_name($fidl_toolchain)" ]
forward_variables_from(invoker, [ "testonly" ])
}
dart_library(main_target_name) {
forward_variables_from(invoker,
[
"testonly",
"visibility",
])
package_root = root_dir
package_name = "fidl_" + string_replace(library_name, ".", "_")
null_safe = true
sources = [
rebase_path(async_bindings_file, bindings_dir),
rebase_path(test_bindings_file, bindings_dir),
]
deps = [ ":$generation_target_name" ]
if (defined(invoker.public_deps)) {
deps += invoker.public_deps
}
# invoker.deps are the non_fidl_deps passed in to the fidl() rule
if (defined(invoker.deps)) {
deps += invoker.deps
}
}
}

View File

@@ -0,0 +1,44 @@
#!/usr/bin/env python3.8
# 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.
import argparse
import os
import stat
import string
import sys
def main():
parser = argparse.ArgumentParser(
description='Generate a script that invokes a Dart application')
parser.add_argument(
'--out', help='Path to the invocation file to generate', required=True)
parser.add_argument('--dart', help='Path to the Dart binary', required=True)
parser.add_argument(
'--snapshot', help='Path to the app snapshot', required=True)
args = parser.parse_args()
app_file = args.out
app_path = os.path.dirname(app_file)
if not os.path.exists(app_path):
os.makedirs(app_path)
script_template = string.Template(
'''#!/bin/sh
$dart \\
$snapshot \\
"$$@"
''')
with open(app_file, 'w') as file:
file.write(script_template.substitute(args.__dict__))
permissions = (
stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP |
stat.S_IWGRP | stat.S_IXGRP | stat.S_IROTH)
os.chmod(app_file, permissions)
if __name__ == '__main__':
sys.exit(main())

View File

@@ -0,0 +1,135 @@
#!/usr/bin/env python3.8
# 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.
"""Reads the contents of a package config file generated by the build and
converts it to a real package_config.json file
"""
import argparse
import collections
import json
import os
import re
import sys
import yaml
DEFAULT_LANGUAGE_VERSION = '2.8'
Package = collections.namedtuple(
'Package', ['name', 'rootUri', 'languageVersion', 'packageUri'])
class PackageConfig:
# The version of the package config.
VERSION = 2
# The name of the generator which gets written to the json output
GENERATOR_NAME = os.path.basename(__file__)
def __init__(self, packages):
self.packages = packages
def asdict(self):
"""Converts the package config to a dictionary"""
return {
'configVersion': self.VERSION,
'packages': [p._asdict() for p in sorted(self.packages)],
'generator': self.GENERATOR_NAME,
}
def language_version_from_pubspec(pubspec):
"""Parse the content of a pubspec.yaml"""
with open(pubspec) as pubspec:
parsed = yaml.safe_load(pubspec)
if not parsed:
return DEFAULT_LANGUAGE_VERSION
# If a format like sdk: '>=a.b' or sdk: 'a.b' is found, we'll use a.b.
# In all other cases we default to "2.8"
env_sdk = parsed.get('environment', {}).get('sdk', 'any')
match = re.search(r'^(>=)?((0|[1-9]\d*)\.(0|[1-9]\d*))', env_sdk)
if match:
min_sdk_version = match.group(2)
else:
min_sdk_version = DEFAULT_LANGUAGE_VERSION
return min_sdk_version
def collect_packages(items, relative_to):
"""Reads metadata produced by GN to create lists of packages and pubspecs.
- items: a list of objects collected from gn
- relative_to: The directory which the packages are relative to. This is
the location that contains the package_config.json file
Returns None if there was a problem parsing packages
"""
packages = []
pubspec_paths = []
for item in items:
if 'language_version' in item:
language_version = item['language_version']
elif 'pubspec_path' in item:
pubspec_paths.append(item['pubspec_path'])
language_version = language_version_from_pubspec(
item['pubspec_path'])
else:
language_version = DEFAULT_LANGUAGE_VERSION
package = Package(
name=item['name'],
rootUri=os.path.relpath(item['root_uri'], relative_to),
languageVersion=language_version,
packageUri=item['package_uri'])
# TODO(fxbug.dev/56428): enable once we sort out our duplicate packages
# for p in packages:
# if p.rootUri == package.rootUri:
# print('Failed to create package_config.json file')
# print('The following packages contain the same package root ' + p.rootUri)
# print(' - ' + p.rootUri)
# print(' - ' + package.rootUri)
# return None
packages.append(package)
return packages, pubspec_paths
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument(
'--input', help='Path to original package_config', required=True)
parser.add_argument(
'--output', help='Path to the updated package_config', required=True)
parser.add_argument('--root', help='Path to fuchsia root', required=True)
parser.add_argument('--depfile', help='Path to the depfile', required=True)
args = parser.parse_args()
with open(args.input, 'r') as input_file:
contents = json.load(input_file)
output_dir = os.path.dirname(os.path.abspath(args.output))
packages, pubspec_paths = collect_packages(contents, output_dir)
if packages is None:
return 1
with open(args.depfile, 'w') as depfile:
depfile.write('%s: %s' % (args.output, ' '.join(pubspec_paths)))
with open(args.output, 'w') as output_file:
package_config = PackageConfig(packages)
json.dump(
package_config.asdict(),
output_file,
indent=2,
sort_keys=True,
separators=(',', ': '))
return 0
if __name__ == '__main__':
sys.exit(main())

View File

@@ -0,0 +1,9 @@
# 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.
import("//flutter/tools/fuchsia/dart/dart_tool.gni")
dart_prebuilt_tool("gen_kernel") {
snapshot = "//third_party/dart/pkg/vm/bin/gen_kernel.dart"
}

View File

@@ -0,0 +1,58 @@
#!/usr/bin/env python3.8
# 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.
'''Reads the contents of a kernel manifest generated by the build and
converts it to a format suitable for distribution_entries
'''
import argparse
import collections
import json
import os
import sys
Entry = collections.namedtuple('Entry', ['source', 'destination'])
def collect(lines):
'''Reads the kernel manifest and creates an array of Entry objects.
- lines: a list of lines from the manifest
'''
entries = []
for line in lines:
values = line.split("=", 1)
entries.append(Entry(source=values[1], destination=values[0]))
return entries
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument(
'--input', help='Path to original manifest', required=True)
parser.add_argument(
'--output', help='Path to the updated json file', required=True)
args = parser.parse_args()
with open(args.input, 'r') as input_file:
contents = input_file.read().splitlines()
entries = collect(contents)
if entries is None:
return 1
with open(args.output, 'w') as output_file:
json.dump(
[e._asdict() for e in entries],
output_file,
indent=2,
sort_keys=True,
separators=(',', ': '))
return 0
if __name__ == '__main__':
sys.exit(main())

View File

@@ -0,0 +1,329 @@
# 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.
# NOTE: Generally, the build rules in //flutter/tools/fuchsia/dart/,
# //flutter/tools/fuchsia/dart/kernel/, and similar SUBDIRECTORIES of
# //flutter/tools/fuchsia/ (such as //flutter/tools/fuchsia/flutter/)
# mirror the directory paths and much of the build rule content of fuchsia.git
# //build/...
#
# Most of the fuchsia-derived build rules were implemented after some similar
# build rules already existed in the directory //flutter/tools/fuchsia/
# and several existing build targets use these (legacy) build rules.
# Though some rules and targets in //flutter/tools/fuchsia/ have similar names
# to the fuchsia.git-derived rules, the rule structures and behavior can be
# different. Therefore both are maintained for now.
#
# This file--dart_kernel.gni--and its primary template--dart_kernel()--match
# pre-existing (legacy) template and filename in
# //flutter/tools/fuchsia/dart_kernel.gni.
#
# The templates appear to have different behavior, so both will be maintained
# until we can determine a better way to reconcile them.
import("//flutter/tools/fuchsia/dart/config.gni")
import("//flutter/tools/fuchsia/dart/dart_library.gni")
import("//flutter/tools/fuchsia/dart/toolchain.gni")
import("//flutter/tools/python/python3_action.gni")
_gen_kernel_label =
"//flutter/tools/fuchsia/dart/kernel:gen_kernel($host_toolchain)"
_gen_kernel_path =
get_label_info(_gen_kernel_label, "root_out_dir") + "/dart-tools/gen_kernel"
flutter_platform_name = "flutter_runner"
# Converts the kernel manifest file from fini format to JSON format and
# registers the metadata for the fuchsia_package to pick up.
#
# Parameters
#
# manifest (required)
# Path to the kernel manifest
# Type: Path
template("_convert_kernel_manifest") {
assert(defined(invoker.manifest), "dart_kernel() requires a manifest")
python3_action(target_name) {
forward_variables_from(invoker,
[
"deps",
"testonly",
"visibility",
])
_converted_file_name =
"${target_gen_dir}/${target_name}_kernel_manifest.json"
script = "//flutter/tools/fuchsia/dart/kernel/convert_manifest_to_json.py"
args = [
"--input",
rebase_path(invoker.manifest, root_build_dir),
"--output",
rebase_path(_converted_file_name, root_build_dir),
]
sources = [ invoker.manifest ]
outputs = [ _converted_file_name ]
metadata = {
distribution_entries = [
{
file = rebase_path(_converted_file_name, root_build_dir)
label = get_label_info(target_name, "label_with_toolchain")
},
]
}
}
}
# Generates dill files for a Dart application.
#
# It is not likely that this target will be used directly. Instead, developers
# should use the dart_tool or dart/flutter_component targets which create a
# kernel for you.
#
# Parameters
#
# platform_name (required)
# The name of the platform, either "flutter_runner" or "dart_runner".
#
# packages_path (required)
# Path to the package_config.json file.
#
# main_dart (required, mutually exclusive)
# Path to Dart source file containing main(). Mutually exclusive with
# main_dart_file. This is relative to source_dir, should exist in the
# main_package, and uses a package: URI.
#
# main_package (required, mutually exclusive)
# The name of the package which contains main. Mutually exclusive with
# main_dart_file.
#
# main_dart_file (required, mutually exclusive)
# Path to Dart source file containing main(). Mutually exclusive with
# main_dart. This doesn't need to necessarily exist in main_package and uses
# a fuchsia-source: URI.
#
# product (required)
# Whether this should be built with the product runner.
#
# is_aot required)
# Whether this kernel is an aot build.
#
# generate_manifest (optional)
# Whether the compiler should generate a kernel manifest containing the list
# of partial dill files in JIT builds. This flag is ignored in aot builds
# Default: false
#
# kernel_path (optional)
# The path to the kernel output. Defaults to target_gen_dir/${target_name}.dil
#
# kernel_target_name (optional)
# The name of the kernel target. This parameter is required if you are
# depending on the kernel_path for an input. This allows you to establish a
# dependency chain on the generated file.
#
# args (optional)
# A list of additional arguments to the compiler.dart program in this
# directory that generates the kernel files.
#
# link_platform (optional)
# Whether the kernel compiler should link the current platform.dill into
# the build. If false, the --no-link-platform flag will be passed to the
# compiler. Defaults to false
template("dart_kernel") {
assert(defined(invoker.platform_name), "dart_kernel() requires platform_name")
assert(defined(invoker.packages_path),
"dart_kernel() requires the path to the package config")
assert(
(defined(invoker.main_dart) && defined(invoker.main_package)) !=
defined(invoker.main_dart_file),
"dart_kernel() requires either (main_dart and main_package) or main_dart_file")
assert(defined(invoker.product), "dart_kernel() requires product")
assert(defined(invoker.is_aot), "dart_kernel() requires is_aot")
if (defined(invoker.kernel_target_name)) {
_kernel_target_name = invoker.kernel_target_name
} else {
_kernel_target_name = "${target_name}_kernel"
}
_group_deps = [ ":$_kernel_target_name" ]
_kernel_deps = []
if (defined(invoker.deps)) {
_kernel_deps += invoker.deps
}
_generate_manifest = false
if (invoker.is_aot) {
not_needed(invoker, [ "generate_manifest" ])
} else {
if (defined(invoker.generate_manifest) && invoker.generate_manifest) {
_generate_manifest = true
}
}
if (_generate_manifest) {
_kernel_manifest = "$target_gen_dir/${target_name}.dilpmanifest"
_convert_target_name = "${target_name}_convert_kernel_manifest"
_convert_kernel_manifest(_convert_target_name) {
forward_variables_from(invoker,
[
"testonly",
"visibility",
])
manifest = _kernel_manifest
# must depend on the kernel target so we have the kernel manifest
deps = [ ":$_kernel_target_name" ]
}
_group_deps += [ ":$_convert_target_name" ]
}
python3_action(_kernel_target_name) {
forward_variables_from(invoker,
[
"testonly",
"visibility",
])
if (defined(invoker.kernel_path)) {
_kernel_path = invoker.kernel_path
} else {
_kernel_path =
"$target_gen_dir/__untraced_dart_kernel__/${target_name}.dil"
}
depfile = "${_kernel_path}.d"
_kernel_deps += [ _gen_kernel_label ]
if (invoker.platform_name == flutter_platform_name) {
_kernel_deps += [
"//flutter/shell/platform/fuchsia/flutter/kernel:kernel_platform_files",
]
_platform_path = "$root_out_dir/flutter_runner_patched_sdk"
} else {
assert(false,
"platform_name must be either dart_runner or flutter_runner")
}
_platform_strong_dill = "${_platform_path}/platform_strong.dill"
inputs = [
_gen_kernel_path,
_platform_strong_dill,
invoker.packages_path,
]
outputs = [ _kernel_path ]
if (_generate_manifest) {
outputs += [
# Explicit output when using --manifest.
_kernel_manifest,
# Implicit output when using --manifest; see createManifest in compiler.dart.
_kernel_manifest + ".dilplist",
_kernel_manifest + ".frameworkversion",
]
}
_multi_root_scheme = "fuchsia-source"
# Rebase against // instead of root_build_dir since the package_config is
# relative to the sources.
_rebased_packages_path = rebase_path(invoker.packages_path, "//")
# gen_kernel writes absolute paths to depfiles, convert them to relative.
# See more information in https://fxbug.dev/75451.
script = "//flutter/tools/fuchsia/depfile_path_to_relative.py"
args = [
"--depfile=" + rebase_path(depfile, root_build_dir),
"--",
rebase_path(_gen_kernel_path, root_out_dir),
]
if (defined(invoker.args)) {
args += invoker.args
}
args += [
"--verbosity=warning",
"--no-sound-null-safety",
"--target",
invoker.platform_name,
"--platform",
rebase_path(_platform_strong_dill, root_build_dir),
"--filesystem-scheme",
_multi_root_scheme,
"--filesystem-root",
rebase_path("//"),
"--packages",
"$_multi_root_scheme:///$_rebased_packages_path",
# Repeating "--depfile" because the previous one is for
# `depfile_path_to_relative.py`, and this one is for `_gen_kernel_path`.
"--depfile",
rebase_path(depfile, root_build_dir),
"--output",
rebase_path(_kernel_path, root_build_dir),
]
if (_generate_manifest) {
args += [
"--split-output-by-packages",
"--manifest",
rebase_path(_kernel_manifest, root_build_dir),
]
}
if (is_debug) {
args += [ "--embed-sources" ]
} else {
args += [ "--no-embed-sources" ]
}
if (invoker.is_aot) {
args += [
"--aot",
"--tfa",
]
} else if (!defined(invoker.link_platform) || !invoker.link_platform) {
args += [ "--no-link-platform" ]
}
if (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:
#
# This define excludes debugging and profiling code from Flutter.
args += [ "-Ddart.vm.product=true" ]
} else {
if (!is_debug) {
# The following define excludes debugging code from Flutter.
args += [ "-Ddart.vm.profile=true" ]
}
}
if (defined(invoker.main_dart)) {
args += [ "package:${invoker.main_package}/${invoker.main_dart}" ]
} else {
rebased_main_dart = rebase_path(invoker.main_dart_file, "//")
args += [ "$_multi_root_scheme:///$rebased_main_dart" ]
}
deps = _kernel_deps
}
group(target_name) {
forward_variables_from(invoker,
[
"testonly",
"visibility",
])
deps = _group_deps
}
}

View File

@@ -0,0 +1,51 @@
#!/usr/bin/env python3.8
"""Merges sources of a Dart target and its dependencies"""
# 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.
import argparse
import json
import os
import sys
def main():
parser = argparse.ArgumentParser(
'Merges sources of a Dart target and its dependencies',
fromfile_prefix_chars='@')
parser.add_argument(
'--output',
help='Path to output the final list',
type=argparse.FileType('w'),
required=True)
parser.add_argument(
'--depfile',
help='Path to the depfile to generate',
type=argparse.FileType('w'),
required=True)
parser.add_argument(
'--sources',
help='Sources of this target',
nargs='*',
)
parser.add_argument(
'--source_lists',
help='Files containing lists of Dart sources',
nargs='*')
args = parser.parse_args()
args.depfile.write(
'{}: {}\n'.format(args.output.name, ' '.join(args.source_lists)))
# Merges sources of this target, and all of its dependencies.
all_sources = set(args.sources)
for f in args.source_lists:
with open(f, 'r') as f:
all_sources.update(json.load(f))
json.dump(sorted(all_sources), args.output)
if __name__ == '__main__':
sys.exit(main())

View File

@@ -0,0 +1,10 @@
# 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.
dart_toolchain = "//flutter/tools/fuchsia/dart:dartlang"
dart_root_gen_dir = get_label_info("//bogus($dart_toolchain)", "root_gen_dir")
# In order to access the target_gen_dir in the Dart toolchain from some location
# in the source tree, use the following:
# dart_target_gen_dir = get_label_info(":bogus($dart_toolchain)", "target_gen_dir")

View File

@@ -0,0 +1,72 @@
#!/usr/bin/env python3.8
# 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.
import argparse
import os
import sys
import pathlib
def main():
parser = argparse.ArgumentParser(
"Verifies that all .dart files are included in sources, and sources don't include nonexsitent files"
)
parser.add_argument(
"--source_dir",
help="Path to the directory containing the package sources",
required=True)
parser.add_argument(
"--stamp",
help="File to touch when source checking succeeds",
required=True)
parser.add_argument(
"sources", help="source files", nargs=argparse.REMAINDER)
args = parser.parse_args()
actual_sources = set()
# Get all dart sources from source directory.
src_dir_path = pathlib.Path(args.source_dir)
for (dirpath, dirnames, filenames) in os.walk(src_dir_path, topdown=True):
relpath_to_src_root = pathlib.Path(dirpath).relative_to(src_dir_path)
actual_sources.update(
os.path.normpath(relpath_to_src_root.joinpath(filename))
for filename in filenames
if pathlib.Path(filename).suffix == ".dart")
expected_sources = set(args.sources)
# It is possible for sources to include dart files outside of source_dir.
actual_sources.update(
[
s for s in (expected_sources - actual_sources)
if src_dir_path.joinpath(s).resolve().exists()
],
)
if actual_sources == expected_sources:
with open(args.stamp, "w") as stamp:
stamp.write("Success!")
return 0
def sources_to_abs_path(sources):
return sorted(str(src_dir_path.joinpath(s)) for s in sources)
missing_sources = actual_sources - expected_sources
if missing_sources:
print(
'\nSource files found that were missing from the "sources" parameter:\n{}\n'
.format("\n".join(sources_to_abs_path(missing_sources))),
)
nonexistent_sources = expected_sources - actual_sources
if nonexistent_sources:
print(
'\nSource files listed in "sources" parameter but not found:\n{}\n'.
format("\n".join(sources_to_abs_path(nonexistent_sources))),
)
return 1
if __name__ == "__main__":
sys.exit(main())

View File

@@ -0,0 +1,36 @@
#!/usr/bin/env python3.8
# 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.
import argparse
import os
import subprocess
import sys
def main():
parser = argparse.ArgumentParser(
description=
'Executes a command, then rewrites the depfile, converts all absolute paths to relative'
)
parser.add_argument(
'--depfile', help='Path to the depfile to rewrite', required=True)
parser.add_argument(
'command', nargs='+', help='Positional args for the command to run')
args = parser.parse_args()
retval = subprocess.call(args.command)
if retval != 0:
return retval
lines = []
with open(args.depfile, 'r') as f:
for line in f:
lines.append(' '.join(os.path.relpath(p) for p in line.split()))
with open(args.depfile, 'w') as f:
f.write('\n'.join(lines))
if __name__ == '__main__':
sys.exit(main())

View File

@@ -0,0 +1,330 @@
# 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.
# Declare data files to be accessible at runtime on the target device.
#
# A resource() target looks just like a copy() target but $outputs are
# relative target paths. Using $data_deps to this resource() target in
# each target whose code uses $outputs at runtime ensures that the files
# will be present on the system.
#
# If the file is not in the source tree, it should be generated by another
# target in the build listed in $deps. If that would be a generated_file()
# target, then use generated_resource() instead of resource().
#
# Parameters
#
# data_deps
# Optional: Additional dependencies for the runtime image. These are
# included in the image if this target is, but are not related to the
# $sources list.
# Type: list(label)
#
# deps
# Optional: Targets that produce $sources. Any files listed in
# $sources that are produced by the build should be produced by a
# target listed here. This is the only thing that guarantees those
# files will have been built by the time the image is being packed.
# Targets reached only via this $deps list will *not* contribute their
# own contents to the image directly. For that, list them in $data_deps.
# Targets listed here are used only to produce the $sources files.
# Type: list(label)
#
# outputs
# Required: List of one runtime path. This must be a relative path (no
# leading `/`). It can use placeholders based on $sources; see copy()
# and `gn help source_expansion`. When this resource() target is in
# the dependency graph of a zbi() target, then this is the path within
# the BOOTFS, which appears at /boot in the namespace of early-boot and
# standalone Zircon processes.
# Type: list(path)
#
# sources
# Required: List of files in the source tree or build that become $outputs.
# See copy() for details.
# Type: list(file)
#
# See copy() for other parameters.
template("resource") {
if (invoker.sources != []) {
_label = get_label_info(":$target_name", "label_with_toolchain")
}
group(target_name) {
forward_variables_from(invoker,
"*",
[
"metadata",
"outputs",
"sources",
])
metadata = {
# Used by the distribution_manifest() template.
distribution_entries_barrier = []
distribution_entries = []
# Used by the zbi() template.
zbi_input_barrier = []
if (defined(invoker.metadata)) {
forward_variables_from(invoker.metadata, "*")
}
# Stop *_manifest() and zbi_test() from picking up files or
# zbi_input() items from the deps, but let them reach the data_deps.
if (defined(data_deps)) {
distribution_entries_barrier += data_deps
zbi_input_barrier += data_deps
}
foreach(source, invoker.sources) {
foreach(target, process_file_template([ source ], invoker.outputs)) {
assert(rebase_path(target, "foo") != target,
"`outputs` in resource() cannot start with /")
distribution_entries += [
{
source = rebase_path(source, root_build_dir)
destination = target
label = _label
},
]
}
}
}
}
}
# Declare data files to be accessible at runtime on the target device.
#
# Similar to resource() but with a different interface that allows grouping
# multiple files into a single target when their packaged paths don't follow
# a common pattern.
#
# Parameters
#
# data_deps
# Optional: Additional dependencies for the runtime image. These are
# included in the image if this target is, but are not related to the
# $sources list.
# Type: list(label)
#
# deps
# Optional: Targets that produce $sources. Any files listed in
# $sources that are produced by the build should be produced by a
# target listed here. This is the only thing that guarantees those
# files will have been built by the time the image is being packed.
# Targets reached only via this $deps list will *not* contribute their
# own contents to the image directly. For that, list them in $data_deps.
# Targets listed here are used only to produce the $sources files.
# Type: list(label)
#
# files
# Required: List of scopes containing `source` and `dest` paths.
# `source` paths are local file paths.
# `dest` paths are packaged paths.
# For instance:
# files = [
# {
# source = "//path/to/file.txt"
# dest = "data/first.txt"
# },
# {
# source = "//path/to/other_file.txt",
# dest = "data/second.txt"
# },
# ]
# Type: list(scope)
#
# testonly, visibility
template("resource_group") {
if (invoker.files != []) {
_label = get_label_info(":$target_name", "label_with_toolchain")
}
group(target_name) {
forward_variables_from(invoker,
[
"deps",
"testonly",
"visibility",
])
metadata = {
# Used by the distribution_manifest() template.
distribution_entries_barrier = []
distribution_entries = []
# Used by the zbi() template.
zbi_input_barrier = []
if (defined(invoker.metadata)) {
forward_variables_from(invoker.metadata, "*")
}
# Stop *_manifest() and zbi_test() from picking up files or
# zbi_input() items from the deps, but let them reach the data_deps.
if (defined(data_deps)) {
distribution_entries_barrier += data_deps
zbi_input_barrier += data_deps
}
foreach(file, invoker.files) {
distribution_entries += [
{
source = rebase_path(file.source, root_build_dir)
destination = file.dest
label = _label
},
]
}
}
}
}
# resource_tree() is similar to resource() but makes it easy to replicate
# a tree of sources files, relative to a given sources path prefix, to a
# given destination directory.
#
# For example:
#
# //some/dir/BUILD.gn:
# resource_trees("my-resources") {
# sources_root = "res"
# sources = [
# foo.resource",
# bar/bar-1.resource",
# ]
# dest_dir = "data/resources"
# }
#
# Will declare the following installation requirements:
#
# //some/dir/res/foo.resource --> data/resources/foo.resource
# //some/dir/res/bar/bar.resource --> data/resources/bar/bar.resource
#
# This is difficult to do with resource() because GN source expansion
# cannot preserve the original sources input paths.
#
# This template is useful to avoid calling resource() multiple times
# in a loop when dealing with resource files laid out into different
# sub-directories. Note that the files cannot be renamed though!
#
# Parameters
#
# source_root
# Optional: A path prefix that is prepended to all items in the 'sources'
# list. If not specified, the current target's directory is used.
# Type: string(path)
#
# sources
# Required: List of files in the source tree or build that will be
# installed. Each 'file' item in this list is installed to
# '$dest_dir/$file', and its content taken from '$sources_root/$file'.
# Note that unlike resource(), there is no way to transform or expand
# source paths.
# Type: list(file)
#
# dest_dir
# Required: Destination path where all sources are installed.
# Cannot start with a "/". Use an empty string to install files directory
# to the package's top-level directory.
# Type: string(path)
#
# data_deps
# Optional: Additional dependencies for the runtime image. These are
# included in the image if this target is, but are not related to the
# $sources list.
# Type: list(label)
#
# deps
# Optional: Targets that produce $sources. Any files listed in
# $sources that are produced by the build should be produced by a
# target listed here. This is the only thing that guarantees those
# files will have been built by the time the image is being packed.
# Targets reached only via this $deps list will *not* contribute their
# own contents to the image directly. For that, list them in $data_deps.
# Targets listed here are used only to produce the $sources files.
# Type: list(label)
#
template("resource_tree") {
assert(defined(invoker.sources), "sources is required!")
assert(defined(invoker.dest_dir), "dest_dir is required!")
dest_dir = invoker.dest_dir
if (dest_dir != "") {
# Sanitize dest_dir and append a directory separator.
assert(rebase_path(dest_dir, "foo") != dest_dir,
"dest_dir cannot start with /: $dest_dir")
assert(dest_dir != "." && dest_dir != ".." &&
string_replace(dest_dir, "./", "") == dest_dir,
"dest_dir cannot contain . or .. path elements!: $dest_dir")
dest_dir = string_replace(dest_dir + "/", "//", "/")
}
if (defined(invoker.sources_root)) {
assert(invoker.sources_root != "", "sources_root cannot be empty!")
sources_prefix = invoker.sources_root
# Append trailing separator if needed
if (string_replace(sources_prefix + "###", "/###", "") ==
sources_prefix + "###") {
sources_prefix += "/"
}
} else {
sources_prefix = ""
}
target_label = get_label_info(":$target_name", "label_with_toolchain")
if (invoker.sources == []) {
# Support resource_tree() targets with empty sources list.
not_needed(invoker,
[
"dest_dir",
"sources_root",
])
not_needed([
"sources_prefix",
"dest_dir",
"target_label",
])
}
group(target_name) {
forward_variables_from(invoker,
"*",
[
"dest_dir",
"metadata",
"sources",
"sources_root",
])
metadata = {
# Used by the distribution_manifest() template.
distribution_entries_barrier = []
distribution_entries = []
# Used by the zbi() template.
zbi_input_barrier = []
if (defined(invoker.metadata)) {
forward_variables_from(invoker.metadata, "*")
}
# Stop *_manifest() and zbi_test() from picking up files or
# zbi_input() items from the deps, but let them reach the data_deps.
if (defined(data_deps)) {
distribution_entries_barrier += data_deps
zbi_input_barrier += data_deps
}
foreach(_source, invoker.sources) {
distribution_entries += [
{
source = rebase_path(sources_prefix + _source, root_build_dir)
destination = dest_dir + _source
label = target_label
},
]
}
}
}
}

View File

@@ -0,0 +1,24 @@
# 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.
import("//build/fuchsia/sdk.gni")
import("//flutter/tools/fuchsia/fidl/fidl.gni")
import("//flutter/tools/fuchsia/fidl/toolchain.gni")
import("//flutter/tools/fuchsia/sdk/sdk_targets.gni")
import("//flutter/tools/fuchsia/toolchain/basic_toolchain.gni")
# A toolchain dedicated to processing FIDL libraries.
# The only targets in this toolchain are action() targets, so it
# has no real tools. But every toolchain needs stamp and copy.
if (current_toolchain == default_toolchain) {
basic_toolchain("fidling") {
expected_label = fidl_toolchain
}
}
if (current_toolchain != default_toolchain) {
sdk_targets("fidl_library") {
meta = "$fuchsia_sdk_path/meta/manifest.json"
}
}

View File

@@ -0,0 +1,46 @@
# 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.
import("//build/fuchsia/sdk.gni")
import("//flutter/tools/fuchsia/dart/toolchain.gni")
import("//flutter/tools/fuchsia/fidl/toolchain.gni")
# Declares a FIDL library.
#
# Depending on the toolchain in which this targets is expanded, it will yield
# different results:
# - in the FIDL toolchain, it will compile its source files into an
# intermediate representation consumable by language bindings generators;
# - in the target or shared toolchain, this will produce a source_set
# containing language-specific bindings.
template("fidl") {
# Allow generated targets visibility to their dependant generated targets
if (defined(invoker.visibility)) {
invoker.visibility += [ ":*" ]
}
assert(!defined(invoker.deps),
"All FIDL dependencies are inherently " +
"public, use 'public_deps' instead of 'deps'.")
deps = []
if (current_toolchain == dart_toolchain) {
import("//flutter/tools/fuchsia/dart/fidl_dart.gni")
fidl_dart(target_name) {
forward_variables_from(invoker, "*")
}
} else {
if (current_toolchain == fidl_toolchain) {
import("//flutter/tools/fuchsia/fidl/fidl_library.gni")
fidl_library(target_name) {
forward_variables_from(invoker, "*")
}
} else {
not_needed("*")
}
}
}

View File

@@ -0,0 +1,143 @@
# 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.
import("//flutter/tools/executable_action.gni")
import("//flutter/tools/fuchsia/fidl/fidl.gni")
import("//flutter/tools/fuchsia/fidl/toolchain.gni")
# Generates some representation of a FIDL library that's consumable by Language
# bindings generators.
#
# The parameters for this template are defined in //flutter/tools/fuchsia/fidl/fidl.gni. The
# relevant parameters in this template are:
# - name;
# - sources.
template("fidl_library") {
assert(
current_toolchain == fidl_toolchain,
"This template can only be used in the FIDL toolchain $fidl_toolchain.")
assert(defined(invoker.sources), "A FIDL library requires some sources.")
library_name = target_name
if (defined(invoker.name)) {
library_name = invoker.name
}
response_file = "$target_gen_dir/$target_name.args"
fidl_stem = "$target_gen_dir/$target_name.fidl"
json_representation = "$fidl_stem.json"
coding_tables = "$fidl_stem.tables.c"
main_target_name = target_name
response_file_target_name = "${target_name}_response_file"
compilation_target_name = "${target_name}_compile"
# Only artifacts that have various associated FIDL generated targets.
fidl_deps = []
# Artifacts other than FIDL, that are also dependencies.
non_fidl_deps = []
if (defined(invoker.non_fidl_deps)) {
non_fidl_deps += invoker.non_fidl_deps
}
if (defined(invoker.deps)) {
fidl_deps += invoker.deps - non_fidl_deps
}
if (defined(invoker.public_deps)) {
fidl_deps += invoker.public_deps
}
action(response_file_target_name) {
visibility = [ ":*" ]
script = "//flutter/tools/fuchsia/fidl/gen_response_file.py"
forward_variables_from(invoker,
[
"deps",
"public_deps",
"sources",
"testonly",
])
libraries = "$target_gen_dir/$main_target_name.libraries"
outputs = [
response_file,
libraries,
]
args = [
"--out-response-file",
rebase_path(response_file, root_build_dir),
"--out-libraries",
rebase_path(libraries, root_build_dir),
"--json",
rebase_path(json_representation, root_build_dir),
"--tables",
rebase_path(coding_tables, root_build_dir),
"--name",
library_name,
"--sources",
] + rebase_path(sources, root_build_dir)
if (fidl_deps != []) {
dep_libraries = []
foreach(dep, fidl_deps) {
gen_dir = get_label_info(dep, "target_gen_dir")
name = get_label_info(dep, "name")
dep_libraries += [ "$gen_dir/$name.libraries" ]
}
inputs = dep_libraries
args += [ "--dep-libraries" ] + rebase_path(dep_libraries, root_build_dir)
}
}
executable_action(compilation_target_name) {
forward_variables_from(invoker, [ "testonly" ])
visibility = [ ":*" ]
tool = "${fuchsia_sdk_path}/tools/fidlc"
inputs = [ response_file ]
outputs = [
coding_tables,
json_representation,
]
args = [ "@" + rebase_path(response_file, root_build_dir) ]
deps = [ ":$response_file_target_name" ] + non_fidl_deps
}
group(main_target_name) {
forward_variables_from(invoker,
[
"testonly",
"visibility",
"response_file",
])
# Metadata to allow us to query all FIDL IR files.
metadata = {
fidl_json = [ rebase_path(json_representation, root_build_dir) ]
generated_sources = fidl_json
}
public_deps = [
":$compilation_target_name",
":$response_file_target_name",
]
}
}

View File

@@ -0,0 +1,122 @@
#!/usr/bin/env python3.8
# 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.
import argparse
import os
import string
import sys
def read_libraries(libraries_path):
with open(libraries_path) as f:
lines = f.readlines()
return [l.rstrip("\n") for l in lines]
def write_libraries(libraries_path, libraries):
directory = os.path.dirname(libraries_path)
if not os.path.exists(directory):
os.makedirs(directory)
with open(libraries_path, "w+") as f:
for library in libraries:
f.write(library)
f.write("\n")
def main():
parser = argparse.ArgumentParser(
description="Generate response file for FIDL frontend")
parser.add_argument(
"--out-response-file",
help="The path for for the response file to generate",
required=True)
parser.add_argument(
"--out-libraries",
help="The path for for the libraries file to generate",
required=True)
parser.add_argument(
"--json", help="The path for the JSON file to generate, if any")
parser.add_argument(
"--tables", help="The path for the tables file to generate, if any")
parser.add_argument(
"--deprecated-fuchsia-only-c-client",
help="The path for the C simple client file to generate, if any")
parser.add_argument(
"--deprecated-fuchsia-only-c-header",
help="The path for the C header file to generate, if any")
parser.add_argument(
"--deprecated-fuchsia-only-c-server",
help="The path for the C simple server file to generate, if any")
parser.add_argument(
"--name", help="The name for the generated FIDL library, if any")
parser.add_argument(
"--depfile", help="The name for the generated depfile, if any")
parser.add_argument(
"--sources", help="List of FIDL source files", nargs="*")
parser.add_argument(
"--dep-libraries", help="List of dependent libraries", nargs="*")
parser.add_argument(
"--experimental-flag",
help="List of experimental flags",
action="append")
args = parser.parse_args()
target_libraries = []
for dep_libraries_path in args.dep_libraries or []:
dep_libraries = read_libraries(dep_libraries_path)
for library in dep_libraries:
if library in target_libraries:
continue
target_libraries.append(library)
target_libraries.append(" ".join(sorted(args.sources)))
write_libraries(args.out_libraries, target_libraries)
response_file = []
response_file.append('--experimental allow_new_syntax')
if args.json:
response_file.append("--json %s" % args.json)
if args.tables:
response_file.append("--tables %s" % args.tables)
if args.deprecated_fuchsia_only_c_client:
response_file.append(
"--deprecated-fuchsia-only-c-client %s" %
args.deprecated_fuchsia_only_c_client)
if args.deprecated_fuchsia_only_c_header:
response_file.append(
"--deprecated-fuchsia-only-c-header %s" %
args.deprecated_fuchsia_only_c_header)
if args.deprecated_fuchsia_only_c_server:
response_file.append(
"--deprecated-fuchsia-only-c-server %s" %
args.deprecated_fuchsia_only_c_server)
if args.name:
response_file.append("--name %s" % args.name)
if args.depfile:
response_file.append("--depfile %s" % args.depfile)
if args.experimental_flag:
for experimental_flag in args.experimental_flag:
response_file.append("--experimental %s" % experimental_flag)
response_file.extend(
["--files %s" % library for library in target_libraries])
with open(args.out_response_file, "w+") as f:
f.write(" ".join(response_file))
f.write("\n")
if __name__ == "__main__":
sys.exit(main())

View File

@@ -0,0 +1,5 @@
# 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.
fidl_toolchain = "//flutter/tools/fuchsia/fidl:fidling"

View File

@@ -0,0 +1,24 @@
# 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.
import("//flutter/tools/fuchsia/flutter/flutter_build_config.gni")
declare_args() {
# If set to true, will force the runners to be built in
# product mode which means they will not have an exposed vm service
flutter_force_product = false
}
declare_args() {
if (flutter_force_product) {
# Product AOT
flutter_default_build_cfg = flutter_release_build_cfg
} else if (is_debug) {
# Non-product JIT
flutter_default_build_cfg = flutter_debug_build_cfg
} else {
# Non-product AOT
flutter_default_build_cfg = flutter_profile_build_cfg
}
}

View File

@@ -0,0 +1,56 @@
# 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.
# Non-product JIT is "debug". It launches the vm service.
# Non-product AOT is "profile". It also launches the vm service, but lacks tools that rely on JIT.
# Product AOT is "release". It doesn't launch the vm service.
# Builds the component in a non-product JIT build. This will
# launch the vm service in the runner.
flutter_debug_build_cfg = {
runtime_meta = "//flutter/shell/platform/fuchsia/flutter/meta/jit_runtime"
runner_dep = "//flutter/shell/platform/fuchsia/flutter:jit"
platform_name = "flutter_runner"
is_aot = false
is_product = false
enable_asserts = true
}
# Builds the component in a non-product AOT build. This will
# launch the vm service in the runner.
# This configuration is not compatible with a --release build since the
# profile aot runner is built without asserts.
flutter_aot_debug_build_cfg = {
runtime_meta = "//flutter/shell/platform/fuchsia/flutter/meta/aot_runtime"
runner_dep = "//flutter/shell/platform/fuchsia/flutter:aot"
platform_name = "flutter_runner"
is_aot = true
is_product = false
enable_asserts = true
}
# Builds the component in a non-product AOT build. This will
# launch the vm service in the runner.
flutter_profile_build_cfg = {
runtime_meta =
"//flutter/shell/platform/fuchsia/flutter/meta/aot_runtime" # profile
# runner
runner_dep = "//flutter/shell/platform/fuchsia/flutter:aot"
platform_name = "flutter_runner"
is_aot = true
is_product = false
enable_asserts = false
}
# Builds the component in a product AOT build. This will
# not launch the vm service in the runner.
flutter_release_build_cfg = {
runtime_meta =
"//flutter/shell/platform/fuchsia/flutter/meta/aot_product_runtime"
runner_dep = "//flutter/shell/platform/fuchsia/flutter:aot_product"
platform_name = "flutter_runner"
is_aot = true
is_product = true
enable_asserts = false
}

View File

@@ -0,0 +1,137 @@
# 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.
import("//flutter/tools/fuchsia/dart/dart.gni")
import("//flutter/tools/fuchsia/dart/dart_library.gni")
import("//flutter/tools/fuchsia/flutter/config.gni")
import("//flutter/tools/fuchsia/flutter/internal/flutter_dart_component.gni")
# Defines a Flutter component which can be used in a fuchsia package
#
# Flutter components require at least one library which contains a main
# entry point. The library should be defined using the dart_library.gni.
#
# ```
# dart_library("lib") {
# package_name = "my_library"
# sources = [ "main.dart" ]
# deps = [ "//third_party/dart-pkg/git/flutter/packages/flutter" ]
# }
# ```
#
# Once a library is defined a flutter component can be created which
# depends on this package. If the component needs any other resources they may
# be defined using the resource target and added to the components deps.
#
# ```
# resource("text-file") {
# sources = [ "text_file.txt" ]
# outputs = [ "data/text_file.txt" ]
# }
#
# flutter_component("my-component") {
# manifest = "meta/my-component.cmx"
# main_package = "my_library"
# deps = [
# ":lib",
# ":text-file",
# ]
# }
# ```
#
# Once a component is defined it can be added as a dep of a fuchsia_package
# ```
# fuchsia_package("my-package") {
# deps = [
# ":my-component",
# ]
# }
# ```
#
# Parameters
#
# manifest (required)
# The component manifest
# Type: path
#
# main_package (optional)
# The name of the package containing main_dart
# Type: string
# Default: component_name with dashes replaced by underscores, if defined.
# Otherwise, the target_name with dashes replaced by underscores will be
# used.
#
# component_name (optional)
# The name of the component.
# Type: string
# Default: target_name
#
# main_dart (optional)
# File containing the main function of the component.
# Type: string
# Default: main.dart
#
# package_root (optional)
# The root of the package generated for this component. Each component must
# have a unique package_root. For each component, there must be a
# pubspec.yaml and an analysis_options.yaml at the package root.
# Type: path
# Default: "."
#
# build_cfg (optional)
# Specifies the parameters for building the component.
# See //flutter/tools/fuchsia/flutter/flutter_build_config.gni for predefined configs.
#
# deps
# testonly
# visibility
template("flutter_component") {
assert(defined(invoker.manifest), "Must define manifest")
_component_deps = []
if (defined(invoker.deps)) {
_component_deps += invoker.deps
}
if (defined(invoker.build_cfg)) {
_build_cfg = invoker.build_cfg
} else {
_build_cfg = flutter_default_build_cfg
}
if (defined(invoker.main_package)) {
_main_package = invoker.main_package
} else if (defined(invoker.component_name)) {
_main_package = string_replace(invoker.component_name, "-", "_")
} else {
_main_package = string_replace(target_name, "-", "_")
}
if (defined(invoker.main_dart)) {
_main_dart = invoker.main_dart
} else {
_main_dart = "main.dart"
}
# We need to specify the runner as a dependency to be bundled with the dill
# files generated by dart_kernel.
_component_deps += [ _build_cfg.runner_dep ]
flutter_dart_component(target_name) {
forward_variables_from(invoker,
"*",
[
"build_cfg",
"deps",
"main_dart",
"main_package",
])
deps = _component_deps
main_dart = _main_dart
main_package = _main_package
build_cfg = _build_cfg
}
}

View File

@@ -0,0 +1,244 @@
# 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.
import("//flutter/tools/executable_action.gni")
import("//flutter/tools/fuchsia/dart/config.gni")
import("//flutter/tools/fuchsia/dart/dart.gni")
import("//flutter/tools/fuchsia/dart/dart_package_config.gni")
import("//flutter/tools/fuchsia/dart/kernel/dart_kernel.gni")
import("//flutter/tools/fuchsia/dist/resource.gni")
import("//flutter/tools/fuchsia/sdk/cmc.gni")
import("//flutter/tools/fuchsia/sdk/component.gni")
# Defines a component which will run in a flutter_runner or dart_runner
#
# This template is not intended to be used directly. Users should use the
# flutter_component and dart_component actions instead.
#
# Parameters
#
# manifest (required)
# The component manifest
# Type: path
#
# main_package (required)
# The name of the package containing the main_dart
# Type: string
#
# component_name (optional)
# The name of the component.
# Type: string
# Default: target_name
#
# build_cfg (required)
# A description of how to build this component. This object needs
# to contain the following variables:
# runtime_meta: a path to the partial cmx file containing the runner
# platform_name: either 'dart_runner' or 'flutter_runner'
# is_aot: a boolean indicating if this is an AOT build
# is_product: a boolean indicating if this is a product build
# enable_asserts: whether we should enable asserts when compiling
#
# main_dart (required)
# File containing the main function of the component.
# Type: string
#
# generate_asset_manifest (optional)
# If true, will generate an asset manifest for this component
# Type: boolean
# Default: false
#
# deps
# testonly
# visibility
template("flutter_dart_component") {
assert(defined(invoker.manifest), "must specify a manifest file")
assert(defined(invoker.build_cfg), "must specify build_cfg")
assert(defined(invoker.main_dart), "Must specify main_dart")
assert(defined(invoker.main_package), "Must specify main_package")
build_cfg = invoker.build_cfg
_component_deps = []
if (defined(invoker.deps)) {
_component_deps += invoker.deps
}
if (defined(invoker.component_name)) {
_component_name = invoker.component_name
} else {
_component_name = target_name
}
# merge the runner cmx into this one which allows us to switch runners based
# on compilation modes
_merged_target_name = "${target_name}_merged.cmx"
cmc_merge(_merged_target_name) {
forward_variables_from(invoker,
[
"testonly",
"visibility",
])
sources = [
invoker.manifest,
rebase_path(build_cfg.runtime_meta, "."),
]
}
_merged_outputs = []
_merged_outputs += get_target_outputs(":$_merged_target_name")
_merged_manifest = _merged_outputs[0]
_component_deps += [ ":$_merged_target_name" ]
_dart_package_config_target_name = "${target_name}_dart_package"
dart_package_config(_dart_package_config_target_name) {
forward_variables_from(invoker,
[
"testonly",
"visibility",
])
deps = _component_deps
}
_package_config_output = []
_package_config_output =
get_target_outputs(":$_dart_package_config_target_name")
_packages_path = _package_config_output[0]
_kernel_target_name = _component_name + "_kernel"
_kernel_target_dep_name = _kernel_target_name + "_gen_file"
_kernel_path = "$target_gen_dir/__untraced_dart_kernel__/${target_name}.dil"
dart_kernel(_kernel_target_name) {
kernel_path = _kernel_path
# establishes a dependency chain for the snapshot since
# the kernel is wrapped in a group
kernel_target_name = _kernel_target_dep_name
forward_variables_from(invoker,
[
"testonly",
"visibility",
"main_dart",
"main_package",
])
deps = [ ":$_dart_package_config_target_name" ]
packages_path = _packages_path
args = [
"--component-name",
_component_name,
]
# always generate a manifest for fuchsia builds. If this is an aot build
# the kernel will ignore this variable.
generate_manifest = true
platform_name = build_cfg.platform_name
product = build_cfg.is_product
is_aot = build_cfg.is_aot
}
_component_deps += [ ":$_kernel_target_name" ]
if (build_cfg.is_aot) {
_snapshot_path = "$target_gen_dir/${_component_name}_snapshot.so"
_snapshot_target_name = target_name + "_snapshot"
_stats_json_path =
"$target_gen_dir/${_component_name}/stats/symbol_sizes.json"
if (build_cfg.is_product) {
_gen_snapshot_script_target = gen_snapshot_product
} else {
_gen_snapshot_script_target = gen_snapshot
}
executable_action(_snapshot_target_name) {
forward_variables_from(invoker,
[
"testonly",
"visibility",
])
deps = [ ":$_kernel_target_dep_name" ]
inputs = [ _kernel_path ]
outputs = [
_snapshot_path,
_stats_json_path,
]
if (defined(invoker.toolchain)) {
toolchain = invoker.toolchain
} else {
toolchain = host_toolchain
}
# Construct the host toolchain version of the tool.
# host_tool = invoker.tool + "($toolchain)"
host_tool = _gen_snapshot_script_target + "($toolchain)"
# Get the path to the executable. Currently, this assumes that the tool
# does not specify output_name so that the target name is the name to use.
# If that's not the case, we'll need another argument to the script to
# specify this, since we can't know what the output name is (it might be in
# another file not processed yet).
host_executable =
get_label_info(host_tool, "root_out_dir") + "/" +
get_label_info(host_tool, "name") + host_executable_suffix
# Add the executable itself as an input.
inputs += [ host_executable ]
deps += [ host_tool ]
tool = host_executable
args = [
"--deterministic",
"--snapshot_kind=app-aot-elf",
"--elf=" + rebase_path(_snapshot_path, root_build_dir),
"--print-instructions-sizes-to=" +
rebase_path(_stats_json_path, root_build_dir),
]
# No asserts in debug or release product.
# No asserts in non-product release
# Yes asserts in non-product debug.
# if (is_debug && !dart_force_product)
if (build_cfg.enable_asserts) {
args += [ "--enable_asserts" ]
}
args += [ rebase_path(_kernel_path, root_build_dir) ]
}
# copy the snapshot as a resource
_snapshot_resource_target_name = "${target_name}_snapshot_resource"
resource(_snapshot_resource_target_name) {
sources = [ _snapshot_path ]
outputs = [ "data/${_component_name}/app_aot_snapshot.so" ]
}
_component_deps += [
":$_snapshot_resource_target_name",
":$_snapshot_target_name",
]
}
fuchsia_component(target_name) {
forward_variables_from(invoker,
[
"testonly",
"visibility",
"component_name",
])
deps = _component_deps
manifest = _merged_manifest
}
}

0
engine/src/flutter/tools/fuchsia/make_build_info.py Normal file → Executable file
View File

View File

@@ -0,0 +1,145 @@
#!/usr/bin/env python3.8
"""Creats a Python zip archive for the input main source."""
# 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.
import argparse
import json
import os
import shutil
import sys
import zipapp
def main():
parser = argparse.ArgumentParser(
'Creates a Python zip archive for the input main source')
parser.add_argument(
'--target_name',
help='Name of the build target',
required=True,
)
parser.add_argument(
'--main_source',
help='Path to the source containing the main function',
required=True,
)
parser.add_argument(
'--main_callable',
help=
'Name of the the main callable, that is the entry point of the generated archive',
required=True,
)
parser.add_argument(
'--gen_dir',
help='Path to gen directory, used to stage temporary directories',
required=True,
)
parser.add_argument('--output', help='Path to output', required=True)
parser.add_argument(
'--sources',
help='Sources of this target, including main source',
nargs='*',
)
parser.add_argument(
'--library_infos',
help='Path to the library infos JSON file',
type=argparse.FileType('r'),
required=True,
)
parser.add_argument(
'--depfile',
help='Path to the depfile to generate',
type=argparse.FileType('w'),
required=True,
)
args = parser.parse_args()
infos = json.load(args.library_infos)
# Temporary directory to stage the source tree for this python binary,
# including sources of itself and all the libraries it imports.
#
# It is possible to have multiple python_binaries in the same directory, so
# using target name, which should be unique in the same directory, to
# distinguish between them.
app_dir = os.path.join(args.gen_dir, args.target_name)
os.makedirs(app_dir, exist_ok=True)
# Copy over the sources of this binary.
for source in args.sources:
basename = os.path.basename(source)
if basename == '__main__.py':
print(
'__main__.py in sources of python_binary is not supported, see https://fxbug.dev/73576',
file=sys.stderr,
)
return 1
dest = os.path.join(app_dir, basename)
shutil.copy2(source, dest)
# For writing a depfile.
files_to_copy = []
# Make sub directories for all libraries and copy over their sources.
for info in infos:
dest_lib_root = os.path.join(app_dir, info['library_name'])
os.makedirs(dest_lib_root, exist_ok=True)
src_lib_root = info['source_root']
# Sources are relative to library root.
for source in info['sources']:
src = os.path.join(src_lib_root, source)
dest = os.path.join(dest_lib_root, source)
# Make sub directories if necessary.
os.makedirs(os.path.dirname(dest), exist_ok=True)
files_to_copy.append(src)
shutil.copy2(src, dest)
args.depfile.write('{}: {}\n'.format(args.output, ' '.join(files_to_copy)))
# Main module is the main source without its extension.
main_module = os.path.splitext(os.path.basename(args.main_source))[0]
# Manually create a __main__.py file for the archive, instead of using the
# `main` parameter from `create_archive`. This way we can import everything
# from the main module (create_archive only `import pkg`), which is
# necessary for including all test cases for unit tests.
#
# TODO(https://fxbug.dev/73576): figure out another way to support unit
# tests when users need to provide their own custom __main__.py.
main_file = os.path.join(app_dir, "__main__.py")
with open(main_file, 'w') as f:
f.write(
f'''
import sys
from {main_module} import *
sys.exit({args.main_callable}())
''')
zipapp.create_archive(
app_dir,
target=args.output,
interpreter='/usr/bin/env python3.8',
compressed=True,
)
# Manually remove the temporary app directory and all the files, instead of
# using shutil.rmtree. rmtree records reads on directories which throws off
# the action tracer.
for root, dirs, files in os.walk(app_dir, topdown=False):
for file in files:
os.remove(os.path.join(root, file))
for dir in dirs:
os.rmdir(os.path.join(root, dir))
os.rmdir(app_dir)
if __name__ == '__main__':
sys.exit(main())

View File

@@ -0,0 +1,123 @@
# 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.
import("//flutter/tools/python/python3_action.gni")
# Defines a Python binary.
#
# Example
#
# ```
# python_binary("main") {
# main_source = "main.py"
# main_callable = "main"
# sources = [
# "foo.py",
# "bar.py",
# ]
# output_name = "main.pyz"
# deps = [ "//path/to/lib" ]
# }
# ```
#
# Parameters
#
# main_source (required)
# Source file including the entry callable for this binary.
# This file will typically contain
# ```
# if __name__ == "__main__":
# main()
# ```
# Type: path
#
# main_callable (optional)
# Main callable, which serves as the entry point of the output zip archive.
# In the example above, this is "main".
# Type: string
# Default: main
#
# output_name (optional)
# Name of the output Python zip archive, must have .pyz as extension.
# Type: string
# Default: ${target_name}.pyz
#
# sources
# deps
# visibility
# testonly
template("python_binary") {
assert(defined(invoker.main_source), "main_source is required")
_library_infos_target = "${target_name}_library_infos"
_library_infos_json = "${target_gen_dir}/${target_name}_library_infos.json"
generated_file(_library_infos_target) {
forward_variables_from(invoker,
[
"testonly",
"deps",
])
visibility = [ ":*" ]
outputs = [ _library_infos_json ]
output_conversion = "json"
data_keys = [ "library_info" ]
walk_keys = [ "library_info_barrier" ]
}
# action(target_name) {
python3_action(target_name) {
forward_variables_from(invoker,
[
"testonly",
"visibility",
])
sources = [ invoker.main_source ]
if (defined(invoker.sources)) {
sources += invoker.sources
}
inputs = [ _library_infos_json ]
deps = [ ":${_library_infos_target}" ]
# Output must be a .pyz, so our build knows to use a vendored Python
# interpreter to run them.
#
# Output a single .pyz file makes the output deterministic, otherwise we'd
# have to list out all the library sources that will be copied to output
# directory, which is not possible because they are not known until the
# generated JSON file is parsed at build time.
_output = "${target_out_dir}/${target_name}.pyz"
if (defined(invoker.output_name)) {
assert(get_path_info(invoker.output_name, "extension") == "pyz",
"output_name must have .pyz as extension")
_output = "${target_out_dir}/${invoker.output_name}"
}
outputs = [ _output ]
_main_callable = "main"
if (defined(invoker.main_callable)) {
_main_callable = invoker.main_callable
}
script = "//flutter/tools/fuchsia/python/package_python_binary.py"
depfile = "${target_out_dir}/${target_name}.d"
args = [ "--sources" ] + rebase_path(sources, root_build_dir) + [
"--target_name",
target_name,
"--main_source",
rebase_path(invoker.main_source, root_build_dir),
"--main_callable",
_main_callable,
"--library_infos",
rebase_path(_library_infos_json, root_build_dir),
"--depfile",
rebase_path(depfile, root_build_dir),
"--gen_dir",
rebase_path(target_gen_dir, root_build_dir),
"--output",
rebase_path(_output, root_build_dir),
]
}
}

View File

@@ -0,0 +1,243 @@
# 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.
import("config/config.gni")
# Internal template for the cmc tool.
#
# Invokes cmc
#
# Example:
#
# ```
# _cmc_tool("validate_cmx") {
# inputs = [ manifest ]
# outputs = [ stamp_file ]
#
# args = [
# "--stamp",
# rebase_path(stamp_file, root_build_dir),
# "validate",
# rebase_path(invoker.manifest),
# ]
# }
# ```
#
# Parameters:
#
# inputs (required)
# List of files that are input for cmc.
# Type: list(path)
#
# outputs (required)
# List paths that are output for the run of cmc.
# Type: list(path)
#
# args (required)
# List command line args for cmc.
# Type: list(path)
#
# deps
# public_deps
# testonly
# visibility
#
template("_cmc_tool") {
action(target_name) {
forward_variables_from(invoker,
[
"deps",
"public_deps",
"testonly",
"visibility",
])
script = "//build/gn_run_binary.py"
_cmc_tool_path = "${fuchsia_tool_dir}/cmc"
assert(defined(invoker.inputs), "inputs is a required parameter.")
assert(defined(invoker.outputs), "outputs is a required parameter.")
assert(defined(invoker.args), "args is a required parameter.")
inputs =
[
_cmc_tool_path,
# Depend on the SDK hash, to ensure rebuild if the SDK tools change.
fuchsia_sdk_manifest_file,
] + invoker.inputs
outputs = invoker.outputs
args = [ rebase_path(_cmc_tool_path, root_build_dir) ] + invoker.args
}
}
# Compiles a Components Framework v2 manifest (.cml) file to .cm
#
# Example:
#
# ```
# cmc_compile(_compiled_manifest_target) {
# forward_variables_from(invoker, [ "deps" ])
# manifest = rebase_path(manifest)
# }
# ```
#
# Parameters:
#
# manifest (required)
# The input Component Framework v2 manifest source (.cml) file.
# The file must have the extension ".cml".
#
# output_name (optional)
# Name of the output file to generate. Defaults to $target_name.
# This should not include a file extension (.cm)
#
# deps
# public_deps
# testonly
# visibility
#
template("cmc_compile") {
output_name = target_name
if (defined(invoker.output_name)) {
output_name = invoker.output_name
}
_cmc_tool(target_name) {
forward_variables_from(invoker,
[
"deps",
"manifest",
"public_deps",
"testonly",
"visibility",
])
assert(defined(manifest), "manifest file required")
inputs = [ manifest ]
output_file = "$target_out_dir/$output_name.cm"
outputs = [ output_file ]
depfile = "$target_out_dir/$target_name.d"
args = [
"compile",
rebase_path(manifest, root_build_dir),
"--output",
rebase_path(output_file, root_build_dir),
"--includeroot",
rebase_path("//", root_build_dir),
"--includepath",
rebase_path("$fuchsia_sdk/pkg/", root_build_dir),
"--depfile",
rebase_path(depfile, root_build_dir),
]
}
}
# Validates a component manifest file
#
# The cmc_validate template will ensure that a given cmx file is conformant to
# the cmx schema, as defined by //tools/cmc/schema.json. A stamp file is
# generated to mark that a given cmx file has passed.
#
# Parameters:
#
# manifest (required)
# [file] The path to the cmx file that is to be validated
#
# deps
# testonly
# visibility
#
template("cmc_validate") {
_cmc_tool(target_name) {
forward_variables_from(invoker,
[
"manifest",
"deps",
"testonly",
"visibility",
])
stamp_file = "$target_gen_dir/$target_name.verified"
assert(defined(manifest), "manifest file required")
inputs = [ manifest ]
outputs = [ stamp_file ]
args = [
"--stamp",
rebase_path(stamp_file, root_build_dir),
"validate",
rebase_path(invoker.manifest),
]
}
}
# Merges multiple component manifest files into one.
#
# Combines mutliple component manifests into a single manifest.
# This is useful for merging fragments of sandbox configurations into
# a single component manifest.
#
# Example
#
# ```
# cmc_merge("combined_cmx") {
# sources = ["sandbox.cmx", "services.cmx", "program.cmx"]
# output_name = "my-component.cmx"
# }
# ```
#
# Parameters
#
# sources
# The list of cmx files to merge together.
#
# Type: list of strings (filepath)
#
# output_name [optional]
# The name of the merged cmx file. This file is created in $target_out_dir.
# If not specified, $target_name.cmx is used.
#
# Type: string
#
# Standard parameters:
# deps
# testonly
# visibility
#
template("cmc_merge") {
_cmc_tool(target_name) {
forward_variables_from(invoker,
[
"deps",
"output_name",
"sources",
"testonly",
"visibility",
])
if (!defined(output_name)) {
output_name = "${target_name}.cmx"
}
merged_output = "${target_out_dir}/${output_name}"
inputs = invoker.sources
outputs = [ merged_output ]
args = [
"merge",
"--output",
rebase_path(merged_output, root_build_dir),
]
foreach(source, sources) {
args += [ rebase_path(source, root_build_dir) ]
}
}
}

View File

@@ -0,0 +1,233 @@
# 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.
import("cmc.gni")
declare_args() {
# Enable code coverage for Fuchsia components. Only applies to v1 components.
fuchsia_code_coverage = false
}
# Defines a Fuchsia component.
# See: https://fuchsia.dev/fuchsia-src/glossary#component
#
# A component is defined by a component manifest.
# A component is a unit of executable software on Fuchsia. When the componet is executed, there are usually many files
# needed at runtime, such as the executable itself, shared libraries, and possibly other data resources. These files are
# specified by using the GN concept of "data_deps".
#
# Components are distributed using a fuchsia package which can contain multiple components. The component manifest and
# the runtime dependencies of the component are packaged using the fuchsia_package rule.
#
# By default, the runtime depenencies of the component are included in the package using relative paths calcualted from
# the "closest" root of: $root_gen_dir, $root_dir, $out_dir. If a specific path is desired in the package, the "resources" parameter can
# be used to explicitly specify the path of a specific file.
#
# A component is launched by a URL which identifies the package and the component manifest.
# See: https://fuchsia.dev/fuchsia-src/glossary#component_url
#
# Example
#
# ```
# fuchsia_component("my_component") {
# manifest = "meta/component-manifest.cmx"
# resources = [
# path = "testdata/use_case1.json"
# dest = "data/testdata/use_case1.json"
# ]
# data_deps = [ ":hello_world_executable"]
# }
# ```
#
# Parameters
#
# manifest
# The source manifest file for this component. This can be either v1 (.cmx)
# or v2 (.cml) manifest.
#
# Type: string (filepath)
#
# data_deps
# The labels of targets that generate the files needed at runtime by the component.
# At minimum, this should include the label of the binary to include in the component.
#
# Type: list of labels
#
# manifest_output_name [optional]
# The name of the manifest file contained in the distribution that this
# component is included in. The output name should have no extension or
# prefixes. The resulting filename will have the extension correct for the
# manifest version. For example, if `manifest` is "foo.cmx"
# and `manifest_output_name` is "bar", the filename will be "bar.cmx". If
# `manifest` is "foo.cml" (a v2 manifest), the filename will be "bar.cm".
#
# Type: string
# Default: The base file name of `manifest` without an extension.
#
# resources [optional]
# Lists additional files to include for runtime access by the component.
# Defines the resources in a package containing this component. A resource
# is a data file that may be produced by the build system, checked in to a
# source repository, or produced by another system that runs before the
# build. Resources are placed in the `data/` directory of the assembled
# package.
#
# Type: list of scopes. Entries in a scope in the resources list:
# path (required)
# Location of resource in source or build directory. If the
# resource is checked in, this will typically be specified
# as a path relative to the BUILD.gn file containing the
# `package()` target. If the resource is generated, this will
# typically be specified relative to `$target_gen_dir`.
#
# dest (required) string (path) Location the resource will be placed within `data/`.
#
# Standard parameters:
# deps
# testonly
# visibility
#
# Metadata
# contents - list of scopes describing files for this component. This metadata is consumed by
# The fuchsia_package rule, which describes the entries used.
# Entries in scope:
# type: the usage type of the element, manifest or resource.
# Each type can have specific properties included in the scope.
# source [type == manifest || resource] The source file to include in
# the package for this component. In the case of v2 components,
# this is the compiled manifest.
# output_name [type == manifest] The basename of the manifest as it should appear in the package.
# manifest_version [type == manifest]
# dest: [type == resource] The package relative path of the resource.
template("fuchsia_component") {
forward_variables_from(invoker,
[
"manifest",
"manifest_output_name",
])
assert(defined(manifest), "manifest file required for this component")
if (!defined(manifest_output_name)) {
manifest_output_name = get_path_info(manifest, "name")
}
# Determine manifest_version from the `manifest` file extension.
_manifest_extension = get_path_info(manifest, "extension")
assert(_manifest_extension == "cmx" || _manifest_extension == "cml",
"Manifest file extension must be .cmx or .cml")
if (_manifest_extension == "cmx") {
_manifest_version = "v1"
} else if (_manifest_extension == "cml") {
_manifest_version = "v2"
}
if (fuchsia_code_coverage) {
if (_manifest_version == "v1") {
merged_manifest = "${target_name}-coverage.cmx"
cmc_merge(merged_manifest) {
forward_variables_from(invoker,
[
"deps",
"testonly",
])
sources = [
"${fuchsia_sdk}/build/enable_coverage_data.cmx",
manifest,
]
output_name = merged_manifest
}
manifest = "${target_out_dir}/${merged_manifest}"
}
}
# The component manifest validated using cmx_validation for v1,
# or cmc_compile for v2.
_cm_validation_target =
"${target_name}_validate_" + get_path_info(manifest, "file")
if (_manifest_version == "v1") {
cmc_validate(_cm_validation_target) {
forward_variables_from(invoker, [ "testonly" ])
manifest = manifest
deps = []
if (defined(invoker.deps)) {
deps += invoker.deps
}
if (fuchsia_code_coverage) {
deps += [ ":${merged_manifest}" ]
}
}
_manifest_source = manifest
} else if (_manifest_version == "v2") {
cmc_compile(_cm_validation_target) {
forward_variables_from(invoker,
[
"deps",
"testonly",
])
manifest = rebase_path(manifest)
}
_compiled_manifest_outputs = get_target_outputs(":$_cm_validation_target")
_manifest_source = _compiled_manifest_outputs[0]
}
group(target_name) {
forward_variables_from(invoker,
[
"data",
"deps",
"data_deps",
"resources",
"testonly",
"visibility",
])
# Data is used for adding files as runtime dependencies. Files used as
# sources in the resources parameter are added as data to make sure
# non-generated files listed are captured as dependencies.
if (!defined(data)) {
data = []
}
if (!defined(resources)) {
resources = []
}
if (!defined(deps)) {
deps = []
}
deps += [ ":$_cm_validation_target" ]
# Create the component metadata entries. These capture the manifest information and
# the resources parameter contents. The metadata is intended for the fuchsia_package rule.
component_contents = [
{
type = "manifest"
source = rebase_path(_manifest_source)
output_name = manifest_output_name
manifest_version = _manifest_version
},
]
foreach(resource, resources) {
data += [ resource.path ]
component_contents += [
{
type = "resource"
source = rebase_path(resource.path)
dest = resource.dest
},
]
}
# The contents of the component are enumerated in the
# metadata.
metadata = {
contents = [ component_contents ]
}
}
}

View File

@@ -0,0 +1,39 @@
# 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.
import("//build/fuchsia/sdk.gni")
declare_args() {
# Path to the fuchsia SDK. This is intended for use in other templates & rules
# to reference the contents of the fuchsia SDK.
fuchsia_sdk = "$fuchsia_sdk_path"
# Build ID uniquely identifying the Fuchsia IDK. This is exposed as a property so
# it can be used to locate images and packages on GCS and as a marker to indicate the
# "version" of the IDK. If it is empty, then it is most likely that something is fatally wrong.
fuchsia_sdk_id = ""
}
declare_args() {
# The SDK manifest file. This is useful to include as a dependency
# for some targets in order to cause a rebuild when the version of the
# SDK is changed.
fuchsia_sdk_manifest_file = "$fuchsia_sdk/meta/manifest.json"
# fuchsia_tool_dir is use to specify the directory in the SDK to locate tools for the
# host cpu architecture. If the host_cpu is not recognized, then tool dir
# defaults to x64.
fuchsia_tool_dir = "$fuchsia_sdk/tools/x64"
if (host_cpu == "x64" || host_cpu == "arm64") {
fuchsia_tool_dir = "${fuchsia_sdk}/tools/${host_cpu}"
}
}
if (fuchsia_sdk_id == "") {
# Note: If we need to expose more than just the id in the future,
# we should consider exposing the entire json object for the metadata vs.
# adding a bunch of variables.
_meta = read_file(fuchsia_sdk_manifest_file, "json")
fuchsia_sdk_id = _meta.id
}

View File

@@ -0,0 +1,92 @@
#!/usr/bin/env python3
#
# 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.
""" Resolve a dart third_party library dependency by returning the path to an
existing downloaded version one of a few possible subdirectories under
//third_party. Some of these pre-downloaded libraries may be directly downloaded
via a //flutter/DEPS entry. Others may be bundled with the Dart SDK, in one of
its provided libraries or its third_party packages.
"""
import argparse
import json
import yaml
import os
import sys
import pkg_resources
def find_package(root, local_paths, package, version):
"""Return the package target if found with at least this version"""
needed_version = pkg_resources.parse_version(version)
for local_path in local_paths:
package_path = os.path.join(local_path, package)
pubspec_yaml = os.path.join(root, package_path, 'pubspec.yaml')
if os.path.exists(pubspec_yaml):
with open(pubspec_yaml) as yaml_file:
pubspec = yaml.safe_load(yaml_file)
found_version = pkg_resources.parse_version(pubspec['version'])
if found_version >= needed_version:
return "//" + package_path
return None
def main():
parser = argparse.ArgumentParser()
parser.add_argument(
'--ignore-missing',
action='store_true',
help=('Return a success exit status, with all matched dart libraries, '
'even if one or more matches were not found'))
parser.add_argument(
'--root',
help='Path to the flutter engine src root',
required=True)
parser.add_argument(
'--target',
help='The name of the target that consolidates the derived deps',
required=True)
parser.add_argument(
'--local-path',
help=('A parent directory of pre-existing third_party dart libraries '
'(multiple --local-path arguments allowed)'),
action='append',
dest='local_paths',
required=True)
(args, versioned_dart_packages) = parser.parse_known_args()
assert os.path.exists(args.root)
for path in args.local_paths:
assert os.path.isdir(os.path.join(args.root, path))
if len(versioned_dart_packages) > 0:
assert len(versioned_dart_packages) % 2 == 0, (
'Each third_party_dep package must be accompanied by a version')
dart_package_paths = []
it = iter(versioned_dart_packages)
for item in it:
(package, version) = item, next(it)
path = find_package(args.root, args.local_paths, package, version)
if path is not None:
dart_package_paths.append(path)
else:
print(
'No package found for %s with version %s' % (package, version),
file=sys.stderr)
if not args.ignore_missing:
return 1
json.dump(dart_package_paths, sys.stdout)
return 0
if __name__ == '__main__':
sys.exit(main())

View File

@@ -0,0 +1,139 @@
# 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.
import("//build/fuchsia/sdk.gni")
import("//flutter/tools/fuchsia/dart/dart_library.gni")
import("//flutter/tools/fuchsia/fidl/fidl.gni")
_fuchsia_sdk_path = "//fuchsia/sdk/$host_os"
template("_fuchsia_dart_library") {
assert(defined(invoker.meta), "The meta file content must be specified.")
meta = invoker.meta
assert(meta.type == "dart_library")
_output_name = meta.name
_sources = []
_deps = []
if (defined(meta.dart_library_null_safe) && meta.dart_library_null_safe) {
_dart_language_version = "2.12"
} else {
_dart_language_version = "2.0"
}
foreach(source, meta.sources) {
_sources += [ string_replace("$source", "${meta.root}/lib/", "") ]
}
foreach(dep, meta.deps) {
_deps += [ "../dart:$dep" ]
}
foreach(dep, meta.fidl_deps) {
_deps += [ "//flutter/tools/fuchsia/fidl:$dep" ]
}
# Compute the third_party deps. The Fuchsia SDK doesn't know where to resolve
# a third_party dep, and Flutter has third_party Dart libraries in more than
# one location (some downloaded directly, others as part of the Dart SDK or
# bundled as a Dart SDK third_party dep). Find a matching library. If a match
# is required by a build dependency, and a match is not found, you may need to
# add an entry for it in `flutter/DEPS`.
known_pkg_paths = [
"third_party/pkg",
"third_party/dart/pkg",
"third_party/dart/third_party/pkg",
]
args = [
"--ignore-missing",
"--root",
rebase_path("//"),
"--target",
rebase_path(target_name, "//"),
]
foreach(path, known_pkg_paths) {
args += [
"--local-path",
path,
]
}
foreach(third_party_dep, meta.third_party_deps) {
name = third_party_dep.name
version = third_party_dep.version
args += [
name,
version,
]
}
third_party_deps_json =
exec_script("//flutter/tools/fuchsia/sdk/find_dart_libraries.py",
args,
"json")
_deps += third_party_deps_json
dart_library(target_name) {
package_root = "${_fuchsia_sdk_path}/${meta.root}"
package_name = _output_name
language_version = _dart_language_version
sources = _sources
deps = _deps
}
}
template("_fuchsia_fidl_library") {
assert(defined(invoker.meta), "The meta file content must be specified.")
meta = invoker.meta
assert(meta.type == "fidl_library")
fidl(target_name) {
sources = []
foreach(source, meta.sources) {
sources += [ "$fuchsia_sdk_path/$source" ]
}
public_deps = []
foreach(dep, meta.deps) {
public_deps += [ ":$dep" ]
}
}
}
template("sdk_targets") {
assert(defined(invoker.meta), "The meta.json file path must be specified.")
target_type = invoker.target_name
meta_json = read_file(invoker.meta, "json")
foreach(part, meta_json.parts) {
part_meta_json = {
}
part_meta = part.meta
part_meta_rebased = "$fuchsia_sdk_path/$part_meta"
part_meta_json = read_file(part_meta_rebased, "json")
subtarget_name = part_meta_json.name
if (part.type == target_type) {
if (target_type == "dart_library") {
_fuchsia_dart_library(subtarget_name) {
meta = part_meta_json
}
} else if (target_type == "fidl_library") {
_fuchsia_fidl_library(subtarget_name) {
meta = part_meta_json
}
}
}
}
group(target_name) {
}
}

View File

@@ -0,0 +1,58 @@
# 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.
import("//flutter/tools/fuchsia/toolchain/default_tools.gni")
declare_args() {
toolchain_variant = {
}
}
# Define a basic GN toolchain() instance that only has the "stamp" and "copy"
# tools. Use this for toolchains that will only have action() targets.
#
# Parameters:
# expected_label: Optional
# If provided, this template will assert that the full toolchain label
# matches this value. This is useful when the definition should match
# a global variable (e.g. go_toolchain or dart_toolchain).
# Type: GN label
#
# toolchain_args: Optional
# A scope of extra toolchain_args keys for this toolchain instance.
#
# NOTE: This also ensures this defines the global `toolchain_variant.base`
# variable, allowing BUILDCONFIG.gn to detect that this is not the default
# toolchain (see the definition of in_default_toolchain in that file for
# more details).
template("basic_toolchain") {
# The line below is required, otherwise 'gn gen' will complain with an error
# (i.e. 'You set the variable "invoker" here and it was unused before it went
# out of scope') if the template is called without any arguments.
not_needed([ "invoker" ])
toolchain(target_name) {
tool("stamp") {
command = stamp_command
description = stamp_description
}
tool("copy") {
command = copy_command
description = copy_description
}
toolchain_args = {
if (defined(invoker.toolchain_args)) {
forward_variables_from(invoker.toolchain_args, "*")
}
toolchain_variant = {
base = get_label_info(":$target_name", "label_no_toolchain")
if (defined(invoker.expected_label)) {
assert(
base == invoker.expected_label,
"Invalid toolchain label $base, expected ${invoker.expected_label}")
}
}
}
}
}

View File

@@ -0,0 +1,48 @@
#!/usr/bin/env python3.8
# 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.
"""Emulation of `rm -f out && cp -af` in out. This is necessary on Mac in order
to preserve nanoseconds of mtime. See https://fxbug.dev/56376#c5."""
import os
import shutil
import sys
def main():
if len(sys.argv) != 3:
print('usage: copy.py source dest', file=sys.stderr)
return 1
source = sys.argv[1]
dest = sys.argv[2]
if os.path.isdir(source):
print(
f'{source} is a directory, tool "copy" does not support directory copies'
)
return 1
if os.path.exists(dest):
if os.path.isdir(dest):
def _on_error(fn, path, dummy_excinfo):
# The operation failed, possibly because the file is set to
# read-only. If that's why, make it writable and try the op
# again.
if not os.access(path, os.W_OK):
os.chmod(path, stat.S_IWRITE)
fn(path)
shutil.rmtree(dest, onerror=_on_error)
else:
if not os.access(dest, os.W_OK):
# Attempt to make the file writable before deleting it.
os.chmod(dest, stat.S_IWRITE)
os.unlink(dest)
shutil.copy2(source, dest)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,28 @@
# 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.
# Each toolchain must define "stamp" and "copy" tools,
# but they are always the same in every toolchain.
stamp_command = "touch {{output}}"
stamp_description = "STAMP {{output}}"
# mtime on directories may not reflect the latest of a directory. For example in
# popular file systems, modifying a file in a directory does not affect mtime of
# the directory. Because of this, disable directory copy for incremental
# correctness. See https://fxbug.dev/73250.
copy_command = "if [ -d {{source}} ]; then echo 'Tool \"copy\" does not support directory copies'; exit 1; fi; "
# We use link instead of copy; the way "copy" tool is being used is
# compatible with links since Ninja is tracking changes to the source.
if (host_os == "mac") {
# `cp -af` does not correctly preserve mtime (the nanoseconds are truncated to
# microseconds) which causes spurious ninja rebuilds. As a result, shell to a
# helper to copy rather than calling cp -r. See https://fxbug.dev/56376#c5.
copy_command += "ln -f {{source}} {{output}} 2>/dev/null || (" +
rebase_path("//flutter/tools/fuchsia/toolchain/copy.py") +
" {{source}} {{output}})"
} else {
copy_command += "ln -f {{source}} {{output}} 2>/dev/null || (rm -f {{output}} && cp -af {{source}} {{output}})"
}
copy_description = "COPY {{source}} {{output}}"