| # Copyright 2022 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/bazel/bazel_inputs.gni") |
| import("//build/bazel/config/logging.gni") |
| import("//build/bazel/remote_services.gni") |
| import("//build/licenses/generated_licenses_spdx.gni") |
| import("//build/rust/config.gni") |
| |
| declare_args() { |
| # Automatically refreshes compile_commands.json after bazel_actions are built. |
| # |
| # NOTE: Enabling will add a several seconds of overhead to the build. |
| bazel_auto_refresh_compdb = false |
| } |
| |
| # Wrap a Bazel command with a GN action. |
| # |
| # May only be called on the default_toolchain so as to prevent generating Bazel |
| # workspace multiple times. Host targets can be built by specifying |
| # `host = true`. |
| # |
| # The caller should pass a list of Bazel target patterns for the |
| # `bazel build` command, as well as a list Bazel output files relative |
| # to the workspace's root that will be copied into the |
| # GN target's target_out_dir by default. |
| # |
| # All inputs seen by the Bazel command must be defined in the |
| # @legacy_ninja_build_outputs Bazel repository, which is populated by |
| # bazel_input_xxx() targets that must appear as dependencies of the |
| # //build/bazel:legacy_ninja_build_outputs target. |
| # |
| # The bazel-generated files will be copied (possibly hard-linked) into the |
| # `ninja_base_dir` (which is `target_out_dir` by default) matching the GN |
| # action for this template call. |
| # |
| # This also takes a list of Bazel target patterns, since Bazel does not |
| # support building specific files, only targets. For now it is up to the |
| # caller to know exactly which files are generated by Bazel for a given |
| # set of target patterns. |
| # |
| # Args: |
| # command: (required) |
| # The Bazel command, e.g. `build`, `run`, `test`... |
| # See: `bazel help`. |
| # Type: string. |
| # |
| # bazel_inputs: (optional) |
| # DEPRECATED: Just use `deps` for these. |
| # |
| # List of labels to bazel_input_xxx() targets that define |
| # the set of Ninja-generated inputs that the Bazel build command will |
| # use. These must be in the dependency tree of |
| # `//build/bazel:legacy_ninja_build_outputs`. Note that this is only used to |
| # ensure that said inputs are properly generated by Ninja before this |
| # action's command is run. The command will be able to see any input |
| # files exported by the @legacy_ninja_build_outputs Bazel repository, |
| # as there is no way to restrict them for now. |
| # Type: list of GN labels. |
| # |
| # bazel_targets: |
| # A list of Bazel targets for the `bazel build` command. |
| # This list cannot be empty since there is no concept of 'default' |
| # targets in Bazel. Note target sets (i.e. `...`) are not supported. |
| # |
| # Relative target names (e.g. ":foo" or "foo:bar") are supported and |
| # will be resolved relative to the current directory. |
| # |
| # Type: list of Bazel targets. |
| # |
| # ninja_base_dir: (optional) |
| # A GN path for the base directory used for `ninja` paths in the |
| # scope items of `copy_outputs`, `directory_outputs`, etc.. |
| # Default value is `target_out_dir`. |
| # |
| # update_rust_project: (optional) |
| # A boolean (default=false) to update rust_project.json with the Rust |
| # targets contained within this Bazel action. |
| # |
| # copy_outputs: (optional) |
| # A list of scopes, where each item describes a Bazel output and a |
| # corresponding Ninja output location (where the Bazel build artifact |
| # will be copied). |
| # |
| # Each scope uses the following format: |
| # |
| # { |
| # bazel = "<bazel_path>" |
| # ninja = "<ninja_path>" |
| # } |
| # |
| # See technical note below for details about <bazel_path> and <ninja_path> |
| # |
| # Type: list of scopes (cannot be empty) |
| # |
| # directory_outputs: (optional) |
| # A list of scopes, where each item describes a Bazel output directory |
| # (a.k.a. TreeArtifact) and the corresponding Ninja output location where |
| # it will be copied. |
| # |
| # Each scope uses the following schema: |
| # |
| # bazel_target (optional) |
| # A Bazel target label generating the directory. Must be reachable from |
| # one of the bazel_targets labels. Defaults to bazel_targets[0]. |
| # |
| # bazel_dir (required) |
| # A path string to the location of the directory, relative to the |
| # Bazel workspace. This can use the same substitution expressions |
| # as `copy_outputs` items. |
| # |
| # ninja_dir (required) |
| # A path string, relative to `ninja_base_dir`, where the |
| # directory will be recursively copied to. Previous instances are |
| # replaced, instead of being overwritten, to avoid keeping stale |
| # files from previous builds. |
| # |
| # tracked_files (required) |
| # A non-empty list of file paths, relative to ninja_dir, corresponding |
| # to files (not directories), whose timestamps will be used by Ninja |
| # to determine when to re-run the current action. |
| # |
| # These will also be listed as outputs for this GN action, as using |
| # directories as outputs can lead to incremental build issues in GN/Ninja, |
| # because timestamps on directories may not correctly represent freshness |
| # of its contents. |
| # |
| # IMPORTANT: For incremental build correctness, these tracked files |
| # timestamps must always reflect the freshness of the whole directory |
| # content. |
| # |
| # copy_debug_symbols: (optional) |
| # A boolean flag, set it to true to copy all debug symbols from |
| # the package's ELF binaries to the top-level ${root_build_dir}/.build-id/ |
| # directory. |
| # |
| # package_outputs: (optional) |
| # A list of scopes describing where to place various Fuchsia package |
| # related output files. Scope schema is: |
| # |
| # package_label: (required) |
| # A bazel label to a fuchsia_package() or fuchsia_test_package() |
| # target. This target must be reachable from one of the labels |
| # listed in the top-level bazel_targets argument. |
| # |
| # archive: (required) |
| # output path for the package's archive, relative to `ninja_base_dir`. |
| # |
| # copy_debug_symbols: (optional) |
| # A boolean flag, set it to true to copy all debug symbols from |
| # the package's ELF binaries to the top-level ${root_build_dir}/.build-id/ |
| # directory. |
| # |
| # final_symlink_outputs: (optional) |
| # A list of scopes describing symlink locations, relative to the Ninja build |
| # directory, pointing to Bazel artifacts directly. This is similar |
| # to copy_outputs, except that the `ninja` path points to a symlink location |
| # in the Ninja build directory. |
| # |
| # IMPORTANT: This should only be used for "final" targets of the Ninja build |
| # graph, i.e. ones that are never used as input for other Ninja commands, since |
| # the timestamp in the Bazel output base, which the symlink point to, are never |
| # guaranteed to be consistent. |
| # |
| # This is useful to use the symlinks after the build complete. |
| # |
| # NOTE: This feature is a special case and is not available to wrappers |
| # like `bazel_build_action()` intentionally, in order to limit its usage. |
| # |
| # include_host_tools_licenses: (optional) |
| # Set this to true to include the licenses of host tool dependencies in |
| # @gn_targets//:all_licenses.spdx.json. |
| # Type: boolean |
| # Default: false |
| # |
| # ignore_license_collection_errors: (optional) |
| # Set this to true to ignore errors when collecting license requirements |
| # from dependencies. |
| # Type: boolean |
| # Default: false |
| # |
| # bazel_config: |
| # String matching one of the following: |
| # * "host": Build host artifacts. |
| # * "fuchsia_platform": Build Fuchsia platform artifacts. |
| # * "fuchsia_sdk": Build Fuchsia platform artifacts using the |
| # in-tree Bazel SDK. Targets are not available to the GN graph until the |
| # entire SDK has been built. |
| # |
| # bazel_platform: (optional) |
| # Overwrite the `--platforms` flag when building with Bazel. |
| # Must match one of the available platforms defined in |
| # //build/bazel/platforms/BUILD.bazel. |
| # When not set, the configured platform from the .bazelrc will be used. |
| # |
| # NOTE: There is no guarantee that your chosen platform will work with the |
| # `--config` applied, so use this parameter with caution. |
| # |
| # Type: string |
| # |
| # deps: |
| # metadata: |
| # check_for_output_dir_leaks: |
| # testonly: |
| # visibility: |
| # Usual GN meaning. |
| # |
| # |
| # TECHNICAL NOTE ON BAZEL OUTPUTS: |
| # |
| # Bazel places its build artifacts under directories that are specific to |
| # the Bazel build configuration. In practice, these will be different based |
| # on the current GN toolchain instance where the bazel_action() target |
| # is defined. |
| # |
| # Because the exact Bazel config directories are hard to predict, Bazel |
| # creates (or updates) a symlink named `bazel-bin` in the main workspace |
| # directory. This symlink points to the correct config-specific directory, |
| # and build artifacts are then reachable as |
| # "$BAZEL_WORKSPACE/bazel-bin/<bazel_target_package>/<output_files>" |
| # |
| # However, every time a bazel_action() action is run, the value of the |
| # bazel-bin symlink target *may* change, so these bazel output paths cannot |
| # be considered stable or valid once the action has completed. |
| # |
| # Hence Bazel build outputs must be copied to stable locations in the |
| # Ninja build directory, by the script invoked by bazel_action(). |
| # |
| # The `copy_outputs` argument is used to list all Bazel outputs and their |
| # corresponding Ninja output path. It is a list of scopes whose format |
| # is: |
| # |
| # { |
| # bazel = "<bazel_path>" |
| # ninja = "<ninja_path>" |
| # } |
| # |
| # Where <bazel_path> is a Bazel output path, relative to the Bazel workspace |
| # that looks like "bazel-bin/<bazel_target_package>/<output_file>", and |
| # where <ninja_path> is an output path relative to the `ninja_base_dir` directory. |
| # |
| # Moreover, the <bazel_path> value supports these special substitution |
| # expressions: |
| # |
| # {{BAZEL_TARGET_NAME}} |
| # Expands to the target name of the first `bazel_targets` label |
| # |
| # {{BAZEL_TARGET_PACKAGE}} |
| # Expands to the package name of the first `bazel_targets` label |
| # without a // prefix! |
| # |
| # {{BAZEL_TARGET_OUT_DIR}} |
| # Expands to "bazel-bin/{{BAZEL_TARGET_PACKAGE}}" |
| # |
| # {{BAZEL_TARGET_OUT_PATH}} |
| # Expands to {{BAZEL_TARGET_OUT_DIR}}/{{BAZEL_TARGET_NAME}}. |
| # |
| template("bazel_action") { |
| # Bazel actions can only be run in the default toolchain, so no-op the |
| # template since trying to enforce this in all the BUILD.gn files themselves |
| # is currently infeasible. |
| if (current_toolchain == default_toolchain) { |
| assert(defined(invoker.command), "command must be defined!") |
| assert(defined(invoker.bazel_targets), "bazel_targets must be defined!") |
| assert(invoker.bazel_targets != [], "bazel_targets cannot be empty!") |
| assert(defined(invoker.bazel_config), "bazel_config must be defined!") |
| |
| # Calculate the correct Bazel platform to use. |
| if (invoker.bazel_config == "host") { |
| _bazel_platform_config = "host_config_args" |
| _bazel_platform_label = "//build/bazel/platforms:host" |
| _no_sdk = true |
| _build_for_host = true |
| } else if (invoker.bazel_config == "fuchsia_platform") { |
| _bazel_platform_config = "fuchsia_config_args" |
| _bazel_platform_label = |
| "//build/bazel/platforms:fuchsia_platform_${current_cpu}" |
| _no_sdk = true |
| _build_for_host = false |
| } else if (invoker.bazel_config == "fuchsia_sdk") { |
| _bazel_platform_config = "fuchsia_config_args" |
| _bazel_platform_label = |
| "//build/bazel/platforms:fuchsia_sdk_${current_cpu}" |
| _no_sdk = false |
| _build_for_host = false |
| } else { |
| assert( |
| false, |
| "Unrecognized `bazel_config` value: '${invoker.bazel_config}'. Use: 'host' for host artifacts, 'fuchsia_platform' for platform artifacts, or 'fuchsia_sdk' when using the Bazel SDK.") |
| } |
| |
| if (defined(invoker.bazel_platform)) { |
| _bazel_platform_label = |
| "//build/bazel/platforms:${invoker.bazel_platform}" |
| } |
| |
| _update_rust_project = |
| defined(invoker.update_rust_project) && invoker.update_rust_project |
| |
| _copy_outputs = [] |
| if (defined(invoker.copy_outputs)) { |
| _copy_outputs = invoker.copy_outputs |
| } |
| |
| _directory_outputs = [] |
| if (defined(invoker.directory_outputs)) { |
| _directory_outputs = invoker.directory_outputs |
| } |
| |
| _package_outputs = [] |
| if (defined(invoker.package_outputs)) { |
| _package_outputs = invoker.package_outputs |
| } |
| |
| _final_symlink_outputs = [] |
| if (defined(invoker.final_symlink_outputs)) { |
| _final_symlink_outputs = invoker.final_symlink_outputs |
| } |
| |
| assert( |
| _copy_outputs != [] || _directory_outputs != [] || |
| _package_outputs != [] || _final_symlink_outputs != [], |
| "At least one of `copy_outputs`, `directory_outputs` or `package_outputs` must be a non-empty list!") |
| |
| _has_package_outputs = false |
| |
| _ninja_base_dir = target_out_dir |
| if (defined(invoker.ninja_base_dir)) { |
| _ninja_base_dir = invoker.ninja_base_dir |
| } |
| |
| _bazel_targets = invoker.bazel_targets |
| |
| # Collect all outputs into a single list of scopes with different schemas. |
| # All of them have a "type" string key, and a "bazel_target" label string. |
| |
| _all_outputs = [] |
| |
| foreach(entry, _copy_outputs) { |
| assert("$entry" != entry, |
| "`copy_outputs` items must be scopes, string found: \"$entry\"") |
| assert(defined(entry.bazel), |
| "`copy_outputs` scope requires bazel key: $entry") |
| assert(defined(entry.ninja), |
| "`copy_outputs` scope requires ninja key: $entry") |
| |
| _bazel_target = _bazel_targets[0] |
| if (defined(entry.bazel_target)) { |
| _bazel_target = entry.bazel_target |
| } |
| |
| foreach(path, [ entry.bazel ]) { |
| assert(rebase_path(path, "//") != path, |
| "bazel output path must be relative: $path") |
| assert(string_replace("XX$path", "XX-", "") == "XX$path", |
| "bazel output path cannot begin with dash: $path") |
| if (string_replace(path, "{{BAZEL_TARGET_", "") != path) { |
| _bazel_target_name = get_label_info(_bazel_target, "name") |
| _bazel_target_package = |
| rebase_path(get_label_info(_bazel_target, "dir"), "//") |
| _bazel_target_out_dir = "bazel-bin/" + _bazel_target_package |
| |
| path = |
| string_replace(path, "{{BAZEL_TARGET_NAME}}", _bazel_target_name) |
| path = string_replace(path, |
| "{{BAZEL_TARGET_PACKAGE}}", |
| _bazel_target_package) |
| path = string_replace(path, |
| "{{BAZEL_TARGET_OUT_DIR}}", |
| _bazel_target_out_dir) |
| path = |
| string_replace(path, |
| "{{BAZEL_TARGET_OUT_PATH}}", |
| "${_bazel_target_out_dir}/${_bazel_target_name}") |
| } |
| |
| # In case of typo with a substitution (e.g. writing |
| # {{BAZEL_TARGET_O_DIR}}) GN will complain with an error but will not |
| # display the problematic so use an assert to provide a user-friendly |
| # message. |
| assert(string_replace(path, "{{", "") == path, |
| "Unsupported substitution in Bazel output path: $path") |
| |
| _bazel_file = path |
| } |
| |
| _all_outputs += [ |
| { |
| type = "file" |
| bazel_target = get_label_info(_bazel_target, "label_no_toolchain") |
| bazel_file = _bazel_file |
| ninja_file = "${_ninja_base_dir}/${entry.ninja}" |
| }, |
| ] |
| } |
| |
| foreach(entry, _directory_outputs) { |
| assert( |
| "$entry" != entry, |
| "`directory_outputs` items must be scopes, string found: \"$entry\"") |
| assert(defined(entry.bazel_dir), |
| "`directory_outputs` scope requires bazel_dir key: $entry") |
| assert(defined(entry.ninja_dir), |
| "`directory_outputs` scope requires ninja_dir key: $entry") |
| assert(defined(entry.tracked_files), |
| "`directory_outputs` scope requires tracked_files key: $entry") |
| |
| _bazel_target = _bazel_targets[0] |
| if (defined(entry.bazel_target)) { |
| _bazel_target = entry.bazel_target |
| } |
| |
| foreach(path, [ entry.bazel_dir ]) { |
| assert(rebase_path(path, "//") != path, |
| "bazel output path must be relative: $path") |
| assert(string_replace("XX$path", "XX-", "") == "XX$path", |
| "bazel output path cannot begin with dash: $path") |
| if (string_replace(path, "{{BAZEL_TARGET_", "") != path) { |
| _bazel_target_name = get_label_info(_bazel_target, "name") |
| _bazel_target_package = |
| rebase_path(get_label_info(_bazel_target, "dir"), "//") |
| _bazel_target_out_dir = "bazel-bin/" + _bazel_target_package |
| |
| path = |
| string_replace(path, "{{BAZEL_TARGET_NAME}}", _bazel_target_name) |
| path = string_replace(path, |
| "{{BAZEL_TARGET_PACKAGE}}", |
| _bazel_target_package) |
| path = string_replace(path, |
| "{{BAZEL_TARGET_OUT_DIR}}", |
| _bazel_target_out_dir) |
| path = |
| string_replace(path, |
| "{{BAZEL_TARGET_OUT_PATH}}", |
| "${_bazel_target_out_dir}/${_bazel_target_name}") |
| } |
| |
| # In case of typo with a substitution (e.g. writing |
| # {{BAZEL_TARGET_O_DIR}}) GN will complain with an error but will not |
| # display the problematic so use an assert to provide a user-friendly |
| # message. |
| assert(string_replace(path, "{{", "") == path, |
| "Unsupported substitution in Bazel output path: $path") |
| |
| _bazel_dir = path |
| } |
| |
| _all_outputs += [ |
| { |
| type = "directory" |
| bazel_target = get_label_info(_bazel_target, "label_no_toolchain") |
| bazel_dir = _bazel_dir |
| ninja_dir = "${_ninja_base_dir}/${entry.ninja_dir}" |
| copy_debug_symbols = |
| defined(entry.copy_debug_symbols) && entry.copy_debug_symbols |
| assert(entry.tracked_files != [], |
| "Directory outputs require tracked files.") |
| tracked_files = entry.tracked_files |
| }, |
| ] |
| } |
| |
| foreach(entry, _package_outputs) { |
| assert("$entry" != entry, |
| "`package_outputs` items must be scopes, string found: \"$entry\"") |
| assert(defined(entry.package_label), |
| "`package_outputs` scope requires package_label key: $entry") |
| _archive = "" |
| if (defined(entry.archive)) { |
| _archive = "${_ninja_base_dir}/${entry.archive}" |
| } |
| _all_outputs += [ |
| { |
| type = "package" |
| bazel_target = |
| get_label_info(entry.package_label, "label_no_toolchain") |
| ninja_archive = _archive |
| copy_debug_symbols = |
| defined(entry.copy_debug_symbols) && entry.copy_debug_symbols |
| }, |
| ] |
| |
| _has_package_outputs = true |
| } |
| |
| foreach(entry, _final_symlink_outputs) { |
| assert( |
| "$entry" != entry, |
| "`final_symlink_outputs` items must be scopes, string found: \"$entry\"") |
| assert(defined(entry.bazel), |
| "`final_symlink_outputs` scope requires bazel key: $entry") |
| assert(defined(entry.ninja), |
| "`final_symlink_outputs` scope requires ninja key: $entry") |
| |
| _bazel_target = _bazel_targets[0] |
| if (defined(entry.bazel_target)) { |
| _bazel_target = entry.bazel_target |
| } |
| |
| foreach(path, [ entry.bazel ]) { |
| assert(rebase_path(path, "//") != path, |
| "bazel output path must be relative: $path") |
| assert(string_replace("XX$path", "XX-", "") == "XX$path", |
| "bazel output path cannot begin with dash: $path") |
| if (string_replace(path, "{{BAZEL_TARGET_", "") != path) { |
| _bazel_target_name = get_label_info(_bazel_target, "name") |
| _bazel_target_package = |
| rebase_path(get_label_info(_bazel_target, "dir"), "//") |
| _bazel_target_out_dir = "bazel-bin/" + _bazel_target_package |
| |
| path = |
| string_replace(path, "{{BAZEL_TARGET_NAME}}", _bazel_target_name) |
| path = string_replace(path, |
| "{{BAZEL_TARGET_PACKAGE}}", |
| _bazel_target_package) |
| path = string_replace(path, |
| "{{BAZEL_TARGET_OUT_DIR}}", |
| _bazel_target_out_dir) |
| path = |
| string_replace(path, |
| "{{BAZEL_TARGET_OUT_PATH}}", |
| "${_bazel_target_out_dir}/${_bazel_target_name}") |
| } |
| |
| # In case of typo with a substitution (e.g. writing |
| # {{BAZEL_TARGET_O_DIR}}) GN will complain with an error but will not |
| # display the problematic so use an assert to provide a user-friendly |
| # message. |
| assert(string_replace(path, "{{", "") == path, |
| "Unsupported substitution in Bazel output path: $path") |
| |
| _bazel_file = path |
| } |
| |
| _all_outputs += [ |
| { |
| type = "final_symlink" |
| bazel_target = get_label_info(_bazel_target, "label_no_toolchain") |
| bazel_file = _bazel_file |
| ninja_file = "${_ninja_base_dir}/${entry.ninja}" |
| }, |
| ] |
| } |
| |
| # Write the log of build events to a target-specific file. |
| # See https://bazel.build/remote/bep for details. |
| # For now, produce in JSON output since we lack a tool to convert from |
| # binary to other formats in the tree. |
| _bazel_build_events_log_json = |
| "$target_out_dir/$target_name.bazel_events.log.json" |
| |
| _rebased_bazel_build_events_log_json = |
| rebase_path(_bazel_build_events_log_json, root_build_dir) |
| |
| _bazel_build_files = [] |
| _bazel_targets = [] |
| foreach(label, invoker.bazel_targets) { |
| dir = get_label_info(label, "dir") |
| name = get_label_info(label, "name") |
| assert(get_path_info(dir, "file") != "...", |
| "`...` is not supported in bazel_targets") |
| _bazel_build_files += [ "${dir}/BUILD.bazel" ] |
| _bazel_targets += [ "${dir}:${name}" ] |
| } |
| |
| # A group to depend on all bazel_input_xxx() dependencies. |
| _bazel_inputs_group_target = "$target_name.bazel_inputs" |
| group(_bazel_inputs_group_target) { |
| forward_variables_from(invoker, |
| [ |
| "deps", |
| "testonly", |
| ]) |
| if (defined(invoker.bazel_inputs)) { |
| if (!defined(deps)) { |
| deps = [] |
| } |
| deps += invoker.bazel_inputs |
| } |
| visibility = [ ":*" ] |
| } |
| |
| # Generate a manifest file that references all transitive bazel_input_file() |
| # and bazel_input_directory() dependencies from 'deps' or 'bazel_inputs'. |
| # |
| # These are passed to bazel_gn_target_action.py to populate the @gn_targets |
| # external repository with symlinks and filegroups(). |
| # |
| _gn_targets_repository_manifest = |
| "$target_out_dir/${target_name}.gn_targets_manifest.json" |
| _gn_targets_repository_manifest_target = "${target_name}.gn_targets" |
| generate_gn_targets_repository_manifest( |
| _gn_targets_repository_manifest_target) { |
| forward_variables_from(invoker, [ "testonly" ]) |
| output = _gn_targets_repository_manifest |
| deps = [ ":${_bazel_inputs_group_target}" ] |
| } |
| |
| # Generate an SPDX file that contains license information for all |
| # dependencies of this bazel_action() GN target, this will be exposed |
| # through the special @gn_targets//all_licenses_spdx_json, which should |
| # be used in product-specific build rules instead of |
| # @legacy_ninja_build_outputs//:all_bazel_inputs_licenses_spdx_json |
| |
| _all_licenses_spdx_target = "${target_name}.all_licenses_spdx" |
| _all_licenses_spdx_file = |
| "$target_out_dir/${target_name}.all_licenses.spdx.json" |
| |
| generated_licenses_spdx(_all_licenses_spdx_target) { |
| forward_variables_from(invoker, [ "testonly" ]) |
| target = ":${_bazel_inputs_group_target}" |
| output = _all_licenses_spdx_file |
| spdx_root_package_name = "Fuchsia" |
| debug_hints = true |
| |
| include_host_tools = defined(invoker.include_host_tools_licenses) && |
| invoker.include_host_tools_licenses |
| |
| ignore_collection_errors = |
| defined(invoker.ignore_license_collection_errors) && |
| invoker.ignore_license_collection_errors |
| |
| visibility = [ ":*" ] |
| } |
| |
| # Location of the @gn_targets repository for this Bazel invocation. |
| # This points to a directory that is generated by //build/regenerator |
| # before the build, to allow for Bazel queries to be performed as soon as |
| # possible. |
| _gn_targets_repository_path = "${target_out_dir}/${target_name}.gn_targets" |
| |
| # A file that will receive the exact Bazel command invoked by the |
| # bazel_gn_targets_action.py script. |
| _bazel_command_file = "${target_out_dir}/${target_name}.bazel_command.sh" |
| _rebased_bazel_command_file = |
| rebase_path(_bazel_command_file, root_build_dir) |
| |
| # A file that will receive the explain output from the |
| # bazel_gn_target_action.py script. |
| # |
| # The output is from dependency checker in Bazel build's execution phase to |
| # explain, for each build step, either why it is being executed, or that it |
| # is up-to-date. |
| # |
| # NOTE: This file will only include explain output from the `build` command, |
| # not other commands like `query`. |
| _bazel_explain_file = "${target_out_dir}/${target_name}.bazel_explain.txt" |
| _rebased_bazel_explain_file = |
| rebase_path(_bazel_explain_file, root_build_dir) |
| |
| _timings_file = "${target_out_dir}/${target_name}.bazel_action_timings.json" |
| _rebased_timings_file = rebase_path(_timings_file, root_build_dir) |
| |
| _debug_symbols_manifest = |
| "${target_out_dir}/${target_name}.debug_symbols.json" |
| _rebased_debug_symbols_manifest = |
| rebase_path(_debug_symbols_manifest, root_build_dir) |
| |
| if (_update_rust_project) { |
| _rust_project_json = "${target_out_dir}/${target_name}.rust-project.json" |
| _rebased_rust_project_json = |
| rebase_path(_rust_project_json, root_build_dir) |
| } |
| |
| action(target_name) { |
| forward_variables_from(invoker, |
| [ |
| "deps", |
| "check_for_output_dir_leaks", |
| "testonly", |
| "visibility", |
| ]) |
| if (!defined(deps)) { |
| deps = [] |
| } |
| |
| mnemonic = "BAZEL" |
| script = "//build/bazel/scripts/bazel_gn_target_action.py" |
| |
| inputs = [ |
| "//build/bazel/toplevel.MODULE.bazel", |
| "//build/bazel/templates/template.platform_mappings", |
| "//build/bazel/templates/template.bazel.sh.config", |
| "//build/bazel/templates/template.bazelrc", |
| |
| # TODO(https://fxbug.dev/475142618): Remove this once change in rust.BUILD.bazel |
| # correctly trigger bazel action rebuilds. |
| "//build/bazel/toolchains/rust/rust.BUILD.bazel", |
| |
| # Starlark query files |
| "//build/bazel/starlark/FuchsiaPackageInfo_archive.cquery", |
| |
| # Imported by bazel_gn_target_action.py |
| # LINT.IfChange(bazel_gn_target_imports) |
| "//build/api/debug_symbols.py", |
| "//build/bazel/scripts/bazel_action_impl.py", |
| "//build/bazel/scripts/bazel_ninja_delayed_actions.py", |
| "//build/bazel/scripts/bazel_action_file_copy_utils.py", |
| "//build/bazel/scripts/bazel_action_utils.py", |
| "//build/bazel/scripts/bazel_compdb_utils.py", |
| "//build/bazel/scripts/bazel_label_mapper.py", |
| "//build/bazel/scripts/bazel_rust_analyzer_utils.py", |
| "//build/bazel/scripts/build_utils.py", |
| "//build/bazel/scripts/thread_pool_helpers.py", |
| "//build/bazel/scripts/workspace_utils.py", |
| |
| #LINT.ThenChange(//build/bazel/scripts/bazel_gn_target_action.py:imports) |
| |
| # Imported by bazel_action_impl.py |
| #LINT.IfChange(bazel_action_impl_imports) |
| "//build/bazel/scripts/bazel_action_file_copy_utils.py", |
| "//build/bazel/scripts/bazel_action_utils.py", |
| "//build/bazel/scripts/bazel_source_path_mapper.py", |
| "//build/bazel/scripts/build_utils.py", |
| "//build/bazel/scripts/stdio_redirection.py", |
| |
| #LINT.ThenChange(//build/bazel/scripts/bazel_action_impl.py:imports) |
| |
| # The shell script used to execute Bazel itself. |
| "//build/bazel/wrapper.bazel.sh", |
| ] + _bazel_build_files |
| |
| if (defined(invoker.inputs)) { |
| inputs += invoker.inputs |
| } |
| |
| depfile = "${target_gen_dir}/${target_name}.d" |
| |
| outputs = [ |
| _bazel_command_file, |
| _bazel_explain_file, |
| _debug_symbols_manifest, |
| _timings_file, |
| ] |
| if (_update_rust_project) { |
| outputs += [ _rust_project_json ] |
| } |
| |
| # bazel_gn_target_action.py always checks the rbe_settings.json file to |
| # see if RBE is enabled or not. |
| inputs += [ "${root_build_dir}/rbe_settings.json" ] |
| deps += [ "//build/rbe:rbe_settings.json" ] |
| |
| # bazel_gn_target_action.py always checks global_bazel_args.json for |
| # configuration of extra global arguments |
| inputs += [ "${root_build_dir}/bazel_args/global_args.json" ] |
| deps += [ "//build/bazel/config:global_args.json" ] |
| |
| # Write stamp files for every Bazel target executed by this bazel_action. |
| # Note these stamps are written to paths based on Bazel target labels. |
| # This makes sure the same Bazel target is not claimed by multiple |
| # bazel_actions in the same build graph, which breaks Ninja noop checks, |
| # see http://b/353897478. In case it happens, GN will fail complaining about |
| # multiple targets sharing the same output. |
| _dedupe_stamp_lookup = [] |
| foreach(_bazel_target, _bazel_targets) { |
| _out_dir = get_label_info(_bazel_target, "target_out_dir") |
| _bazel_label = get_label_info(_bazel_target, "name") |
| |
| if (_build_for_host) { |
| _dedupe_suffix = "${host_os}_${host_cpu}" |
| } else { |
| _dedupe_suffix = "${current_os}_${current_cpu}" |
| } |
| if (defined(invoker.bazel_platform)) { |
| _dedupe_suffix = invoker.bazel_platform |
| } |
| |
| _stamp_path = "${_out_dir}/${_bazel_label}.${_dedupe_suffix}.bazel_target_can_only_be_referenced_by_one_bazel_action" |
| outputs += [ _stamp_path ] |
| _dedupe_stamp_lookup += [ |
| { |
| bazel_target = _bazel_target |
| stamp_path = _stamp_path |
| }, |
| ] |
| } |
| |
| args = [ |
| "--build-dir", |
| rebase_path(root_build_dir, root_build_dir), |
| "--fuchsia-dir", |
| rebase_path("//", root_build_dir), |
| "--command", |
| invoker.command, |
| "--gn-target-label", |
| get_label_info(":$target_name", "label_no_toolchain"), |
| "--bazel-platform-label", |
| _bazel_platform_label, |
| "--bazel-targets", |
| ] + _bazel_targets + |
| [ |
| "--depfile", |
| rebase_path(depfile, root_build_dir), |
| "--command-file", |
| _rebased_bazel_command_file, |
| "--timings-file", |
| _rebased_timings_file, |
| "--explain-file", |
| _rebased_bazel_explain_file, |
| "--debug-symbols-manifest", |
| _rebased_debug_symbols_manifest, |
| ] |
| |
| if (_update_rust_project) { |
| args += [ |
| "--rust-sysroot", |
| rebased_rustc_prefix, |
| "--rust-project-json", |
| _rebased_rust_project_json, |
| ] |
| } |
| |
| if (bazel_auto_refresh_compdb) { |
| _compdb_file = |
| "${target_out_dir}/${target_name}.bazel_compile_commands.json" |
| _rebased_compdb_file = rebase_path(_compdb_file, root_build_dir) |
| outputs += [ _compdb_file ] |
| args += [ |
| "--compdb-file", |
| _rebased_compdb_file, |
| ] |
| } |
| |
| # Set the expected outputs |
| foreach(output, _all_outputs) { |
| if (output.type == "file") { |
| outputs += [ output.ninja_file ] |
| } else if (output.type == "directory") { |
| foreach(tracked_file, output.tracked_files) { |
| outputs += [ "${output.ninja_dir}/${tracked_file}" ] |
| } |
| } else if (output.type == "package") { |
| outputs += [ output.ninja_archive ] |
| } else if (output.type == "final_symlink") { |
| outputs += [ output.ninja_file ] |
| } |
| } |
| |
| if (_has_package_outputs) { |
| # These starlark script are used to perform queries to get provider |
| # values for each package. |
| inputs += [ "//build/bazel/starlark/FuchsiaPackageInfo_archive.cquery" ] |
| } |
| |
| if (invoker.command == "build") { |
| outputs += [ _bazel_build_events_log_json ] |
| |
| args += [ |
| "--bazel-build-events-log-json", |
| _rebased_bazel_build_events_log_json, |
| ] |
| } |
| |
| metadata = { |
| if (defined(invoker.metadata)) { |
| forward_variables_from(invoker.metadata, "*") |
| } |
| expect_includes_barrier = [] |
| |
| # Hint to ninja that this action can take about a minute, so that it's |
| # appropriately weighted in the calculation of the critical path for a |
| # build. |
| ninja_edge_weights = |
| [ rebase_path(outputs[0], root_build_dir) + ",60000" ] |
| |
| if (invoker.command == "build") { |
| # Used by //:bazel_build_events_logs Build API module. |
| bazel_build_events_log = [ |
| { |
| gn_label = get_label_info(":$target_name", "label_no_toolchain") |
| build_events_log = _rebased_bazel_build_events_log_json |
| format = "json" |
| }, |
| ] |
| |
| # Used by //:bazel_build_actions target. |
| bazel_build_actions_barrier = [] |
| bazel_build_actions = [ |
| # LINT.IfChange(bazel_build_actions) |
| { |
| gn_target = get_label_info(":$target_name", "label_no_toolchain") |
| bazel_targets = _bazel_targets |
| no_sdk = _no_sdk |
| is_host = _build_for_host |
| gn_targets_dir = |
| rebase_path(_gn_targets_repository_path, root_build_dir) |
| gn_targets_manifest = |
| rebase_path(_gn_targets_repository_manifest, root_build_dir) |
| gn_targets_licenses_spdx = |
| rebase_path(_all_licenses_spdx_file, root_build_dir) |
| debug_symbols_manifest = _rebased_debug_symbols_manifest |
| bazel_command_file = _rebased_bazel_command_file |
| bazel_explain_file = _rebased_bazel_explain_file |
| timings_file = _rebased_timings_file |
| build_events_log_json = _rebased_bazel_build_events_log_json |
| |
| if (_update_rust_project) { |
| bazel_rust_project_json = _rebased_rust_project_json |
| } |
| |
| if (bazel_auto_refresh_compdb) { |
| bazel_compdb_file = _rebased_compdb_file |
| } |
| }, |
| # LINT.ThenChange(//BUILD.gn:bazel_build_actions) |
| ] |
| |
| # Used by //:debug_symbols |
| debug_symbol_manifests = [ |
| { |
| label = get_label_info(":$target_name", "label_no_toolchain") |
| manifest = _rebased_debug_symbols_manifest |
| }, |
| ] |
| } |
| |
| # Used by //:bazel_target_infos target. |
| bazel_target_infos_barrier = [] |
| bazel_target_infos = [] |
| foreach(entry, _all_outputs) { |
| # LINT.IfChange(bazel_target_infos) |
| bazel_target_infos += [ |
| { |
| forward_variables_from(entry, |
| "*", |
| [ |
| "ninja_file", |
| "ninja_archive", |
| "ninja_dir", |
| ]) |
| |
| # Look up the stamp path for the bazel target that makes these |
| # outputs. |
| _stamp_entry = { |
| } |
| foreach(_stamp_entry, _dedupe_stamp_lookup) { |
| if (_stamp_entry.bazel_target == bazel_target) { |
| stamp_path = |
| rebase_path(_stamp_entry.stamp_path, root_build_dir) |
| } |
| } |
| |
| # To differentiate different bazel invocations' outputs. |
| bazel_platform_config = _bazel_platform_config |
| bazel_platform_label = _bazel_platform_label |
| |
| # These all need to be rebased from GN paths to outdir-relative |
| # paths |
| if (defined(entry.ninja_file)) { |
| ninja_file = rebase_path(entry.ninja_file, root_build_dir) |
| } |
| if (defined(entry.ninja_archive)) { |
| ninja_archive = rebase_path(entry.ninja_archive, root_build_dir) |
| } |
| if (defined(entry.ninja_dir)) { |
| ninja_dir = rebase_path(entry.ninja_dir, root_build_dir) |
| } |
| |
| # The depfile that ninja will read for this action. |
| ninja_depfile = rebase_path(depfile, root_build_dir) |
| |
| # The gn_targets_dir that needs to be symlinked into the workspace |
| # to build the bazel action. This is transitional until this is |
| # setup on a per-action basis via the bazel_gn_target_action.py |
| # script and more explicit data about the GN inputs needed by the |
| # bazel action. |
| gn_targets_dir = |
| rebase_path(_gn_targets_repository_path, root_build_dir) |
| gn_targets_manifest = |
| rebase_path(_gn_targets_repository_manifest, root_build_dir) |
| }, |
| ] |
| # LINT.ThenChange(//BUILD.gn:bazel_target_infos, |
| # //build/bazel/scripts/bazel_action_utils.py:bazel_target_infos) |
| } |
| } |
| |
| deps += [ |
| # This dependency exists to ensure that this manifest is generated |
| # at `gn gen` time |
| ":${_gn_targets_repository_manifest_target}", |
| |
| # This dependency exists to ensure the SPDX file is updated if needed. |
| # //build/regenerator will write a placeholder file at the same location |
| # with a timestamp in the distant past, as this is needed to perform |
| # Bazel queries before calling Ninja. However, building Bazel targets |
| # require a valid license file. |
| ":${_all_licenses_spdx_target}", |
| |
| # In addition to checking whether the action is allowed, this dependency |
| # ensures that the template is being used on the default toolchain. |
| "//build/bazel:bazel_action_allowlist", |
| ] |
| |
| if (!_no_sdk) { |
| deps += [ |
| # TODO(https://fxbug.dev/333907192): Remove this IDK. |
| "//build/bazel:fuchsia_internal_only_idk.hash", |
| |
| # The IDK repository is generated by regenerator.py but contains |
| # symlinks to Ninja artifact locations. Ensure the ninja artifacts |
| # exist. |
| "//sdk:ensure_bazel_in_tree_idk_is_populated_for_bazel_action", |
| ] |
| } else if (invoker.bazel_config == "fuchsia_platform") { |
| deps += [ "//zircon/public/sysroot_sdk:sysroot_for_fuchsia_platform" ] |
| } |
| |
| # Using the console pool prevents concurrent bazel build actions to run |
| # (otherwise the `bazel-bin` symlink target would become unpredictable |
| # resulting in erroneous outputs or errors), as well as allow Bazel to |
| # print its progress on smart terminals when `fx build` is invoked |
| # from one, which is handy to follow long-lasting commands. |
| pool = "//:console($default_toolchain)" |
| |
| # This action definitely cannot be hermetic. Callers should add |
| # themselves to the //build:non_hermetic_deps visibility list. |
| hermetic_deps = false |
| |
| # The build events log contains absolute paths written by Bazel! |
| check_for_output_dir_leaks = false |
| } |
| } else { |
| not_needed(invoker, "*") |
| not_needed([ "target_name" ]) |
| } |
| } |