| # 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/bazel_args.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() { |
| # Output extra information when Bazel build actions fail. |
| bazel_verbose_failures = true |
| |
| # 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 target patterns 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 target patterns. |
| # |
| # 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`. |
| # |
| # 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`. |
| # |
| # manifest: (optional) |
| # output path for the package's manifest file, 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. |
| # |
| # extra_bazel_args: (optional) |
| # A list extra command line arguments to pass to Bazel. |
| # Type: list of string. |
| # |
| # filter_bazel_info_logs: (optional) |
| # When true (the default value), INFO level logs are filtered from Bazel. |
| # INFO level logs from Bazel are usually not interesting during Ninja |
| # invocations. |
| # Type: boolean |
| # Default: true |
| # |
| # remote_build: (optional) |
| # Set this to false to override the global default `enable_bazel_remote_rbe` |
| # setting which controls whether the underlying bazel invocation |
| # will build remotely using RBE. |
| # Type: boolean |
| # Default: `enable_bazel_remote_rbe` (global) |
| # |
| # 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 |
| # |
| # no_sdk: (optional) |
| # Set this to true to run a Bazel command to build artifacts that do not |
| # depend on the Fuchsia IDK or SDK. This makes these targets available to |
| # the GN graph early during the build. Must be true if `host` is true. |
| # Type: boolean |
| # Default: false |
| # |
| # host: (optional) |
| # Set this to true to run a Bazel command to build host artifacts. |
| # Requires `no_sdk = true`. |
| # Type: boolean |
| # Default: false |
| # |
| # 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") { |
| 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!") |
| |
| _no_sdk = defined(invoker.no_sdk) && invoker.no_sdk |
| _build_for_host = defined(invoker.host) && invoker.host |
| assert(!_build_for_host || _no_sdk, |
| "`no_sdk` must true when `host` is true. ") |
| |
| # Limit usage of `bazel_platform` to host platforms to minimize chances of |
| # misuse. It's created to support cross-compiling SDK host tools. |
| if (defined(invoker.bazel_platform)) { |
| assert(_build_for_host, |
| "`bazel_platform` is only supported when `host` is true.") |
| } |
| |
| _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_file_outputs = false |
| _has_directory_outputs = false |
| _has_package_outputs = false |
| _has_final_symlink_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}" |
| }, |
| ] |
| _has_file_outputs = true |
| } |
| |
| 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 |
| tracked_files = entry.tracked_files |
| }, |
| ] |
| |
| _has_directory_outputs = true |
| } |
| |
| 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}" |
| } |
| _manifest = "" |
| if (defined(entry.manifest)) { |
| _manifest = "${_ninja_base_dir}/${entry.manifest}" |
| } |
| _all_outputs += [ |
| { |
| type = "package" |
| bazel_target = get_label_info(entry.package_label, "label_no_toolchain") |
| ninja_archive = _archive |
| ninja_manifest = _manifest |
| 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}" |
| }, |
| ] |
| _has_final_symlink_outputs = true |
| } |
| |
| # 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_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 contain a mapping from Bazel artifacts to Ninja outputs. |
| _path_mapping = "${target_out_dir}/${target_name}.path_mapping" |
| _rebased_path_mapping = rebase_path(_path_mapping, root_build_dir) |
| |
| # A file that will receive the exact Bazel command invoked by the |
| # bazel_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_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) |
| |
| _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", |
| ]) |
| |
| mnemonic = "BAZEL" |
| script = "//build/bazel/scripts/bazel_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", |
| |
| # Imported by bazel_action.py |
| "//build/api/debug_symbols.py", |
| "//build/bazel/scripts/bazel_compdb_utils.py", |
| "//build/bazel/scripts/bazel_rust_analyzer_utils.py", |
| "//build/bazel/scripts/build_utils.py", |
| "//build/bazel/scripts/stdio_redirection.py", |
| "//build/bazel/scripts/thread_pool_helpers.py", |
| "//build/bazel/scripts/workspace_utils.py", |
| "//build/bazel/wrapper.bazel.sh", |
| ] + _bazel_build_files |
| |
| if (defined(invoker.inputs)) { |
| inputs += invoker.inputs |
| } |
| |
| depfile = "${target_gen_dir}/${target_name}.d" |
| |
| outputs = [ |
| _path_mapping, |
| _bazel_command_file, |
| _bazel_explain_file, |
| _debug_symbols_manifest, |
| _rust_project_json, |
| _timings_file, |
| ] |
| |
| # 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_stamps = [] |
| foreach(_bazel_target, _bazel_targets) { |
| _out_dir = get_label_info(_bazel_target, "target_out_dir") |
| _bazel_label = get_label_info(_bazel_target, "name") |
| |
| _dedupe_suffix = "${current_os}_${current_cpu}" |
| if (_build_for_host) { |
| _dedupe_suffix = "${host_os}_${host_cpu}" |
| } |
| if (defined(invoker.bazel_platform)) { |
| _dedupe_suffix = invoker.bazel_platform |
| } |
| |
| _dedupe_stamps += [ "${_out_dir}/${_bazel_label}.${_dedupe_suffix}.bazel_target_can_only_be_referenced_by_one_bazel_action" ] |
| } |
| outputs += _dedupe_stamps |
| |
| 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"), |
| "--gn-targets-repository-dir", |
| rebase_path(_gn_targets_repository_path, root_build_dir), |
| "--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, |
| "--path-mapping", |
| _rebased_path_mapping, |
| "--debug-symbols-manifest", |
| _rebased_debug_symbols_manifest, |
| "--rust-sysroot", |
| rebased_rustc_prefix, |
| "--rust-project-json", |
| _rebased_rust_project_json, |
| "--stamp-files", |
| ] |
| foreach(s, _dedupe_stamps) { |
| args += [ rebase_path(s, root_build_dir) ] |
| } |
| if (bazel_verbose_failures) { |
| args += [ "--verbose_failures" ] |
| } |
| |
| 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, |
| ] |
| } |
| |
| if (_has_file_outputs) { |
| args += [ "--file-outputs" ] |
| foreach(output, _all_outputs) { |
| if (output.type == "file") { |
| args += [ |
| output.bazel_file, |
| rebase_path(output.ninja_file, root_build_dir), |
| ] |
| outputs += [ output.ninja_file ] |
| } |
| } |
| } |
| |
| if (_has_directory_outputs) { |
| foreach(output, _all_outputs) { |
| if (output.type == "directory") { |
| args += [ |
| "--directory-outputs", |
| output.bazel_dir, |
| rebase_path(output.ninja_dir, root_build_dir), |
| "${output.copy_debug_symbols}", |
| ] + output.tracked_files |
| assert(output.tracked_files != [], |
| "Directory outputs require tracked files.") |
| foreach(tracked_file, output.tracked_files) { |
| outputs += [ "${output.ninja_dir}/${tracked_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_and_manifest.cquery", |
| "//build/bazel/starlark/FuchsiaDebugSymbolInfo_debug_symbol_dirs.cquery", |
| ] |
| foreach(output, _all_outputs) { |
| if (output.type == "package") { |
| _archive_arg = "NONE" |
| if (output.ninja_archive != "") { |
| outputs += [ output.ninja_archive ] |
| _archive_arg = rebase_path(output.ninja_archive, root_build_dir) |
| } |
| _manifest_arg = "NONE" |
| if (output.ninja_manifest != "") { |
| outputs += [ output.ninja_manifest ] |
| _manifest_arg = rebase_path(output.ninja_manifest, root_build_dir) |
| } |
| _copy_debug_symbols = output.copy_debug_symbols |
| |
| args += [ |
| "--package-outputs", |
| output.bazel_target, |
| _archive_arg, |
| _manifest_arg, |
| "${output.copy_debug_symbols}", |
| ] |
| } |
| } |
| } |
| |
| if (_has_final_symlink_outputs) { |
| args += [ "--final-symlink-outputs" ] |
| foreach(output, _all_outputs) { |
| if (output.type == "final_symlink") { |
| args += [ |
| output.bazel_file, |
| rebase_path(output.ninja_file, root_build_dir), |
| ] |
| outputs += [ output.ninja_file ] |
| } |
| } |
| } |
| |
| if (invoker.command == "build") { |
| outputs += [ _bazel_build_events_log_json ] |
| |
| args += [ |
| "--bazel-build-events-log-json", |
| _rebased_bazel_build_events_log_json, |
| ] |
| } |
| |
| args += [ "--" ] |
| |
| if (bazel_quiet) { |
| args += [ "--config=quiet" ] |
| } else { |
| # Disable INFO lines and printing results, this makes Bazel output much |
| # less chatty when invoked from Ninja. https://fxbug.dev/42077198 |
| args += [ "--ui_event_filters=-info" ] |
| |
| if (invoker.command != "query") { |
| # The --show_result option is not supported by bazel query. |
| args += [ "--show_result=0" ] |
| } |
| } |
| |
| if (_build_for_host) { |
| args += [ "--config=host_config_args" ] |
| if (defined(invoker.bazel_platform)) { |
| args += |
| [ "--platforms=//build/bazel/platforms:${invoker.bazel_platform}" ] |
| } else { |
| args += [ "--platforms=//build/bazel/platforms:host" ] |
| } |
| } else { |
| # Since this template can only be used on the default toolchain, the |
| # platform is always Fuchsia. |
| args += [ "--config=fuchsia_config_args" ] |
| if (defined(invoker.bazel_platform)) { |
| args += |
| [ "--platforms=//build/bazel/platforms:${invoker.bazel_platform}" ] |
| } else { |
| args += [ "--platforms=//build/bazel/platforms:fuchsia_${current_cpu}" ] |
| } |
| } |
| |
| # When remote builds are enabled, append the right build arguments. |
| # These must appear on the Bazel command-line otherwise remote builds |
| # will fail on infra (the reason being that the Bazel wrapper script |
| # detects these options to add infra-specific proxy configuration |
| # the the final command-line). |
| if (enable_bazel_remote_rbe) { |
| _remote_build = !defined(invoker.remote_build) || invoker.remote_build |
| if (_remote_build) { |
| # It is assumed that remote builds are enabled for both the default |
| # and host GN toolchains at the same time. |
| args += bazel_args.remote_build |
| } |
| } else { |
| # Remote builds are globally disabled, so ignore this value if it exists. |
| not_needed(invoker, [ "remote_build" ]) |
| } |
| |
| # Similarly, this config must appear on the command-line and cannot |
| # be part of --config=host or --config=fuchsia. |
| if (bazel_upload_build_events != "") { |
| args += [ "--config=$bazel_upload_build_events" ] |
| } |
| |
| # --config=quiet is always used by default, but it is possible |
| # to disable that by setting filter_bazel_info_logs to false. |
| _filter_bazel_info_logs = true |
| if (defined(invoker.filter_bazel_info_logs)) { |
| _filter_bazel_info_logs = invoker.filter_bazel_info_logs |
| } |
| if (!_filter_bazel_info_logs) { |
| args += [ "--config=verbose" ] |
| } |
| |
| metadata = { |
| if (defined(invoker.metadata)) { |
| forward_variables_from(invoker.metadata, "*") |
| } |
| |
| # 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 |
| 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 |
| path_mapping = _rebased_path_mapping |
| timings_file = _rebased_timings_file |
| build_events_log_json = _rebased_bazel_build_events_log_json |
| 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 |
| }, |
| ] |
| } |
| } |
| |
| if (defined(invoker.extra_bazel_args)) { |
| args += invoker.extra_bazel_args |
| } |
| |
| if (!defined(deps)) { |
| deps = [] |
| } |
| 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", |
| ] |
| } |
| |
| # 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 |
| } |
| } |