| # Copyright 2019 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("$zx/public/gn/host_tool_action.gni") |
| import("$zx/public/gn/manifest.gni") |
| import("$zx/public/gn/resource.gni") |
| |
| declare_args() { |
| # This can be either "lz4f" or "zstd", optionally followed by ".LEVEL" |
| # where `LEVEL` can be an integer or "max". It can also be just "LEVEL" |
| # to to use the default algorithm with a non-default setting. |
| # |
| # The default level for each algorithm is tuned to balance compression |
| # speed with compression ratio. Higher levels make image builds slower. |
| # So using the default during rapid development (quick builds, pretty |
| # good compression) and "max' for production builds (slow builds, best |
| # compression available) probably makes sense. |
| zbi_compression = "zstd" |
| } |
| |
| # The compression algorithm part of the $zbi_compression setting. |
| zbi_compression_algorithm = get_path_info(zbi_compression, "name") |
| if (get_path_info(zbi_compression, "extension") == "" && |
| zbi_compression_algorithm != "lz4f" && |
| zbi_compression_algorithm != "zstd") { |
| # This must match what $zx/tools/zbi/zbi.cc uses by default. |
| zbi_compression_algorithm = "lz4f" |
| } |
| |
| # Define inputs to a dependent zbi() target. |
| # |
| # The target generates a manifest that collects any manifest_lines from its |
| # dependencies' metadata, e.g. contributed by resource() targets. It |
| # contributes metadata that will drive zbi() to use this manifest, as well |
| # as any non-BOOTFS inputs given via $sources and $args. |
| # |
| # resource() targets in the dependencies explicitly contribute to the |
| # manifest. Many other target types such as executable() and |
| # shared_library() that have a $install_path parameter (even if defaulted) |
| # implicitly contribute to the manifest. |
| # |
| # It's not necessary to use an explicit zbi_input() target just to collect |
| # files into the BOOTFS of a zbi(). Use zbi_input() explicitly to get the |
| # manifest file as an explicit build artifact, to apply a target directory |
| # prefix to the manfiest file, or to include other types. |
| # |
| # Parameters |
| # |
| # data_deps, deps |
| # Optional: Dependencies examined for metadata. Any other zbi_input() |
| # or zbi() targets in this dependency graph will flow into any zbi() |
| # target that depends on this one. Any manifest metadata will be collected |
| # here into a manifest file; see manifest_file(). |
| # Type: list(label) |
| # |
| # prefix |
| # Optional: Directory prefix prepended to the target path in each |
| # manifest entry. This is normalized when nonempty so it need not end |
| # with a `/`. |
| # Type: string |
| # Default: "" |
| # |
| # type |
| # Optional: The input type for any $sources or $args, as in the |
| # `--type` switch to the `zbi` tool. See `zbi --help` for the set of |
| # available types. A value of "" uses `zbi --files`. |
| # Type: string |
| # Default: "" |
| # |
| # sources |
| # Optional: Files to put into the ZBI. $type determines what kinds of |
| # files these can be and how their contents are used. If $type is "" |
| # (the default), then these can be manifest files or directories. |
| # Type: list(file) |
| # |
| # args |
| # Optional: Additional arguments to the `zbi` tool. These are switches |
| # that will precede the $sources on the `zbi` command line, so they |
| # can include e.g. `--prefix=...` to affect contents of manifest file. |
| # The most common use is "--entry=..." to provide literal contents right |
| # in the GN file (e.g. for `type = "cmdline"`). |
| # |
| # See manifest_file() for additional parameters. The manifest file |
| # produced from those parameters contributes to the BOOTFS (as modified |
| # by $prefix). |
| # |
| template("zbi_input") { |
| manifest_file(target_name) { |
| prefix = "" |
| forward_variables_from(invoker, |
| "*", |
| [ |
| "args", |
| "metadata", |
| "type", |
| "sources", |
| ]) |
| |
| # Elaborate the defaults identically to manifest_file() so that we know |
| # the file name to pass to `zbi`. |
| if (!defined(output_dir)) { |
| output_dir = target_gen_dir |
| } |
| if (!defined(output_extension)) { |
| output_extension = "manifest" |
| } |
| if (!defined(output_name)) { |
| output_name = target_name |
| } |
| |
| manifest_file = "$output_dir/$output_name" |
| if (output_extension != "") { |
| manifest_file += ".$output_extension" |
| } |
| |
| metadata = { |
| # TODO(mcgrathr): seems to tickle a gn bug, see below |
| #zbi_barrier = [] |
| zbi_bootfs_manifest = [] |
| zbi_input_args = [] |
| |
| if (defined(invoker.metadata)) { |
| forward_variables_from(invoker.metadata, "*") |
| } |
| |
| # When a zbi() target depends on this zbi_input() target, it includes |
| # other zbi_input() targets in this target's deps, but not data_deps. |
| if (defined(invoker.deps)) { |
| # TODO(mcgrathr): seems to tickle a gn bug |
| #zbi_barrier += invoker.deps |
| } |
| |
| # An explicit type applies only to $sources and $args. |
| if (defined(invoker.type) && invoker.type != "") { |
| zbi_input_args += [ "--type=${invoker.type}" ] |
| } else if (defined(invoker.args) || defined(invoker.sources)) { |
| zbi_input_args += [ |
| # The implicit type is always --files, and needs to be reset in |
| # case the previous `zbi_input_args` list collected left a |
| # different `--type=...` as the last state. |
| "--files", |
| |
| # Following $args and $sources entries shouldn't get a |
| # previously-set prefix. |
| "--prefix=", |
| ] |
| } |
| |
| # Explicit $args come first, for e.g. "-u" or "-g" to affect inputs. |
| # $args may also contain "--entry=..." payloads directly. |
| if (defined(invoker.args)) { |
| zbi_input_args += invoker.args |
| } |
| |
| if (defined(invoker.sources)) { |
| zbi_input_args += rebase_path(invoker.sources, root_build_dir) |
| } |
| |
| # Always include the manifest generated from the deps here. The |
| # `manifest_barrier` in manifest_file() will prevent zbi() from |
| # collecting `manifest_lines` that are redundant with this manifest. |
| zbi_input_args += [ |
| "--prefix=$prefix", |
| "--files", |
| rebase_path(manifest_file, root_build_dir), |
| ] |
| zbi_bootfs_manifest += [ |
| { |
| label = get_label_info(":$target_name", "label_with_toolchain") |
| prefix = prefix |
| path = rebase_path(manifest_file, root_build_dir) |
| }, |
| ] |
| } |
| } |
| } |
| |
| # Build a ZBI file rolling up the contents from dependencies. |
| # |
| # This automatically collects a BOOTFS manifest from the dependencies like |
| # zbi_input() does. It also takes any zbi_input() or equivalent targets |
| # from the dependencies. (The kernel acts as a zbi_input(), for example.) |
| # |
| # Parameters |
| # |
| # cpu |
| # Optional: CPU architecture for a complete ZBI. |
| # If this is "", then this target may produce an incomplete ZBI. |
| # Otherwise, it's a CPU name ("arm64" or "x64") and the target will |
| # fail if the ZBI is not complete so it can be booted on that CPU. |
| # Type: string |
| # Default: current_cpu |
| # |
| # compress |
| # Optional: Whether to compress the BOOTFS and other `ZBI_TYPE_STORAGE` |
| # items in the output. See the `--compressed` switch in `zbi --help`. |
| # If this is a string rather than a bool, it's the argument for the |
| # `--compressed` switch to `zbi`. A value of `true` is replaced with |
| # $zbi_compression. |
| # Type: bool or string |
| # Default: true |
| # |
| # output_dir |
| # Optional: Directory where the output file is written. |
| # Type: dir |
| # Default: target_out_dir |
| # |
| # output_extension |
| # Optional: Extension added to $output_name. |
| # Type: string |
| # Default: "zbi" |
| # |
| # output_name |
| # Optional: Name of the output file. |
| # Type: string |
| # Default: target_name |
| # |
| # tags |
| # Optional: List of tags to associate with the image. |
| # This is reflected in build_api_module("images") metadata. |
| # Type: list(string) |
| # |
| template("zbi") { |
| zbi_target = target_name |
| input_target = "_zbi.input.$target_name" |
| rspfile_target = "_zbi.rsp.$target_name" |
| rspfile = "$target_gen_dir/$target_name.zbi.rsp" |
| json_target = "_zbi.manifest.$target_name" |
| json_file = "$target_gen_dir/$target_name.manifest.json" |
| |
| zbi_input(input_target) { |
| visibility = [ |
| ":$rspfile_target", |
| ":$json_target", |
| ] |
| forward_variables_from(invoker, |
| [ |
| "deps", |
| "output_dir", |
| "output_name", |
| "testonly", |
| ]) |
| assert(defined(deps), "zbi(\"$zbi_target\") must have `deps`") |
| if (!defined(output_name)) { |
| output_name = zbi_target |
| } |
| } |
| |
| if (defined(invoker.output_name)) { |
| output_name = invoker.output_name |
| } else { |
| output_name = target_name |
| } |
| |
| output_file = output_name |
| |
| if (defined(invoker.output_extension)) { |
| if (invoker.output_extension != "") { |
| output_file += ".${invoker.output_extension}" |
| } |
| } else { |
| output_file += ".zbi" |
| } |
| |
| if (defined(invoker.output_dir)) { |
| output_dir = invoker.output_dir |
| } else { |
| output_dir = target_out_dir |
| } |
| |
| output_file = "$output_dir/$output_file" |
| |
| # Generate a response file of input arguments collected from metadata. |
| generated_file(rspfile_target) { |
| visibility = [ ":$zbi_target" ] |
| forward_variables_from(invoker, [ "testonly" ]) |
| deps = [ |
| ":$input_target", |
| ] |
| outputs = [ |
| rspfile, |
| ] |
| data_keys = [ "zbi_input_args" ] |
| walk_keys = [ "zbi_barrier" ] |
| output_conversion = "list lines" |
| } |
| |
| # Generate a JSON file that describes all the separate manifest files |
| # that feed into the BOOTFS construction. This could be used to produce |
| # a single flat manifest, though we don't need one to produce the ZBI. |
| # The same information is in the zbi_input_args metadata that feeds into |
| # the response file (above) in the form of --prefix=... switch and |
| # manifest file arguments. |
| generated_file(json_target) { |
| visibility = [ ":$zbi_target" ] |
| forward_variables_from(invoker, [ "testonly" ]) |
| deps = [ |
| ":$input_target", |
| ] |
| outputs = [ |
| json_file, |
| ] |
| data_keys = [ "zbi_bootfs_manifest" ] |
| walk_keys = [ "zbi_barrier" ] |
| output_conversion = "json" |
| metadata = { |
| images = [ |
| { |
| cpu = current_cpu |
| name = "$zbi_target.bootfs" |
| type = "json" |
| path = rebase_path(json_file, root_build_dir) |
| forward_variables_from(invoker, [ "tags" ]) |
| if (!defined(tags)) { |
| tags = [] |
| } |
| tags += [ "manifest" ] |
| }, |
| ] |
| } |
| } |
| |
| host_tool_action(zbi_target) { |
| forward_variables_from(invoker, |
| [ |
| "assert_no_deps", |
| "compress", |
| "data_deps", |
| "visibility", |
| "testonly", |
| ]) |
| deps = [ |
| ":$json_target", |
| ":$rspfile_target", |
| ] |
| outputs = [ |
| output_file, |
| ] |
| depfile = "${output_file}.d" |
| sources = [ |
| rspfile, |
| ] |
| |
| tool = "$zx/tools/zbi" |
| args = [ |
| "--output=" + rebase_path(output_file, root_build_dir), |
| "--depfile=" + rebase_path(depfile, root_build_dir), |
| "@" + rebase_path(rspfile, root_build_dir), |
| ] |
| |
| # Require a complete ZBI for the specified $cpu (or $current_cpu). |
| # A value of "" means it need not be a complete ZBI. |
| if (defined(invoker.cpu)) { |
| cpu = invoker.cpu |
| } else { |
| cpu = current_cpu |
| } |
| if (cpu != "") { |
| args += [ "--complete=$cpu" ] |
| } |
| |
| # This comes last to affect the output despite any earlier |
| # "-c" or "-u" from metadata.zbi_input_args meant to affect |
| # a particular input (e.g. for "--type=ramdisk"). |
| if (!defined(compress) || compress == true) { |
| compress = zbi_compression |
| } |
| if (compress == false) { |
| args += [ "--uncompressed" ] |
| } else { |
| args += [ "--compressed=$compress" ] |
| } |
| |
| metadata = { |
| images = [] |
| zbi_input_args = [] |
| |
| # Another zbi() target that depends on this one will include this ZBI as |
| # input, but not this ZBI's inputs. |
| zbi_barrier = [] |
| |
| if (defined(invoker.metadata)) { |
| forward_variables_from(invoker.metadata, "*") |
| } |
| |
| # For the //:images build_api_module(). |
| images += [ |
| { |
| label = get_label_info(":$target_name", "label_with_toolchain") |
| name = output_name |
| path = rebase_path(output_file, root_build_dir) |
| type = "zbi" |
| cpu = cpu |
| compressed = !defined(invoker.compress) || |
| (invoker.compress != false && invoker.compress != "none") |
| if (defined(testonly) && testonly) { |
| testonly = true |
| } |
| forward_variables_from(invoker, [ "tags" ]) |
| }, |
| ] |
| |
| # Provide metadata so that a zbi() target can also act as if it were a |
| # zbi_input() with `type = "zbi"` and $sources of this target's $outputs. |
| # Thus a zbi() target can be a dependency of another zbi() target to |
| # combine them without requiring an intervening zbi_input() target. |
| zbi_input_args += |
| [ "--type=container" ] + rebase_path(outputs, root_build_dir) |
| } |
| } |
| } |