blob: a710036ae63011f5fb3ceceb3d0a623de90721f5 [file] [log] [blame]
# 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" ])
}
}