| # Copyright 2026 The Fuchsia Authors |
| # |
| # Use of this source code is governed by a MIT-style |
| # license that can be found in the LICENSE file or at |
| # https://opensource.org/licenses/MIT |
| |
| import("//build/config/current_target_tuple.gni") |
| import("//build/rust/build.gni") |
| import("//build/rust/rustc_library.gni") |
| import("kernel_test_deps.gni") |
| |
| template("_kernel_rust_mod_impl") { |
| gen_dir = "$target_gen_dir/$target_name" |
| gen_dir_to_root_build_dir = rebase_path(root_build_dir, gen_dir) |
| |
| output_name = invoker.output_name |
| assert(string_replace(output_name, "-", "_") == output_name, |
| "no - allowed in mod names, only _") |
| assert(string_replace(output_name, ".", "_") == output_name, |
| "no . allowed in mod names, only _") |
| |
| # A label starts with // and so is already a Rust comment! |
| label = get_label_info(":$target_name", "label_with_toolchain") |
| gen_file_comment = [ |
| label, |
| "// This is a generated file. DO NOT EDIT!", |
| "", |
| ] |
| |
| assert(defined(invoker.sources), "kernel_rust_mod() requires `sources` list") |
| foreach(file, invoker.sources) { |
| assert(get_path_info(file, "extension") == "rs", |
| "only .rs files go in `source` list; use `inputs` for others") |
| } |
| _rust_sources = invoker.sources |
| |
| # This is semantically in Rust generating a single source file that contains: |
| # ``` |
| # <... the $source_root file's contents ...> |
| # #[path "$gen_dir_to_root_build_dir"] |
| # mod _imports { |
| # #[path "../path/from/root_build_dir/to/foo/source/dir"] |
| # mod foo; |
| # <... pair of such lines for each foo in deps + public_deps ...> |
| # } |
| # #[allow(unused_imports)] |
| # use _imports::{ |
| # foo, |
| # <... for each foo in deps ...> |
| # } |
| # #[allow(unused_imports)] |
| # pub use _imports::{ |
| # bar, |
| # <... for each bar in public_deps ...> |
| # } |
| # ``` |
| # |
| # However, it's accomplished with three generated_file() targets to generate |
| # three files at `gn gen` time, and the Rust include! macro, so there's no |
| # need for a build-time action to concatenate things. |
| # |
| # * The first file is the main $target_name target, the actual Rust source |
| # file to be compiled. |
| # * It contains the preamble, which is include!($source_root). |
| # * It then has the `mod _imports { ... }` item. |
| # * Finally, it has an include! for each of the other two files. |
| # * All this is collected via the `rust_mod_import_lines` metadata key. |
| # * The metadata walk include both $deps and $public_deps. |
| # |
| # * The second file contains the `use _imports::{ ... }` item. |
| # * This is collected via the `rust_mod_use_lines` metadata key. |
| # |
| # * The third file contains the `pub use _imports::{ ... }` item. |
| # * This is collected via the `rust_mod_pub_use_lines` metadata key. |
| # |
| # Each file has some prologue lines, then the lines collected from deps |
| # and/or public_deps, and then some epilogue lines. Two group() targets are |
| # defined solely to hold the prologue and epilogue metadata, respectively. |
| # Each file's metadata collection is across the ordered deps list of: |
| # prologue + {deps and/or public_deps} + epilogue. |
| # |
| # The individual lines for the $output_name module itself are contributed to |
| # all three metadata lists by the $target_name target's own metadata to roll |
| # up into the dependent kernel_rust_mod() target. |
| |
| gen_files = [ |
| # This list controls how each file will be generated. First, list |
| # the secondary generated files: the `use` and `pub use` lists. |
| { |
| name = "$target_name.use" |
| output = name |
| vars = { |
| visibility = [ ":$target_name" ] |
| } |
| metadata = { |
| } |
| prologue = { # Start the file. |
| rust_mod_use_lines = gen_file_comment + [ |
| "#[allow(unused_imports)]", |
| "use _imports::{", |
| ] |
| } |
| key = "rust_mod_use_lines" # Comma-separated list comes from here. |
| if (defined(invoker.deps)) { |
| deps = invoker.deps |
| } else { |
| deps = [] |
| } |
| epilogue = { # End the file. |
| rust_mod_use_lines = [ "};" ] |
| } |
| }, |
| { |
| name = "$target_name.pub_use" |
| output = name |
| vars = { |
| visibility = [ ":$target_name" ] |
| } |
| metadata = { |
| } |
| prologue = { # Start the file. |
| rust_mod_pub_use_lines = gen_file_comment + [ |
| "#[allow(unused_imports)]", |
| "pub use _imports::{", |
| ] |
| } |
| key = "rust_mod_pub_use_lines" # Comma-separated list comes from here. |
| if (defined(invoker.public_deps)) { |
| deps = invoker.public_deps |
| } else { |
| deps = [] |
| } |
| epilogue = { # End the file. |
| rust_mod_pub_use_lines = [ "};" ] |
| } |
| }, |
| ] |
| |
| test_deps = [] |
| if (defined(invoker.test_deps)) { |
| test_deps_target = "kernel_rust_mod.${target_name}.test_deps" |
| test_deps += [ ":$test_deps_target" ] |
| |
| kernel_test_deps(test_deps_target) { |
| visibility = [ ":*" ] |
| public_deps = invoker.test_deps |
| } |
| } |
| |
| # The primary generated file's details are partially derived from those. |
| gen_deps = test_deps |
| gen_includes = [] |
| foreach(gen, gen_files) { |
| gen_deps += [ ":${gen.name}" ] |
| gen_includes += [ "include!(\"${gen.name}.rs\");" ] |
| } |
| |
| gen_files += [ |
| { |
| name = target_name |
| output = output_name |
| vars = { |
| # The data_deps here do nothing but propagate to dependent targets. |
| forward_variables_from(invoker, |
| [ |
| "data_deps", |
| "visibility", |
| ]) |
| |
| # The data_deps on the other generated files just gets them into the |
| # graph. Since their outputs are used via include! and tracked via |
| # rustc's depfile generation, no GN target needs them in inputs and so |
| # no target needs to have direct deps on them. |
| if (!defined(data_deps)) { |
| data_deps = [] |
| } |
| data_deps += gen_deps |
| } |
| |
| _mod_import_lines = [] |
| _mod_use_list = [] |
| if (invoker.upward_metadata) { |
| _mod_path = rebase_path("$gen_dir/$output.rs", root_build_dir) |
| _mod_use_list = [ " $output_name," ] |
| |
| # Contribute this mod's own lines to the next kernel_rust_mod() up. |
| # It's always `pub mod` here because that's inside the `mod _imports` |
| # when collected, so it's still actually private to the collecting |
| # kernel_rust_mod() unless it re-exports it via |
| # rust_mod_pub_use_lines. |
| _mod_import_lines += [ |
| " #[path = \"${_mod_path}\"]", |
| " pub mod $output_name; $label", |
| ] |
| } |
| metadata = { |
| # Start the empty lists before forwarding any invoker metadata. |
| rust_mod_barrier = [] |
| rust_mod_import_lines = [] |
| rust_mod_use_lines = [] |
| rust_mod_pub_use_lines = [] |
| rust_sources = [] |
| |
| if (defined(invoker.metadata)) { |
| forward_variables_from(invoker.metadata, "*") |
| } |
| |
| if (invoker.upward_metadata) { |
| rust_mod_import_lines += _mod_import_lines |
| rust_mod_use_lines += _mod_use_list |
| rust_mod_pub_use_lines += _mod_use_list |
| } |
| |
| # The common code in the loop below includes each generated file in the |
| # $rust_sources list. Also contribute anything else from the invoker. |
| rust_sources = rebase_path(_rust_sources, root_build_dir) |
| if (defined(invoker.inputs)) { |
| rust_sources += rebase_path(invoker.inputs, root_build_dir) |
| } |
| |
| # `lk_debug_level_2` (`vmzircon.with-tests`) is selected as the default |
| # kernel toolchain target for Clippy and IDE analysis because it is the |
| # primary development and testing configuration. It includes kernel test |
| # commands and test modules (`ktest`), ensuring full code coverage |
| # during IDE type analysis and diagnostic checks. |
| _toolchain_name = get_label_info(current_toolchain, "name") |
| _is_default_kernel_toolchain = |
| string_replace(_toolchain_name, "lk_debug_level_2", "") != |
| _toolchain_name |
| rust_target_mapping = [ |
| { |
| disable_rustdoc = true |
| disable_clippy = !_is_default_kernel_toolchain |
| clippy_label = |
| get_label_info("//zircon/kernel/bin:vmzircon.with-tests.clippy", |
| "label_with_toolchain") |
| actual_label = |
| get_label_info("//zircon/kernel/bin:vmzircon.with-tests", |
| "label_with_toolchain") |
| original_label = |
| get_label_info(":$target_name", "label_with_toolchain") |
| target_is_fuchsia = is_fuchsia |
| target = current_target_tuple |
| clippy_output = rebase_path( |
| "$root_gen_dir/zircon/kernel/bin/vmzircon.with-tests.clippy", |
| root_build_dir) |
| src = rust_sources |
| }, |
| ] |
| } |
| |
| prologue = { # Start the file. |
| rust_mod_import_lines = gen_file_comment + invoker.preamble |
| rust_mod_import_lines += [ |
| "", |
| "// kernel_rust_mod() source paths are relative to root_build_dir.", |
| "// The `_imports` module exists just to make the collected paths", |
| "// below resolve relative to this generated file.", |
| "#[path = \"${gen_dir_to_root_build_dir}\"]", |
| "mod _imports {", |
| ] |
| } |
| key = "rust_mod_import_lines" |
| if (defined(invoker.deps)) { |
| deps = invoker.deps |
| } else { |
| deps = [] |
| } |
| if (defined(invoker.public_deps)) { |
| deps += invoker.public_deps |
| } |
| epilogue = { # End the file. |
| rust_mod_import_lines = |
| [ |
| "}", |
| "", |
| "// Now bring those modules into the outer scope.", |
| ] + gen_includes |
| } |
| }, |
| ] |
| |
| gen_visibility = [] |
| foreach(gen, gen_files) { |
| gen_visibility += [ ":${gen.name}" ] |
| } |
| |
| # These groups are used in all the generated_file() metadata walks, and exist |
| # just to contribute their metadata before and after others, respectively. |
| # The deps and/or public_deps will come between them in the metadata walks. |
| prologue_deps = [ ":$target_name.prologue" ] |
| epilogue_deps = [ ":$target_name.epilogue" ] |
| foreach(which, |
| [ |
| "prologue", |
| "epilogue", |
| ]) { |
| group("$target_name.$which") { |
| visibility = gen_visibility |
| forward_variables_from(invoker, [ "testonly" ]) |
| metadata = { |
| foreach(gen, gen_files) { |
| forward_variables_from(gen[which], "*") |
| } |
| } |
| } |
| } |
| |
| foreach(gen, gen_files) { |
| generated_file(gen.name) { |
| forward_variables_from(invoker, [ "testonly" ]) |
| forward_variables_from(gen.vars, "*") |
| outputs = [ "$gen_dir/${gen.output}.rs" ] |
| output_conversion = "list lines" |
| data_keys = [ gen.key ] |
| walk_keys = [ |
| "rust_barrier", |
| "rust_mod_barrier", |
| "rust_mod_preamble_barrier", |
| ] |
| deps = prologue_deps + gen.deps + epilogue_deps |
| metadata = { |
| rust_sources = [] |
| forward_variables_from(gen.metadata, "*") |
| rust_sources += rebase_path(outputs, root_build_dir) |
| } |
| } |
| } |
| } |
| |
| # Define a Rust module of code going into a kernel crate. |
| # |
| # This is analogous to source_set() as used for C++ and assembly code, but for |
| # Rust code. Using kernel_rust_mod() targets is an alternative to structuring |
| # Rust source code in the usual Rust way where each `mod foo;` line in a source |
| # file leads to an adjacent `foo.rs` file or a subdirectory `foo/mod.rs` file. |
| # Both methods can be interspersed, but where the `mod ...;` lines are used in |
| # source code, all the sources they lead to must be included in the same one GN |
| # target's $sources list. The kernel_rust_mod() target acts as a `mod.rs` file |
| # containing nothing but `mod ...;` lines for each file in $sources. |
| # |
| # Parameters |
| # |
| # * output_name |
| # - Optional: Name of the Rust module, as if `mod $output_name` appeared in |
| # the parent mod / crate source file. Usually this should not be used and |
| # instead the target name should just be chosen to match instead. |
| # - Type: string |
| # - Default: "$target_name" |
| # |
| # * source_root |
| # - Optional: Root `.rs` source file of the module. Whatever the name |
| # of this source file, $target_name will be the Rust "path" component. |
| # - Type: path |
| # - Default: "$output_name.rs" |
| # |
| # * sources |
| # - Required: This should list `.rs` files reached from $source_root |
| # via `mod` lines, except for those included in other kernel_rust_mod() |
| # targets. (No file should appear in more than one $sources list; nor |
| # in both any $sources list and any $source_root, even a default one.) |
| # It can be empty if $source_root is the only file, but must be present. |
| # - Type: list(path) |
| # |
| # * inputs |
| # - Optional: This should list any files the Rust compiler will read when |
| # compiling $source_root and $sources that aren't `.rs` files in $sources, |
| # via `include!` or the like. |
| # - Type: list(path) |
| # |
| # * data_deps |
| # - Optional: Extra files or ZBI items to go with the kernel. |
| # This works the same as in source_set() et al. |
| # - Type: list(label) |
| # |
| # * deps |
| # - Optional: Bring more things into the eventual Rust crate to satisfy |
| # references made by Rust code in $source_root or $sources. These can be: |
| # * other kernel_rust_mod("foo") targets, which will appear under this |
| # in Rust paths "...::$target_name::foo" as if `mod foo;` appeared in |
| # $source_root and there was a `foo.rs` file in $sources. |
| # * rustc_library() or kernel_rust_crate() targets for crates referred |
| # to in $source_root or $sources code. |
| # * source_set(), static_library(), etc. targets of non-Rust code |
| # * group() targets leading to any and all of these |
| # - Type: list(label) |
| # |
| # * public_deps |
| # - Optional: Same as $deps, but other kernel_rust_mod("foo") targets |
| # reached are as if `pub mod foo;` rather than `mod foo;`. **NOTE:** |
| # This does not behave like $public_deps in source_set() and other targets, |
| # e.g. to propagate $public_configs. It's exactly like $deps in every way |
| # except for `pub mod` declarations instead of `mod` declarations in Rust. |
| # To get the usual $public_deps effects on dependents of this target, |
| # instead use a group() or source_set() target to hold the public_deps |
| # as well as deps on this target. |
| # - Type: list(label) |
| # |
| # * test_deps |
| # - Optional: Dependencies only used in the unit tests within the module. |
| # Note that unlike rustc_library(), none of these dependencies may be |
| # testonly. (See `kernel_test_deps()`.) |
| # - Type: list(label) |
| # - Default: [] |
| # |
| # * metadata, testonly, visibility |
| # - Optional: Usual GN meanings. |
| # |
| template("kernel_rust_mod") { |
| _kernel_rust_mod_impl(target_name) { |
| sources = [] |
| forward_variables_from(invoker, |
| "*", |
| [ |
| "preamble", |
| "upward_metadata", |
| "vars", |
| ]) |
| if (!defined(output_name)) { |
| output_name = target_name |
| } |
| if (defined(invoker.source_root)) { |
| source_root = invoker.source_root |
| assert(get_path_info(source_root, "extension") == "rs", |
| "`source_root` must be a .rs file name") |
| } else { |
| source_root = "$output_name.rs" |
| } |
| |
| sources += [ source_root ] |
| source_root = rebase_path(source_root, "$target_gen_dir/$target_name") |
| preamble = [ |
| "// Textually include the kernel_rust_mod() source_root file.", |
| "include!(\"${source_root}\");", |
| ] |
| |
| upward_metadata = true |
| } |
| } |
| |
| # Define a Rust crate-level attribute that can go into a kernel crate. |
| # |
| # This defines a target whose effect is to insert `#![$target_name]` at the top |
| # of the kernel crate's root source file, when this target is in the $deps |
| # graph of a kernel_executable() target. |
| # |
| # The recommended practice is to put this into deps of the kernel_rust_mod() |
| # target whose sources necessitate using this crate-wide attribute. |
| # |
| # Parameters |
| # |
| # * output_name |
| # - Optional: The line "#![$output_name]" is what will be emitted. |
| # Usually this is not used, and the target is just named appropriately. |
| # But this can be set to a more complex string like "attr = val" too. |
| # - Type: string |
| # - Default: "$target_name" |
| # |
| # * deps, metadata, testonly, visibility |
| # - Optional: Usual GN meanings. |
| # |
| template("kernel_rust_mod_attr") { |
| group(target_name) { |
| forward_variables_from(invoker, |
| [ |
| "deps", |
| "visibility", |
| "testonly", |
| ]) |
| if (defined(invoker.output_name)) { |
| _attr = invoker.output_name |
| } else { |
| _attr = target_name |
| } |
| _label = get_label_info(":$target_name", "label_with_toolchain") |
| metadata = { |
| kernel_rust_mod_preamble = [] |
| if (defined(invoker.metadata)) { |
| forward_variables_from(invoker.metadata, "*") |
| } |
| kernel_rust_mod_preamble += [ "#![$_attr] $_label" ] |
| } |
| } |
| } |
| |
| # Roll up kernel_rust_mod() targets into a $crate_root source file. |
| # |
| # This defines a generated_file() target emitting a `.rs` source file to be |
| # used as the $crate_root in a Rust crate target. Its get_target_outputs() |
| # will yield a single `.rs` source file to use as $crate_root. The target must |
| # also go into the direct $deps list of the crate target to propagate necessary |
| # $public_configs and $public_deps. |
| # |
| # Parameters |
| # |
| # * deps |
| # - Required: Should reach kernel_rust_mod() and kernel_rust_mod_attr() |
| # targets; can be the sole path to anything else to link into the crate. |
| # - Type: list(label) |
| # |
| # * public_configs, public_deps, metadata, testonly, visibility |
| # - Optional: Usual GN meanings. |
| # |
| template("kernel_rust_mod_crate_root") { |
| source_root_file = "$target_gen_dir/$target_name.rs" |
| |
| # GN's support for Rust targets only handles other Rust crates (ultimately, |
| # rust_library() or rust_proc_macro() targets) in "direct" deps. That is, |
| # either literal `deps` list in target itself, or their equivalent via |
| # `public_deps` propagation. These get tool() substitutions in {{externs}} |
| # of `--extern name=...` switches for each of those; the Rust compiler in |
| # turn makes those available for `name::` use, and indeed warns if there is |
| # none. Those, and all transitive Rust crate deps---only via "direct" deps |
| # at each Rust crate target, get tool() substitutions in {{rustdeps}} of |
| # `-Ldependency=...` switches so that the Rust compiler can find all the |
| # dependencies of those `--extern` crates. |
| # |
| # The kernel executable() has no Rust crates as direct deps. Everything |
| # comes only via indirect deps on group() and source_set() targets. So GN |
| # puts nothing into {{externs}} or {{rustdeps}}. The code here must make up |
| # some equivalent plumbing for the kernel's dependencies on Rust crates. |
| |
| targets = { |
| main = target_name |
| label = get_label_info(":$main", "label_with_toolchain") |
| prefix = "_kernel_rust_mod_crate_root.$target_name" |
| mod = "$prefix.mod" |
| preamble = "$prefix.preamble" |
| postamble = "$prefix.postamble" |
| config = "$prefix.config" |
| deps = "$prefix.deps" |
| common = { |
| visibility = [ ":$main" ] |
| forward_variables_from(invoker, [ "testonly" ]) |
| } |
| } |
| |
| # The .rs file generated by _kernel_rust_mod_impl() will be `include!`d into |
| # the crate root. The deps ensure all the non-Rust code goes into the link. |
| # What's not handled is any Rust crates used by the kernel's Rust sources, |
| # i.e. rust_library() or rust_proc_macro() targets that appear in the deps |
| # graph. There are a few ways that a Rust crate can be referenced: |
| # |
| # 1. Kernel Rust sources use `crate_name::...` items in some fashion. |
| # * The defining crate should appear in $deps of the kernel_rust_mod() |
| # that lists the `.rs` source file where it's used. |
| # |
| # 2. A crate referred to via #1 has another crate in its $deps list. |
| # |
| # 3. A kernel_rust_crate() target is in the $deps graph. |
| # * This is used when the crate defines `extern "C"` symbols that are |
| # used by non-Rust code. |
| # * The source_set() containing the non-Rust source that refers to such a |
| # symbol should have the kernel_rust_crate() target in its $deps. |
| # * The _kernel_rust_mod_impl() target effectively transforms this into a |
| # case of #1 via `use crate_name as _;` in a source file. |
| |
| gen_rsp_files = [ |
| { |
| # For #1, --extern switches are needed for each rust_library() or |
| # rust_proc_macro() that appears in the transitive deps graph across |
| # kernel_rust_mod() and non-Rust targets. |
| key = "kernel_rust_externs" |
| |
| # This excludes any that are only indirect deps via another Rust crate. |
| barrier = [ "rust_barrier" ] |
| }, |
| { |
| # For #2, -Ldependency=... switches are needed for each rust_library() or |
| # rust_proc_macro() that appears in the whole transitive deps graph. |
| key = "rust_aux_searchdir" |
| barrier = [] |
| }, |
| ] |
| |
| test_deps = [] |
| if (defined(invoker.test_deps)) { |
| test_deps_target = "kernel_rust_mod.${target_name}.test_deps" |
| test_deps += [ ":$test_deps_target" ] |
| |
| kernel_test_deps(test_deps_target) { |
| visibility = [ ":*" ] |
| public_deps = invoker.test_deps |
| } |
| } |
| |
| gen_deps = test_deps |
| gen_inputs = [] |
| foreach(gen, gen_rsp_files) { |
| gen.target = "${targets.main}.${gen.key}.rsp" |
| gen.label = ":${gen.target}" |
| generated_file(gen.target) { |
| visibility = [ ":*" ] |
| forward_variables_from(invoker, [ "testonly" ]) |
| outputs = [ "$target_gen_dir/$target_name" ] |
| output_conversion = "list lines" |
| walk_keys = gen.barrier + [ "rust_mod_preamble_barrier" ] |
| data_keys = [ gen.key ] |
| deps = invoker.deps |
| metadata = { |
| # No further walks will look through this to find the real deps. |
| rust_barrier = [] |
| rust_mod_barrier = [] |
| rust_mod_preamble_barrier = [] |
| } |
| } |
| gen_deps += [ gen.label ] |
| gen_inputs += get_target_outputs(gen.label) |
| } |
| |
| # The config() adds in the switches that enable what _kernel_rust_mod_impl() |
| # generates to work. |
| config(targets.config) { |
| visibility = [ ":${targets.main}" ] |
| rustflags = [] |
| inputs = gen_inputs + [ source_root_file ] |
| foreach(file, gen_inputs) { |
| rustflags += [ "@" + rebase_path(file, root_build_dir) ] |
| } |
| if (rust_rbe_enable) { |
| rustflags += [ "--remote-inputs=" + |
| string_join(",", rebase_path(inputs, root_build_dir)) ] |
| } |
| } |
| |
| # The crate_root file gets preamble lines collected from metadata. |
| generated_file(targets.main) { |
| forward_variables_from(invoker, |
| [ |
| "metadata", |
| "public_configs", |
| "public_deps", |
| "visibility", |
| "testonly", |
| ]) |
| outputs = [ source_root_file ] |
| output_conversion = "list lines" |
| walk_keys = [ "rust_barrier" ] |
| data_keys = [ "kernel_rust_mod_preamble" ] |
| |
| # The order matters here. Separate += lines is the surest way to avoid any |
| # label sorting by `gn format`. First, the preamble. |
| deps = [ ":${targets.preamble}" ] |
| |
| # Next, the real deps, via a group() that prevents the other metadata walks |
| # from reaching those deps too early. This finds kernel_rust_mod_attr()s. |
| deps += [ ":${targets.deps}" ] |
| |
| # Finally, the postamble. |
| deps += [ ":${targets.postamble}" ] |
| |
| # The crate target needs the switches collected into the config(). |
| if (!defined(public_configs)) { |
| public_configs = [] |
| } |
| public_configs += [ ":${targets.config}" ] |
| |
| # The config() inputs are generated by the $gen_deps, so these need to be |
| # propagated as "direct" deps of the crate target using the config(). |
| if (!defined(public_deps)) { |
| public_deps = [] |
| } |
| public_deps += gen_deps |
| |
| # Likewise for the source_root file. |
| public_deps += [ ":${targets.mod}" ] |
| } |
| |
| # The _kernel_rust_mod_impl() target here rolls up all the Rust source files |
| # for the kernel crate itself. kernel_rust_mod() targets in the deps graph |
| # contribute `mod ...;` lines to define Rust modules for the kernel crate. |
| # Submodules have already been rolled up by the most-direct kernel_rust_mod() |
| # targets; the ones collected here are the top-level modules of the crate. |
| # |
| # kernel_rust_crate() targets instead contribute `use ... as _;` lines here |
| # to tell Rust to link that crate in despite no other apparent reason. |
| _kernel_rust_mod_impl(targets.mod) { |
| forward_variables_from(invoker, |
| [ |
| "visibility", |
| "testonly", |
| ]) |
| |
| # This will roll up all the "top-level" kernel_rust_mod() targets as |
| # submodules of the `_imports` module within the `kernel` crate. All those |
| # top-level modules are reexported as `$crate::<name>`. |
| output_name = "crate" |
| sources = [] |
| deps = invoker.deps |
| |
| preamble = [ |
| "// Top-level collection for kernel_rust_mod_crate_root() target:", |
| get_label_info(":${targets.main}", "label_with_toolchain"), |
| ] |
| upward_metadata = false |
| } |
| |
| mod_outputs = get_target_outputs(":${targets.mod}") |
| mod_file_relpath = rebase_path(mod_outputs[0], target_gen_dir) |
| |
| group(targets.preamble) { |
| forward_variables_from(targets.common, "*") |
| metadata = { |
| kernel_rust_mod_preamble = [ |
| targets.label, |
| "// This is a generated file. DO NOT EDIT!", |
| "", |
| ] |
| } |
| } |
| |
| group(targets.deps) { |
| forward_variables_from(targets.common, "*") |
| deps = invoker.deps |
| metadata = { |
| # The walks above and inside _kernel_rust_mod_impl() will stop here so |
| # they don't reach the deps before they should be reached. |
| rust_mod_preamble_barrier = [] |
| } |
| } |
| |
| group(targets.postamble) { |
| forward_variables_from(targets.common, "*") |
| metadata = { |
| kernel_rust_mod_preamble = [ |
| "", |
| "// Textually include the generated rust_kernel_mod() imports.", |
| "include!(\"$mod_file_relpath\");", |
| "", |
| "// Make each top-level rust_kernel_mod() visible as crate::mod_name.", |
| "#[allow(unused_imports)]", |
| "pub(crate) use _imports::*;", |
| ] |
| } |
| } |
| } |