blob: e76e2418846bf14c6b7ad20b8016d1fe4eb215d7 [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}_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 the target's 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 publication categories of
# "partner" or "public".
# 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. Validates that the
# library is versioned under PLATFORM and added at VERSION (if provided).
# The library's actual platform is determined 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 to "fuchsia" when the library name starts with "fuchsia." and
# sdk_category is "cts", "partner_internal", "partner", or "public".
# Defaults to "unversioned" for testonly libraries. Otherwise, no default.
# TODO(https://fxbug.dev/325669391): Expand enforcement by ensuring that
# there is always a default value.
#
# 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_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_zither (optional flag, default to false)
# Set to true to enable Zither bindings for this library.
# See //zircon/tools/zither/README.md for details.
#
# 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'.")
common_parameters = {
library_name = target_name
if (defined(invoker.name)) {
library_name = invoker.name
}
fidl_target = target_name
fidl_gen_dir = get_label_info(":$fidl_target($fidl_toolchain)",
"target_gen_dir") + "/$fidl_target"
# The FIDL IR target, to be forwarded to each backend as a dependency.
fidl_ir_target = ":${target_name}_compile_fidlc($fidl_toolchain)"
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
# These bindings are not:
enable_banjo = defined(invoker.enable_banjo) && invoker.enable_banjo
enable_hlcpp = defined(invoker.enable_hlcpp) && invoker.enable_hlcpp
enable_zither = defined(invoker.enable_zither) && invoker.enable_zither
not_needed([
"enable_bindlib",
"enable_cpp",
"enable_rust",
"enable_banjo",
"enable_hlcpp",
"enable_zither",
])
# Allow generated targets visibility to their dependant generated targets
if (defined(invoker.visibility)) {
invoker.visibility += [ ":*" ]
}
fidl_only = [
"api",
"sdk_area",
"available",
"excluded_checks",
"experimental_checks",
"experimental_flags",
"goldens_dir",
"non_fidl_deps",
"versioned",
]
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,
[
"library_name",
"fidl_ir_json",
])
}
# Check that the IR JSON is indeed an output of the purported IR target.
fidlc_outputs = get_target_outputs(common_parameters.fidl_ir_target)
assert([ common_parameters.fidl_ir_json ] + fidlc_outputs - fidlc_outputs ==
[])
} else {
not_needed(invoker, fidl_only)
}
if (is_host) {
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 = [ ":${common_parameters.fidl_target}($fidl_toolchain)" ]
}
# Use SDK category markers to enable detection of host targets that use FIDL
# libraries in nonpermissible categories.
marker_category = "unknown"
if (defined(invoker.sdk_category)) {
marker_category = invoker.sdk_category
}
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.
# 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
}
# It's only necessary to depend on fidl_ir_target got get the FIDL IR json
# file, but without depending on fidl_target, there is no entry in
# all_fidl_json.txt, which at the moment is the main source for finding
# the list of current FIDL IR json files.
# TODO(b/295190178): append all_fidl_json.txt with inclusion of
# fidl_ir_target target.
deps = [
":${common_parameters.fidl_target}($fidl_toolchain)",
":${fidl_ir_root_target}",
]
# Add SDK category markers as FIDL-IR host data is used for host tests
# that use Fuchsia Controller.
# Check for allowed marker before adding category.
import("//src/testing/end_to_end/host_test_allowlist.gni")
label_name = get_label_info(":${common_parameters.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) {
marker_category = "allowed-for-host-test"
}
deps += [ "//sdk: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)
},
]
}
}
}
not_needed(invoker, [ "sources" ])
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_target" ])
fidl_gen_dir += "/go"
}
not_needed(invoker,
[
"sdk_category",
"sdk_area",
"sources",
])
}
non_go_only = [
"contains_drivers",
"fuzzers",
"golden_fuzzer",
]
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,
non_go_only + [
"applicable_licenses",
"testonly",
"visibility",
"public_deps",
"sdk_category",
])
forward_variables_from(common_parameters, "*")
enable_hlcpp = enable_hlcpp
enable_cpp = enable_cpp
}
} else {
not_needed([ "non_go_only" ])
}
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 Rust bindings.
fidl_rust("${target_name}_rust") {
forward_variables_from(invoker,
[
"applicable_licenses",
"testonly",
"visibility",
"public_deps",
"disable_rustdoc",
])
forward_variables_from(common_parameters, "*", [ "fidl_target" ])
deps = []
if (is_host) {
# Add SDK category markers as Rust is used for ffx host tools.
# Check for allowed marker before adding category.
import("//src/developer/ffx/build/ffx_subtool_allowlist.gni")
label_name = get_label_info(":${common_parameters.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) {
marker_category = "allowed-for-ffx-subtool"
}
deps += [ "//sdk:marker-${marker_category}" ]
}
fidl_gen_dir += "/rust"
}
} 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_target" ])
fidl_gen_dir += "/bindlib"
}
}
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"
}
}
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"
}
} else {
not_needed(invoker, [ "sources" ])
}
} else {
not_needed(invoker,
non_go_only + [
"sources",
"disable_rustdoc",
])
}
}