| # Copyright 2016 The Fuchsia 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/config/fuchsia/sdk.gni") |
| import("//build/dart/dart.gni") |
| import("//build/dart/dart_package_config.gni") |
| import("//build/dart/toolchain.gni") |
| import("//build/json/validate_json.gni") |
| import("//build/sdk/sdk_atom.gni") |
| import("//build/toolchain/concurrent_jobs.gni") |
| |
| declare_args() { |
| # Enable all dart analysis |
| enable_dart_analysis = true |
| |
| # Enable all strict deps. |
| disable_dart_strict_deps = false |
| |
| # Detect dart API changes |
| # TODO(fxbug.dev/36723, fxbug.dev/6623) Remove this flag once issues are resolved |
| enable_api_diff = false |
| } |
| |
| # 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. |
| # |
| # disable_analysis (optional) |
| # Prevents analysis from being run on this target. |
| # |
| # sdk_category (optional) |
| # Publication level of the library in SDKs. |
| # See //build/sdk/sdk_atom.gni. |
| # |
| # api (optional) |
| # Path to the file representing the API of this library. |
| # This file is used to ensure modifications to the library's API are |
| # explicitly acknowledged. This file must exist for publication categories |
| # of "partner" or "public"; if it does not exist, it will be automatically |
| # generated by analyzing the given sources list. |
| # Defaults to "<Dart library name>.api". |
| # |
| # 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" ]) |
| |
| 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") |
| foreach(sdk_dir, sdk_dirs) { |
| full_dir = string_replace(full_dir, "$sdk_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") |
| source_file = "$target_gen_dir/$target_name.sources" |
| 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) ] |
| } |
| } |
| write_file(source_file, rebased_sources, "list lines") |
| |
| # Dependencies of the umbrella group for the targets in this file. |
| group_deps = [] |
| |
| _metadata_collection_results_path = |
| "$target_gen_dir/${target_name}_dart_build_info.out" |
| _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 included in the build 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. |
| source_verification_target_name = "${target_name}_source_verification" |
| output_file = "$target_gen_dir/$target_name.missing" |
| |
| action(source_verification_target_name) { |
| script = "//build/dart/verify_sources.py" |
| |
| outputs = [ output_file ] |
| |
| args = [ |
| "--package_root", |
| rebase_path(package_root), |
| "--source_dir", |
| source_dir, |
| "--stamp", |
| rebase_path(output_file), |
| ] |
| |
| foreach(source, invoker.sources) { |
| args += [ source ] |
| } |
| |
| forward_variables_from(invoker, [ "testonly" ]) |
| } |
| group_deps += [ ":$source_verification_target_name" ] |
| |
| ################################ |
| |
| # Don't run the analyzer if it is explicitly disabled or if we are using |
| # a custom-built Dart SDK in a cross-build. |
| with_analysis = |
| !defined(invoker.disable_analysis) || !invoker.disable_analysis |
| with_analysis = enable_dart_analysis && with_analysis |
| if (with_analysis) { |
| options_file = "$package_root/analysis_options.yaml" |
| if (defined(invoker.options_file)) { |
| options_file = invoker.options_file |
| } |
| invocation_file = "$target_gen_dir/$target_name.analyzer.sh" |
| invocation_target_name = "${target_name}_analysis_runner" |
| group_deps += [ ":$invocation_target_name" ] |
| |
| dart_analyzer_binary = "$dart_sdk/bin/dartanalyzer" |
| |
| # Creates a script which can be used to manually perform analysis. |
| # TODO(fxbug.dev/3065): remove this target. |
| action(invocation_target_name) { |
| script = "//build/dart/gen_analyzer_invocation.py" |
| |
| deps = dart_sdk_deps + [ ":$_dart_package_config_target_name" ] |
| |
| inputs = [ |
| dart_analyzer_binary, |
| _packages_path, |
| options_file, |
| source_file, |
| ] |
| |
| outputs = [ invocation_file ] |
| |
| args = [ |
| "--out", |
| rebase_path(invocation_file), |
| "--source-file", |
| rebase_path(source_file), |
| "--dot-packages", |
| rebase_path(_packages_path, root_build_dir), |
| "--dartanalyzer", |
| rebase_path(dart_analyzer_binary), |
| "--dart-sdk", |
| rebase_path(dart_sdk), |
| "--options", |
| rebase_path(options_file), |
| "--package-name", |
| package_name, |
| ] |
| |
| forward_variables_from(invoker, [ "testonly" ]) |
| } |
| |
| analysis_target_name = "${target_name}_analysis" |
| group_deps += [ ":$analysis_target_name" ] |
| |
| # Runs analysis on the sources. |
| action(analysis_target_name) { |
| forward_variables_from(concurrent_jobs.local, "*") |
| |
| hermetic_deps = false |
| script = "//build/dart/run_analysis.py" |
| |
| depfile = "$target_gen_dir/$target_name.analysis.d" |
| |
| output_file = "$target_gen_dir/$target_name.analyzed" |
| |
| inputs = [ |
| dart_analyzer_binary, |
| _packages_path, |
| options_file, |
| source_file, |
| ] + rebased_sources |
| |
| outputs = [ output_file ] |
| |
| args = [ |
| "--source-file", |
| rebase_path(source_file), |
| "--dot-packages", |
| rebase_path(_packages_path), |
| "--dartanalyzer", |
| rebase_path(dart_analyzer_binary), |
| "--dart-sdk", |
| rebase_path(dart_sdk), |
| "--options", |
| rebase_path(options_file), |
| "--stamp", |
| rebase_path(output_file), |
| "--depname", |
| rebase_path(output_file, root_build_dir), |
| "--depfile", |
| rebase_path(depfile), |
| ] |
| |
| deps = dart_sdk_deps + [ ":$_dart_package_config_target_name" ] |
| |
| forward_variables_from(invoker, [ "testonly" ]) |
| } |
| } else { |
| not_needed(invoker, [ "options_file" ]) |
| } |
| |
| ################################ |
| # Dart strict deps |
| # |
| # Ensures that this target specifies all of the Dart packages that it |
| # imports as direct dependencies. |
| |
| group("${invoker.target_name}_dart_build_info_self_marker") { |
| metadata = { |
| dart_build_info = [ |
| { |
| __is_current_target = true |
| __package_name = package_name |
| __deps = _dart_deps + _non_dart_deps |
| __public_deps = _public_deps |
| __rebased_sources = rebased_sources |
| }, |
| ] |
| } |
| forward_variables_from(invoker, [ "testonly" ]) |
| } |
| |
| generated_file("${invoker.target_name}_dart_build_info") { |
| data_keys = [ "dart_build_info" ] |
| walk_keys = [ "dart_build_info_barrier" ] |
| outputs = [ _metadata_collection_results_path ] |
| output_conversion = "json" |
| deps = |
| _dart_deps + [ ":${invoker.target_name}_dart_build_info_self_marker" ] |
| forward_variables_from(invoker, [ "testonly" ]) |
| } |
| |
| _strict_deps_tool_label = |
| "//tools/dart-strict-deps:strict_deps($host_toolchain)" |
| _strict_deps_tool_path = |
| get_label_info(_strict_deps_tool_label, "root_out_dir") + |
| "/dart-tools/strict_deps" |
| _strict_deps_stamp = |
| "${invoker.target_gen_dir}/${invoker.target_name}_strict_deps.report" |
| |
| action("${invoker.target_name}_strict_deps") { |
| hermetic_deps = false |
| deps = [ |
| ":$_dart_package_config_target_name", |
| ":${invoker.target_name}_dart_build_info", |
| _strict_deps_tool_label, |
| ] |
| outputs = [ _strict_deps_stamp ] |
| script = _strict_deps_tool_path |
| args = [ |
| "--metadata-file", |
| rebase_path(_metadata_collection_results_path, root_build_dir), |
| "--output-file", |
| rebase_path(_strict_deps_stamp, root_build_dir), |
| "--packages-file", |
| rebase_path(_packages_path, root_build_dir), |
| ] |
| forward_variables_from(invoker, [ "testonly" ]) |
| } |
| |
| # The strict deps tool is excluded from the strict deps check to |
| # prevent a circular dependency. |
| _strict_deps_package_excludes = [ |
| "strict_deps_dart_library", |
| "dart_strict_deps_lib", |
| "dart_strict_deps_proto", |
| "protoc_gen_dart_dart_library", |
| ] |
| _package_excludes_contains_target = |
| _strict_deps_package_excludes + [ target_name ] - [ target_name ] != |
| _strict_deps_package_excludes |
| |
| _full_target_label = get_label_info(":$target_name", "label_no_toolchain") |
| |
| _is_third_party_lib = |
| string_replace(_full_target_label, "//third_party/dart-pkg/pub", "") != |
| _full_target_label |
| |
| 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 |
| |
| if (!disable_dart_strict_deps && !_package_excludes_contains_target && |
| !_is_third_party_lib) { |
| deps += [ ":${invoker.target_name}_strict_deps" ] |
| } else { |
| not_needed([ |
| "_package_excludes_contains_target", |
| "_is_third_party_lib", |
| ]) |
| } |
| |
| public_deps = group_deps |
| |
| metadata = _metadata |
| forward_variables_from(invoker, [ "testonly" ]) |
| } |
| |
| ################################################ |
| # SDK support |
| # |
| |
| with_api_diff = enable_api_diff && (defined(invoker.sdk_category) && |
| invoker.sdk_category != "excluded") |
| |
| if (with_api_diff) { |
| detect_target_name = "${target_name}_detect_action" |
| verify_target_name = "${target_name}_verify" |
| detect_target_file = "$target_gen_dir/$package_name.api" |
| api_file = rebase_path(".") + "/$package_name.api" |
| |
| action(detect_target_name) { |
| runner_label = "//build/dart/sdk/detect_api_changes($dart_toolchain)" |
| runner_out_dir = get_label_info(runner_label, "root_out_dir") |
| script = "$runner_out_dir/dart-tools/detect_api_changes" |
| output_file = detect_target_file |
| |
| inputs = [ |
| _packages_path, |
| source_file, |
| ] + rebased_sources |
| |
| outputs = [ output_file ] |
| |
| args = [ |
| "--api-name", |
| get_label_info(":$target_name", "label_no_toolchain"), |
| "--source-file", |
| rebase_path(source_file), |
| "--dot-packages", |
| rebase_path(_packages_path), |
| "--output-file", |
| rebase_path("$detect_target_file"), |
| "--golden-api", |
| api_file, |
| |
| # Uncomment to force updating the .api files |
| #"--overwrite", |
| ] |
| |
| deps = dart_sdk_deps + [ runner_label ] |
| forward_variables_from(invoker, [ "testonly" ]) |
| } |
| |
| # Verify that the library API file complies with the specified schema. |
| validate_json(verify_target_name) { |
| forward_variables_from(invoker, [ "testonly" ]) |
| data = rebase_path("$detect_target_file") |
| schema = rebase_path("//build/dart/sdk/detect_api_changes/schema.json") |
| deps = dart_sdk_deps + [ ":$detect_target_name" ] |
| public_deps = [ ":$detect_target_name" ] |
| } |
| } |
| |
| if (defined(invoker.sdk_category) && invoker.sdk_category != "excluded") { |
| assert( |
| defined(invoker.package_name), |
| "Dart libraries published in SDKs must have an explicit package name") |
| |
| assert( |
| !defined(invoker.extra_sources), |
| "Extra sources can not be included in SDKs: put them in source_dir") |
| |
| # Dependencies that should normally be included in any SDK containing this |
| # target. |
| sdk_deps = [] |
| |
| # Path to SDK metadata files for first-party dependencies. |
| sdk_metas = [] |
| |
| # Path to Dart manifest files for third-party dependencies. |
| third_party_pubspecs = [] |
| |
| local_deps = filter_exclude(_dart_deps, [ "//third_party/*" ]) |
| third_party_deps = filter_include(_dart_deps, [ "//third_party/*" ]) |
| foreach(dep, local_deps) { |
| sdk_dep = "${dep}_sdk" |
| sdk_deps += [ sdk_dep ] |
| |
| gen_dir = get_label_info(sdk_dep, "target_gen_dir") |
| name = get_label_info(sdk_dep, "name") |
| sdk_metas += [ rebase_path("$gen_dir/$name.meta.json") ] |
| } |
| foreach(dep, third_party_deps) { |
| path = get_label_info(dep, "dir") |
| third_party_pubspecs += [ rebase_path("$path/pubspec.yaml") ] |
| } |
| |
| file_base = "dart/${invoker.package_name}" |
| |
| sdk_sources = [] |
| sdk_source_mappings = [] |
| foreach(source, rebased_sources) { |
| relative_source = rebase_path(source, source_dir) |
| dest = "$file_base/lib/$relative_source" |
| sdk_sources += [ dest ] |
| sdk_source_mappings += [ |
| { |
| source = source |
| dest = dest |
| }, |
| ] |
| } |
| |
| metadata_target_name = "${target_name}_sdk_metadata" |
| metadata_file = "$target_gen_dir/$target_name.sdk_meta.json" |
| action(metadata_target_name) { |
| script = "//build/dart/sdk/gen_meta_file.py" |
| |
| inputs = sdk_metas + third_party_pubspecs |
| |
| outputs = [ metadata_file ] |
| |
| args = [ |
| "--out", |
| rebase_path(metadata_file), |
| "--name", |
| package_name, |
| "--root", |
| file_base, |
| ] |
| args += [ "--specs" ] + sdk_metas |
| args += [ "--sources" ] + sdk_sources |
| args += [ "--third-party-specs" ] + third_party_pubspecs |
| |
| if (defined(invoker.null_safe) && invoker.null_safe) { |
| args += [ "--dart-library-null-safe" ] |
| } |
| |
| deps = sdk_deps |
| |
| forward_variables_from(invoker, [ "testonly" ]) |
| } |
| |
| sdk_atom("${target_name}_sdk") { |
| id = "sdk://dart/${invoker.package_name}" |
| |
| category = invoker.sdk_category |
| |
| meta = { |
| source = metadata_file |
| dest = "$file_base/meta.json" |
| schema = "dart_library" |
| } |
| |
| deps = sdk_deps |
| |
| non_sdk_deps = [ ":$metadata_target_name" ] |
| if (with_api_diff) { |
| non_sdk_deps += [ ":$verify_target_name" ] |
| } |
| |
| if (defined(invoker.non_dart_deps)) { |
| non_sdk_deps += invoker.non_dart_deps |
| } |
| |
| files = sdk_source_mappings |
| } |
| } |
| } |
| } 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)" ] |
| } |
| } |
| } |