| # Copyright 2018 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. |
| |
| # First, import the gni files that define the names of the other toolchains, and |
| # the "is_<foo>_toolchain" variables that are used throughout this file. |
| import("//build/fidl/toolchain.gni") |
| import("//build/go/toolchain.gni") |
| import("//build/testing/host_test_data.gni") |
| |
| # NOTE: The imports of this gni file are dependent on the language used, as |
| # there is no need to import the templates for the other languages when |
| # processing this file in a given language's toolchain. They are done only |
| # within the scopes as needed below. |
| |
| # Declares a FIDL library. |
| # |
| # Supported backends: rust, hlcpp, llcpp, banjo_{c,cpp,rust}, bindlib, |
| # go, and zither. |
| # |
| # Subtargets: |
| # * `${target_name}`: available only in the FIDL toolchain |
| # * `${target_name}_sdk`: available only in the FIDL toolchain |
| # * `${target_name}_go`: available only in the Go toolchain |
| # * `${target_name}_${backend_name}`: available in every toolchain but Go |
| # * `${target_name}_host_test_data`: available on host toolchain |
| # |
| # Parameters |
| # |
| # sources (required) |
| # List of paths to library source files. |
| # |
| # name (optional) |
| # Name of the library. |
| # Defaults to `target_name`. |
| # |
| # sdk_category (optional) |
| # Publication level of the library in SDKs. |
| # See //build/sdk/sdk_atom.gni. |
| # |
| # sdk_area (optional) |
| # [string] The API area responsible for maintaining this FIDL library. |
| # See //build/sdk/sdk_atom.gni. |
| # |
| # api (optional) |
| # Path to the file representing the API of this library. |
| # This file is used to ensure modifications to the library's API are |
| # explicitly acknowledged. It is mandatory for stable = true. |
| # Defaults to `${target_name}.api. |
| # |
| # excluded_checks (optional) |
| # A list of fidl-lint check IDs to ignore (by passing the command line flag |
| # "-e some-check-id" for each value). |
| # |
| # experimental_checks (optional) |
| # A list of fidl-lint check IDs to include (by passing the command line flag |
| # "-x some-check-id" for each value). |
| # |
| # ${backend_name} (optional) |
| # A scope giving private, backend-specific parameters. |
| # Currently supported backends: zither |
| # |
| # fuzzers (optional) |
| # Protocol/methods for which to generate LibFuzzer fuzz targets. Example: |
| # [ |
| # { |
| # # Required: |
| # protocol = "fully.qualified.FIDLProtocolName" |
| # # Optional. Default: All methods in protocol. |
| # methods = [ "MethodName1", "MethodName2", ... ] |
| # }, |
| # ... |
| # ] |
| # |
| # golden_fuzzer (optional) |
| # Boolean flag to generate a LibFuzzer fuzz target for all protocols, used |
| # to ensure fuzzers for golden libraries compile successfully. |
| # |
| # versioned (optional) |
| # A string of the form PLATFORM or PLATFORM:VERSION. If provided, fidlc |
| # will validate that the library is versioned under PLATFORM and added at |
| # VERSION (if provided). |
| # fidlc determines the library's actual platform from FIDL files as follows: |
| # * If there are no @available attributes, the platform is "unversioned". |
| # * The platform can be explicit with @available(platform="PLATFORM"). |
| # * Otherwise, the platform is the first component of the library name. |
| # Defaults are: |
| # * When testonly is true and SDK category is not specified: "unversioned" |
| # * When the library name starts with "fuchsia.": |
| # * If `stable` is true: "fuchsia" |
| # * For unstable libraries in an SDK category: "fuchsia:HEAD" |
| # * Otherwise: "fuchsia:HEAD" (with a few temporary exceptions) |
| # * Otherwise: "unversioned" |
| # |
| # available (optional) |
| # A list of strings of the form PLATFORM:VERSION. This is needed when using |
| # @available annotations for platforms other than "fuchsia". For more |
| # information, look for --available in `fidlc --help`. |
| # Warning: All dependencies must specify the same value for `available`, |
| # otherwise bindings will be inconsistent. Since this is easy to misuse, |
| # this parameter is only allowed on testonly libraries. |
| # |
| # experimental_flags (optional) |
| # A list of experimental fidlc features to enable. |
| # |
| # goldens_dir (optional, default "//sdk/history") |
| # The directory containing golden files for this FIDL API, per API level. |
| # Should not contain a trailing slash. This is only used if the API is |
| # publishable in an SDK. |
| # |
| # non_fidl_deps (optional) |
| # A list of non-FIDL dependency targets, i.e. targets that don't contribute |
| # FIDL artifacts, but should be built before this target regardless. This is |
| # typically used when `sources` contains files generated by another target. |
| # |
| # contains_drivers (optional, boolean, default false) |
| # Indicates if any of the FIDL files contain the driver transport or |
| # references to the driver transport. |
| # |
| # enable_cpp (optional flag, default to true) |
| # Set to false to disable the new C++ bindings for this library |
| # |
| # enable_rust (optional flag, default to true) |
| # Set to false to disable Rust bindings for this library |
| # |
| # enable_rust_drivers (optional flag, default to false) |
| # Set to true to enable experimental rust driver transport support |
| # |
| # enable_bindlib (optional flag, default to true) |
| # Set to false to disable bindlib bindings for this library |
| # |
| # enable_hlcpp (optional flag, default to false) |
| # Set to true to enable legacy HLCPP bindings for this library |
| # |
| # enable_banjo (optional flag, default to false) |
| # Set to true to enable Banjo bindings for this library. |
| # |
| # enable_rust_next (optional flag, default to false) |
| # Set to true to enable next-generation Rust bindings for this library |
| # |
| # enable_zither (optional flag, default to false) |
| # Set to true to enable Zither bindings for this library. |
| # See //zircon/tools/zither/README.md for details. |
| # |
| # stable (optional flag) Whether this library is stabilized. When true, |
| # `versioned` defaults to "fuchsia" for "fuchsia.*" library names and an |
| # .api file is generated. When false, the atom is marked as unstable in the |
| # final IDK. Must be specified if and only if `sdk_category` is specified. |
| # May only be false when `sdk_category` is "partner". |
| # |
| # applicable_licenses |
| # public_deps |
| # testonly |
| # visibility |
| # |
| # Metadata |
| # |
| # fidl_ir_info (`${target_name}_host_test_data` only) |
| # Exactly one scope including the name of the library and the source IR JSON |
| # path (relative to root_build_dir). |
| template("fidl") { |
| assert(defined(invoker.sources), "A FIDL library requires some sources.") |
| assert(!defined(invoker.deps), |
| "All FIDL dependencies are inherently " + |
| "public, use 'public_deps' instead of 'deps'.") |
| assert(defined(invoker.sdk_category) == defined(invoker.stable), |
| "`stable` must be specified when specifying `sdk_category`.") |
| assert(!defined(invoker.sdk_category) || invoker.stable == true || |
| invoker.sdk_category == "partner" || |
| # TODO(https://fxbug.dev/333907192): Remove the "internal_only_idk" |
| # exception when fuchsia.boot is promoted. |
| target_name == "fuchsia.boot", |
| "`stable` must be true unless the category is 'partner'.") |
| |
| # Define values that will be used to generate other variables here so that |
| # such use does not count as having used the member of `common_parameters. |
| _fidl_target_name = target_name |
| _fidl_target = ":${_fidl_target_name}($fidl_toolchain)" |
| _fidl_gen_dir = |
| get_label_info(_fidl_target, "target_gen_dir") + "/${_fidl_target_name}" |
| _fidl_ir_target = ":${_fidl_target_name}_compile_fidlc($fidl_toolchain)" |
| |
| common_parameters = { |
| if (defined(invoker.name)) { |
| library_name = invoker.name |
| } else { |
| library_name = target_name |
| } |
| |
| fidl_gen_dir = _fidl_gen_dir |
| |
| # The main FIDL library target on the FIDL toolchain. Every backend must |
| # depend on it. |
| # For historical reasons, the variable name is the FIDL IR target. |
| # TODO(https://fxbug.dev/381123422): Rename it. |
| fidl_ir_target = ":${target_name}($fidl_toolchain)" |
| |
| # The path to the IR JSON. When passed to `fidl_library()`, it specifies the |
| # desired path at which to generate the file. |
| fidl_ir_json = get_label_info(_fidl_ir_target, "target_gen_dir") + |
| "/${target_name}.fidl.json" |
| } |
| |
| # These bindings are enabled by default: |
| enable_bindlib = !defined(invoker.enable_bindlib) || invoker.enable_bindlib |
| enable_cpp = !defined(invoker.enable_cpp) || invoker.enable_cpp |
| enable_rust = !defined(invoker.enable_rust) || invoker.enable_rust |
| enable_fdomain = enable_rust |
| if (defined(invoker.enable_fdomain)) { |
| enable_fdomain = invoker.enable_fdomain |
| } |
| |
| # FDomain bindings are a subtype of rust binding. Trying to build FDomain |
| # bindings without Rust does nothing. |
| assert(!enable_fdomain || enable_rust) |
| |
| # These bindings are not: |
| enable_banjo = defined(invoker.enable_banjo) && invoker.enable_banjo |
| enable_hlcpp = defined(invoker.enable_hlcpp) && invoker.enable_hlcpp |
| enable_rust_next = |
| defined(invoker.enable_rust_next) && invoker.enable_rust_next |
| enable_zither = defined(invoker.enable_zither) && invoker.enable_zither |
| enable_rust_drivers = |
| defined(invoker.enable_rust_drivers) && invoker.enable_rust_drivers |
| |
| not_needed([ |
| "enable_bindlib", |
| "enable_cpp", |
| "enable_rust", |
| "enable_rust_drivers", |
| "enable_rust_next", |
| "enable_banjo", |
| "enable_hlcpp", |
| "enable_zither", |
| ]) |
| |
| # Allow generated targets visibility to their dependant generated targets |
| if (defined(invoker.visibility)) { |
| invoker.visibility += [ ":*" ] |
| } |
| |
| # Use SDK category markers to enable detection of targets that use FIDL |
| # libraries in non-permissible categories. |
| # TODO(https://fxbug.dev/333907192): Remove the "internal_only_idk" exception |
| # when fuchsia.boot is promoted. |
| _not_in_sdk_category = "not-in-idk" |
| if (defined(invoker.sdk_category) && |
| invoker.sdk_category != "internal_only_idk") { |
| if (invoker.stable) { |
| marker_category = invoker.sdk_category |
| not_needed([ "_not_in_sdk_category" ]) |
| } else { |
| # Unstable libraries in the SDK provide no more compatibility guarantee |
| # than libraries not in the SDK. Use the same marker for simplicity. |
| marker_category = _not_in_sdk_category |
| } |
| } else { |
| marker_category = _not_in_sdk_category |
| } |
| |
| # Override the category if the library is in the allowlist for ffx. |
| # Only do this when building Rust bindings, which ffx uses, or the FIDL |
| # library, which is a dependency of those bindings. |
| if ((is_host && enable_rust && toolchain_variant.supports_rust) || |
| is_fidl_toolchain) { |
| import("//src/developer/ffx/build/ffx_subtool_allowlist.gni") |
| label_name = get_label_info(_fidl_target, "label_no_toolchain") |
| is_allowed_for_ffx = ffx_subtool_fidl_allowlist + [ label_name ] - |
| [ label_name ] != ffx_subtool_fidl_allowlist |
| if (is_allowed_for_ffx) { |
| assert( |
| marker_category == _not_in_sdk_category, |
| "Remove `${label_name}` from //src/developer/ffx/build/ffx_subtool_allowlist.gni.") |
| marker_category = "allowed-for-ffx-subtool" |
| } |
| } |
| |
| fidl_only = [ |
| "api", |
| "sdk_area", |
| "available", |
| "excluded_checks", |
| "experimental_checks", |
| "experimental_flags", |
| "goldens_dir", |
| "non_fidl_deps", |
| "versioned", |
| "stable", |
| ] |
| if (is_fidl_toolchain) { |
| # Only import the fidl_library template when in the fidl toolchain |
| import("//build/fidl/fidl_library.gni") |
| fidl_library(target_name) { |
| forward_variables_from(invoker, |
| fidl_only + [ |
| "applicable_licenses", |
| "testonly", |
| "visibility", |
| "public_deps", |
| "sdk_category", |
| "sources", |
| ]) |
| forward_variables_from(common_parameters, "*") |
| |
| if (!defined(invoker.non_fidl_deps)) { |
| non_fidl_deps = [] |
| } |
| non_fidl_deps += [ "//sdk/categories:marker-${marker_category}" ] |
| } |
| |
| # Check that the IR JSON is indeed an output of the purported IR target. |
| fidlc_outputs = |
| get_target_outputs(":${target_name}_compile_fidlc($fidl_toolchain)") |
| assert([ common_parameters.fidl_ir_json ] + fidlc_outputs - fidlc_outputs == |
| []) |
| } else { |
| not_needed(invoker, fidl_only) |
| } |
| |
| # The check here is to prevent builds using different host toolchain bases from causing build |
| # conflicts. |
| # TODO(b/346586023): This is only really used for Fuchsia Controller, which should instead be |
| # packaging this as a Python data resource. |
| if (is_host && current_toolchain == toolchain_variant.base) { |
| fidl_ir_root_target = "${target_name}_ir_root" |
| fidl_ir_root_base = get_label_info(":anything($fidl_toolchain)", |
| "root_gen_dir") + "/ir_root" |
| fidl_library_name = common_parameters.library_name |
| fidl_ir_root_dir = fidl_ir_root_base + "/" + fidl_library_name |
| fidl_ir_root_outfile = "${fidl_ir_root_base}/${fidl_library_name}/${fidl_library_name}.fidl.json" |
| |
| # This is intended as an alternative easily-searchable setup to all_fidl_json.txt |
| # The only caveat is that this will fail if there are FIDL libraries with duplicate names as |
| # dependencies. A future step may be to create this directory structure in a given package's |
| # gen dir rather than the root FIDL gen dir. |
| action(fidl_ir_root_target) { |
| forward_variables_from(invoker, |
| [ |
| "testonly", |
| "visibility", |
| ]) |
| sources = [ common_parameters.fidl_ir_json ] |
| script = "//build/fidl/gen_ir_root_out.py" |
| args = [ |
| "--root-dir", |
| rebase_path(fidl_ir_root_base, root_build_dir), |
| "--ir-path", |
| rebase_path(common_parameters.fidl_ir_json, fidl_ir_root_dir), |
| "--library-name", |
| fidl_library_name, |
| ] |
| outputs = [ fidl_ir_root_outfile ] |
| deps = [ |
| "//sdk/categories:marker-${marker_category}", |
| _fidl_target, |
| ] |
| } |
| |
| # See https://fxrev.dev/931429 for context. |
| host_test_data("${target_name}_host_test_data_") { |
| forward_variables_from(invoker, |
| [ |
| "applicable_licenses", |
| "visibility", |
| ]) |
| sources = [ |
| common_parameters.fidl_ir_json, |
| fidl_ir_root_outfile, |
| ] |
| |
| # Explicitly set `testonly` to false for SDK inclusion. |
| # See https://fxbug.dev/42070088. |
| # host_test_data()'s default for `testonly` is true so we can't simply |
| # forward `invoker.testonly` as that's most likely unset for fidl() |
| # targets. |
| testonly = false |
| if (defined(invoker.testonly)) { |
| testonly = invoker.testonly |
| } |
| |
| deps = [ ":${fidl_ir_root_target}" ] |
| |
| # Override the category if the library is in the allowlist for host tests. |
| # Do not allow the subtool allowlist for host tests. |
| if (marker_category == "allowed-for-ffx-subtool") { |
| marker_category = _not_in_sdk_category |
| } |
| import("//src/testing/end_to_end/host_test_allowlist.gni") |
| label_name = get_label_info(_fidl_target, "label_no_toolchain") |
| is_allowed_for_host_test = host_test_fidl_allowlist + [ label_name ] - |
| [ label_name ] != host_test_fidl_allowlist |
| if (is_allowed_for_host_test) { |
| assert( |
| marker_category == _not_in_sdk_category, |
| "Remove `${label_name}` from //src/testing/end_to_end/host_test_allowlist.gni.") |
| marker_category = "allowed-for-host-test" |
| } |
| deps += [ "//sdk/categories:marker-${marker_category}" ] |
| } |
| |
| group("${target_name}_host_test_data") { |
| forward_variables_from(invoker, [ "testonly" ]) |
| deps = [ ":${target_name}_" ] |
| if (defined(invoker.public_deps)) { |
| foreach(pdep, invoker.public_deps) { |
| label = get_label_info(pdep, "label_no_toolchain") |
| deps += [ "${label}_host_test_data" ] |
| } |
| } |
| |
| metadata = { |
| fidl_ir_info = [ |
| { |
| library_name = fidl_library_name |
| source = rebase_path(fidl_ir_root_outfile, root_build_dir) |
| }, |
| ] |
| } |
| } |
| } |
| |
| if (is_go_toolchain) { |
| # Only import the fidl_go() template when in the Go toolchain. |
| import("//build/go/fidl_go.gni") |
| |
| # Define the Go bindings |
| fidl_go("${target_name}_go") { |
| forward_variables_from(invoker, |
| [ |
| "applicable_licenses", |
| "testonly", |
| "visibility", |
| "public_deps", |
| ]) |
| forward_variables_from(common_parameters, "*") |
| fidl_gen_dir += "/go" |
| } |
| |
| # This template does not accept `deps`, but it will have an indirect |
| # dependency on the SDK category marker via `fidl_ir_target`. |
| |
| not_needed(invoker, |
| [ |
| "contains_drivers", |
| "fuzzers", |
| "golden_fuzzer", |
| "sdk_category", |
| ]) |
| } |
| |
| if (is_fidl_toolchain || toolchain_variant.supports_cpp || |
| toolchain_variant.supports_rust) { |
| # The C, C++, and Rust bindings are compiled in their own toolchain, from |
| # sources generated in the FIDL toolchain, so this section of the template |
| # is processed in the FIDL toolchain as well as the binary toolchain(s). |
| |
| if (enable_cpp || enable_hlcpp) { |
| # Only import fidl_cpp_family() if in a cpp toolchain and cpp bindings are |
| # enabled, as this can be particularly slow to import. |
| import("//build/cpp/fidl_cpp.gni") |
| |
| # Define the cpp bindings. |
| fidl_cpp_family(target_name) { |
| forward_variables_from(invoker, |
| [ |
| "applicable_licenses", |
| "testonly", |
| "visibility", |
| "public_deps", |
| "contains_drivers", |
| "fuzzers", |
| "golden_fuzzer", |
| ]) |
| forward_variables_from(common_parameters, "*") |
| fidl_target = _fidl_target_name |
| enable_hlcpp = enable_hlcpp |
| enable_cpp = enable_cpp |
| |
| # SDK atom aliases are only relevant in the default toolchain when an |
| # the library is in an SDK category. |
| declare_sdk_atom_aliases = current_toolchain == default_toolchain && |
| defined(invoker.sdk_category) |
| |
| # This template does not accept `deps`, but it will have an indirect |
| # dependency on the SDK category marker via `fidl_ir_target`. |
| } |
| } |
| |
| if (enable_rust && (is_fidl_toolchain || toolchain_variant.supports_rust)) { |
| # Only import the fidl_rust() template if in a rust-capable toolchain and |
| # rust bindings are to be defined. |
| import("//build/rust/fidl_rust.gni") |
| |
| # Define the common portion of the rust bindings. |
| fidl_rust("${target_name}_rust_common") { |
| forward_variables_from(invoker, |
| [ |
| "applicable_licenses", |
| "testonly", |
| "visibility", |
| "public_deps", |
| "disable_rustdoc", |
| ]) |
| forward_variables_from(common_parameters, "*") |
| if (!is_host && enable_rust_drivers) { |
| forward_variables_from(invoker, [ "contains_drivers" ]) |
| } |
| deps = [] |
| common = true |
| if (is_host) { |
| deps = [ "//sdk/categories:marker-${marker_category}" ] |
| } |
| fidl_gen_dir += "/rust" |
| } |
| |
| common_crate_name = |
| "fidl_" + string_replace(common_parameters.library_name, ".", "_") + |
| "_common" |
| |
| # Define the standard FIDL Rust bindings. |
| fidl_rust("${target_name}_rust") { |
| forward_variables_from(invoker, |
| [ |
| "applicable_licenses", |
| "testonly", |
| "visibility", |
| "public_deps", |
| "disable_rustdoc", |
| ]) |
| forward_variables_from(common_parameters, "*") |
| if (!is_host && enable_rust_drivers) { |
| forward_variables_from(invoker, [ "contains_drivers" ]) |
| } |
| deps = [ ":${invoker.target_name}_rust_common" ] |
| use_common = common_crate_name |
| deps += [ "//sdk/categories:marker-${marker_category}" ] |
| fidl_gen_dir += "/rust" |
| } |
| |
| if (enable_fdomain) { |
| # Define the FDomain Rust bindings. |
| fidl_rust("${target_name}_fdomain") { |
| forward_variables_from(invoker, |
| [ |
| "applicable_licenses", |
| "testonly", |
| "visibility", |
| "public_deps", |
| "disable_rustdoc", |
| ]) |
| |
| fdomain = true |
| |
| forward_variables_from(common_parameters, "*") |
| deps = [ |
| ":${invoker.target_name}_rust_common", |
| "//sdk/categories:marker-${marker_category}", |
| ] |
| use_common = common_crate_name |
| fidl_gen_dir += "/rust" |
| } |
| } |
| } |
| |
| if (enable_rust_next && |
| (is_fidl_toolchain || toolchain_variant.supports_rust)) { |
| # Only import the fidl_rust_next() template if in a rust-capable toolchain and |
| # rust bindings are to be defined. |
| import("//build/rust/fidl_rust_next.gni") |
| |
| # Define the Rust bindings. |
| fidl_rust_next("${target_name}_rust_next") { |
| forward_variables_from(invoker, |
| [ |
| "applicable_licenses", |
| "testonly", |
| "visibility", |
| "public_deps", |
| "disable_rustdoc", |
| ]) |
| forward_variables_from(common_parameters, "*") |
| deps = [ "//sdk/categories:marker-${marker_category}" ] |
| fidl_gen_dir += "/rust_next" |
| } |
| } else { |
| not_needed(invoker, [ "disable_rustdoc" ]) |
| } |
| |
| if (enable_bindlib) { |
| # Only import the fidl_bind_library() template if bindlib is enabled. |
| import("//build/bind/fidl_bind_library.gni") |
| |
| # Define the bindlib bindings. |
| fidl_bind_library("${target_name}_bindlib") { |
| forward_variables_from(invoker, |
| [ |
| "applicable_licenses", |
| "testonly", |
| "visibility", |
| ]) |
| forward_variables_from(common_parameters, "*") |
| fidl_gen_dir += "/bindlib" |
| |
| # This template does not accept `deps`, but it will have an indirect |
| # dependency on the SDK category marker via `fidl_ir_target`. |
| } |
| } |
| |
| if (enable_banjo) { |
| # Only import fidl_banjo() if banjo is enabled. |
| import("//build/banjo/fidl_banjo.gni") |
| |
| # Define the banjo bindings. |
| fidl_banjo("${target_name}_banjo") { |
| forward_variables_from(invoker, |
| [ |
| "testonly", |
| "visibility", |
| "public_deps", |
| ]) |
| forward_variables_from(common_parameters, "*") |
| fidl_gen_dir += "/banjo" |
| |
| # This template does not accept `deps`, but it will have an indirect |
| # dependency on the SDK category marker via `fidl_ir_target`. |
| } |
| } |
| |
| if (enable_zither) { |
| # Only import zither_library() if zither is enabled. |
| import("//zircon/tools/zither/zither_library.gni") |
| |
| # Define the zither bindings. |
| zither_library("${target_name}_zither") { |
| forward_variables_from(invoker, |
| [ |
| "testonly", |
| "visibility", |
| "sources", |
| ]) |
| forward_variables_from(common_parameters, "*") |
| if (defined(invoker.zither)) { |
| forward_variables_from(invoker.zither, "*") |
| } |
| fidl_gen_dir += "/zither" |
| |
| # This template does not accept `deps`, but it will have an indirect |
| # dependency on the SDK category marker via `fidl_ir_target`. |
| } |
| } else { |
| not_needed(invoker, [ "sources" ]) |
| } |
| } else { |
| if (!is_fidl_toolchain) { |
| not_needed(invoker, [ "sources" ]) |
| } |
| not_needed(invoker, [ "disable_rustdoc" ]) |
| } |
| |
| # Handle the case where only sub-targets that do not support `deps` are |
| # defined. |
| if (!(is_fidl_toolchain || |
| (is_host && current_toolchain == toolchain_variant.base) || |
| (enable_rust && toolchain_variant.supports_rust))) { |
| not_needed([ "marker_category" ]) |
| } |
| } |