# 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("gn_configs.gni")
import("gn_sdk_configs.gni")
# Defines a base fidl library with no bindings.
#
# FIDL library dependencies under `public_deps` will manifest as corresponding
# library target dependencies.
#
# Parameters
#
# library_name (required)
# Name of the FIDL library.
#
# sources (required)
# List of fidl files to include in the library.
#
# json_representation (required)
# filename to use for the json representation of the library
#
template("fidl_base_library") {
forward_variables_from(invoker,
[
"library_name",
"sources",
"json_representation",
])
_response_file = "${target_gen_dir}/${target_name}.rsp"
action("${target_name}_response_file") {
script = gn_sdk_root + "/gen_fidl_response_file.py"
forward_variables_from(invoker,
[
"deps",
"public_deps",
"testonly",
])
_libraries_file = "$target_gen_dir/${invoker.target_name}.fidl_libraries"
outputs = [
_response_file,
_libraries_file,
]
args = [
"--out-response-file",
rebase_path(_response_file, root_build_dir),
"--out-libraries",
rebase_path(_libraries_file, root_build_dir),
"--json",
rebase_path(json_representation, root_build_dir),
"--name",
library_name,
"--sources",
] + rebase_path(sources, root_build_dir)
# Pass the target API level if it has been specified.
assert(fuchsia_target_api_level >= 1)
args += [
"--target-api-level",
"${fuchsia_target_api_level}",
]
if (defined(invoker.experimental_flags)) {
foreach(flag, invoker.experimental_flags) {
args += [
"--experimental",
flag,
]
}
}
deps = []
if (defined(invoker.deps) || defined(invoker.public_deps)) {
merged_deps = []
if (defined(invoker.deps)) {
merged_deps += invoker.deps
}
if (defined(invoker.public_deps)) {
merged_deps += invoker.public_deps
}
dep_libraries = []
foreach(dep, merged_deps) {
gen_dir = get_label_info(dep, "target_gen_dir")
dep_toolchain = get_label_info(dep, "toolchain")
name = get_label_info(dep, "name")
dep_libraries += [ "${gen_dir}/${name}.fidl_libraries" ]
dep_dir =
get_label_info(get_label_info(dep, "label_no_toolchain"), "dir")
deps += [ "${dep_dir}:${name}_response_file($dep_toolchain)" ]
}
inputs = dep_libraries
args += [ "--dep-libraries" ] + rebase_path(dep_libraries, root_build_dir)
}
if (defined(invoker.non_fidl_deps)) {
deps += invoker.non_fidl_deps
}
}
action("${target_name}_ir") {
forward_variables_from(invoker, [ "testonly" ])
visibility = [ ":*" ]
deps = [ ":${invoker.target_name}_response_file" ]
script = gn_sdk_root + "/gn_run_binary.py"
inputs = [
# Depend on the SDK hash, to ensure rebuild if the SDK tools change.
fuchsia_sdk_manifest_file,
_response_file,
]
outputs = [ json_representation ]
rebased_response_file = rebase_path(_response_file, root_build_dir)
args = [
rebase_path("${fuchsia_tool_dir}/fidlc", root_build_dir),
"@${rebased_response_file}",
]
}
}
# Generates C++ code for a given FIDL library
#
# Parameters
#
# fidl_gen_dir (required)
# The directory into which bindings should be generated.
#
# bindings_flavor (required)
# Identifies which kind of bindings (hlcpp, cpp, ...).
# This should be the same flavor as the one used when instantiating
# the fidl_cpp_library template.
#
# generated_sources (optional)
# A list of source files that will be generated for this binding, relative
# to the target-specific generation directory.
#
# generated_headers (optional)
# A list of header files that will be generated for this binding, relative
# to the target-specific generation directory.
#
# fidlgen_tool (required)
# The code generation tool to use, as an absolute GN label.
#
# additional_visibility (optional)
# A list of labels which are allowed to depend on the generated code.
#
template("fidl_cpp_codegen") {
root = "${invoker.fidl_gen_dir}/${invoker.bindings_flavor}"
generation_target_name = "${target_name}_gen"
generation_visibility = [ ":${target_name}" ]
if (defined(invoker.additional_visibility)) {
generation_visibility += invoker.additional_visibility
}
action(generation_target_name) {
visibility = generation_visibility
forward_variables_from(invoker, [ "testonly" ])
deps = [ invoker.fidl_ir_target ]
inputs = [
# Depend on the SDK hash, to ensure rebuild if the SDK tools change.
fuchsia_sdk_manifest_file,
invoker.json_representation,
]
outputs = []
if (defined(invoker.generated_sources)) {
foreach(output, invoker.generated_sources) {
outputs += [ "${root}/${output}" ]
}
}
if (defined(invoker.generated_headers)) {
foreach(output, invoker.generated_headers) {
outputs += [ "${root}/${output}" ]
}
}
script = gn_sdk_root + "/gn_run_binary.py"
args = [
rebase_path(invoker.fidlgen_tool, root_build_dir),
"--json",
rebase_path(invoker.json_representation, root_build_dir),
"--root",
rebase_path(root, root_build_dir),
]
}
}
template("_fidl_cpp_library_impl") {
root = "${invoker.fidl_gen_dir}/${invoker.bindings_flavor}"
generation_target_name = "${target_name}_gen"
if (defined(invoker.generation_target_prefix)) {
generation_target_name = "${invoker.generation_target_prefix}_gen"
}
config_target_name = "${target_name}_config"
config(config_target_name) {
visibility = [ ":${target_name}" ]
include_dirs = [ root ]
}
source_set(target_name) {
forward_variables_from(invoker,
[
"deps",
"public_deps",
"testonly",
"visibility",
])
if (defined(visibility)) {
# Ensure that layers have visibility to each other.
visibility += [ ":*" ]
}
sources = []
public = []
if (defined(invoker.generated_sources)) {
foreach(source, invoker.generated_sources) {
sources += [ "${root}/${source}" ]
}
}
if (defined(invoker.generated_headers)) {
foreach(header, invoker.generated_headers) {
sources += [ "${root}/${header}" ]
public += [ "${root}/${header}" ]
}
}
if (defined(invoker.generated_headers)) {
# Let dependencies use `#include "$file_stem.h"`.
public_configs = [ ":$config_target_name" ]
}
# Metadata to allow us to query all FIDL IR files.
metadata = {
fidl_json = [ rebase_path(invoker.json_representation, root_build_dir) ]
}
if (!defined(deps)) {
deps = []
}
deps += [
":${generation_target_name}",
invoker.fidl_ir_target,
]
if (!defined(public_deps)) {
public_deps = []
}
not_needed(invoker, [ "bindings_flavor" ])
not_needed(invoker, [ "bindings_layer" ])
if (defined(invoker.public_deps)) {
if (invoker.public_deps != []) {
if (defined(invoker.bindings_layer)) {
bindings_layer = invoker.bindings_layer
} else {
bindings_layer = invoker.bindings_flavor
}
foreach(dep, invoker.public_deps) {
label = get_label_info(dep, "label_no_toolchain")
if (get_label_info(label, "name") != "zx") {
public_deps += [ "${label}_${bindings_layer}" ]
} else {
not_needed([ "bindings_layer" ])
}
}
}
}
public_deps += invoker.additional_public_deps
}
}
# Defines a C++ library target (source_set) generated from a FIDL library.
#
# FIDL library dependencies under `public_deps` will manifest as corresponding
# library target dependencies.
#
# Parameters
#
# fidl_gen_dir (required)
# The directory where generated files will be placed.
#
# json_representation (required)
# The file containing the json representation.
#
# fidl_ir_target (required)
# The target for the base fidl library.
#
# bindings_flavor (required)
# Identifies which kind of bindings (hlcpp, cpp, ...).
# This should be the same suffix as the one used when instantiating
# the fidl_cpp_codegen template.
#
# bindings_layer (optional)
# A particular binding may be decomposed into multiple layers. In that case,
# this identifies the particular layer that makes up this library (e.g.
# domain objects layer, messaging layer, ...). When adding dependencies,
# a particular layer for a FIDL library depends on the corresponding
# layers of the dependencies of that FIDL library.
#
# Some examples of valid layers are:
# * cpp_wire: Wire messaging over channel transport
# * cpp_wire_types: Wire domain objects
#
# If missing, defaults to bindings_flavor.
#
# generated_sources (optional)
# A list of source files that will be generated for this binding, relative
# to the target-specific generation directory.
#
# generated_headers (optional)
# A list of header files that will be generated for this binding, relative
# to the target-specific generation directory.
#
# generation_target_prefix (optional)
# Overrides the prefix for the generation target so that it becomes
# `${generation_target_prefix}_gen`.
#
# additional_public_deps (optional)
# A list of targets to be added to public_deps.
#
template("fidl_cpp_library") {
if (invoker.fidl_target_name == "zx") {
# The zx FIDL library isn't generated with C++ fidlgens.
not_needed(invoker, "*")
group(target_name) {
}
} else {
_fidl_cpp_library_impl(target_name) {
forward_variables_from(invoker,
[
"deps",
"public_deps",
"testonly",
"visibility",
"fidl_gen_dir",
"fidl_ir_target",
"json_representation",
"bindings_flavor",
"bindings_layer",
"generated_sources",
"generated_headers",
"generation_target_prefix",
"additional_public_deps",
])
}
}
}
# Define a Fuchsia FIDL library target.
#
# ${namespace}.${library_name} must match the the library name specified in the FIDL
# files.
#
# Parameters
#
# sources
# Required: List of .fidl files.
#
# library_name
# Optional: Name of the library. target_name is used if name
# is not specified explicitly.
#
# namespace
# Optional: Namespace for the library.
#
# deps
# Optional: List of other fidl_library() targets that this
# FIDL library depends on.
#
# non_fidl_deps
# Optional: List of other deps that aren't fidl_library targets.
#
# experimental_flags
# Optional: List of experimental flags to pass to fidlc.
#
template("fidl_library") {
forward_variables_from(invoker, [ "namespace" ])
library_basename = target_name
if (defined(invoker.library_name)) {
library_basename = invoker.library_name
}
if (defined(namespace)) {
library_name = "${namespace}.${library_basename}"
_namespace_path = string_replace(namespace, ".", "/")
_library_name_slashes = "${_namespace_path}/${library_basename}"
} else {
library_name = library_basename
_library_name_slashes = string_replace(library_basename, ".", "/")
}
json_representation = "${target_gen_dir}/${library_name}.fidl.json"
fidl_gen_dir = "${target_gen_dir}/fidl"
fidl_target_name = target_name
fidl_ir_target = ":${target_name}_ir"
fidl_base_library(target_name) {
forward_variables_from(invoker,
[
"sources",
"deps",
"public_deps",
"testonly",
])
}
# HLCPP bindings
hlcpp_options = {
bindings_flavor = "hlcpp"
generated_headers = [
"${_library_name_slashes}/cpp/fidl.h",
"${_library_name_slashes}/cpp/fidl_test_base.h",
]
generated_sources = [
"${_library_name_slashes}/cpp/fidl.cc",
"${_library_name_slashes}/cpp/tables.c",
]
}
fidl_cpp_codegen("${target_name}_hlcpp") {
forward_variables_from(invoker, [ "testonly" ])
forward_variables_from(hlcpp_options, "*")
fidlgen_tool = "${fuchsia_tool_dir}/fidlgen_hlcpp"
}
fidl_cpp_library("${target_name}_hlcpp") {
forward_variables_from(invoker,
[
"deps",
"public_deps",
"testonly",
"visibility",
])
additional_public_deps = [
"${fuchsia_sdk}/pkg/fidl",
"${fuchsia_sdk}/pkg/fidl_cpp",
]
forward_variables_from(hlcpp_options, "*")
}
# Alias the target name to the _hlcpp target. This is for backward
# compatibility with the the old mechanism where the base fidl library
# and the hlcpp bindings were in a single target. Once all uses of
# hlcpp are removed, this alias should be removed and the target that
# is currently named ${target_name}_ir will become ${target_name}
group(target_name) {
forward_variables_from(invoker,
[
"testonly",
"visibility",
])
public_deps = [ ":${invoker.target_name}_hlcpp" ]
}
# These bindings are defined as a set of layers that build upon each other.
# All of the layers are generated in a single fidlgen invocation but are
# exposed as separate source_sets to user code so that it's easy to include
# just the parts of the bindings that you need.
llcpp_layers = [
{
layer = "cpp_common"
headers = [
"fidl/${library_name}/cpp/common_types.h",
"fidl/${library_name}/cpp/markers.h",
]
sources = [ "fidl/${library_name}/cpp/common_types.cc" ]
public_deps = [
"${fuchsia_sdk}/pkg/fidl",
"${fuchsia_sdk}/pkg/fidl_cpp_wire",
"${fuchsia_sdk}/pkg/fit",
]
},
{
layer = "cpp_wire_types"
headers = [ "fidl/${library_name}/cpp/wire_types.h" ]
sources = [ "fidl/${library_name}/cpp/wire_types.cc" ]
layer_deps = [ "cpp_common" ]
},
{
layer = "cpp_wire" # AKA: wire_channel_messaging
headers = [
"fidl/${library_name}/cpp/wire.h",
"fidl/${library_name}/cpp/wire_messaging.h",
]
sources = [ "fidl/${library_name}/cpp/wire_messaging.cc" ]
layer_deps = [ "cpp_wire_types" ]
},
{
layer = "cpp_wire_testing"
headers = [ "fidl/${library_name}/cpp/wire_test_base.h" ]
layer_deps = [ "cpp_wire" ]
testonly = true
},
{
layer = "cpp_natural_types"
headers = [ "fidl/${library_name}/cpp/natural_types.h" ]
sources = [ "fidl/${library_name}/cpp/natural_types.cc" ]
public_deps = [ "${fuchsia_sdk}/pkg/fidl_cpp_base_v2" ]
layer_deps = [ "cpp_common" ]
},
{
layer = "cpp_natural_ostream"
headers = [ "fidl/${library_name}/cpp/natural_ostream.h" ]
sources = [ "fidl/${library_name}/cpp/natural_ostream.cc" ]
public_deps = [ "${fuchsia_sdk}/pkg/fidl_cpp_natural_ostream" ]
layer_deps = [ "cpp_natural_types" ]
},
{
layer = "cpp_type_conversions"
headers = [ "fidl/${library_name}/cpp/type_conversions.h" ]
sources = [ "fidl/${library_name}/cpp/type_conversions.cc" ]
public_deps = [ "${fuchsia_sdk}/pkg/fidl_cpp_v2" ]
layer_deps = [
"cpp_natural_types",
# TODO(fxbug.dev/101525): Replace with "cpp_wire_types".
"cpp_wire",
]
},
{
layer = "cpp" # AKA: unified_channel_messaging
headers = [
"fidl/${library_name}/cpp/fidl.h",
"fidl/${library_name}/cpp/natural_messaging.h",
]
sources = [ "fidl/${library_name}/cpp/natural_messaging.cc" ]
layer_deps = [
"cpp_natural_types",
"cpp_type_conversions",
"cpp_wire",
]
public_deps = [ "${fuchsia_sdk}/pkg/fidl_cpp_v2" ]
},
{
layer = "cpp_testing"
headers = [ "fidl/${library_name}/cpp/test_base.h" ]
layer_deps = [ "cpp" ]
testonly = true
},
{
layer = "cpp_hlcpp_conversion"
headers = [ "fidl/${library_name}/cpp/hlcpp_conversion.h" ]
public_deps = [
":${target_name}_hlcpp",
"${fuchsia_sdk}/pkg/fidl_cpp_hlcpp_conversion",
]
layer_deps = [ "cpp_natural_types" ]
},
]
# Define new C++ binding targets.
layer_target_prefix = target_name + "_"
fidl_cpp_codegen("${target_name}_cpp") {
forward_variables_from(invoker,
[
"testonly",
"fidl_gen_dir",
"fidl_ir_json",
"fidl_ir_target",
])
bindings_flavor = "cpp"
fidlgen_tool = "${fuchsia_tool_dir}/fidlgen_cpp"
generated_headers = []
generated_sources = []
additional_visibility = []
foreach(layer, llcpp_layers) {
additional_visibility += [ ":${layer_target_prefix}${layer.layer}" ]
if (defined(layer.headers)) {
generated_headers += layer.headers
}
if (defined(layer.sources)) {
generated_sources += layer.sources
}
}
}
foreach(layer, llcpp_layers) {
layer_target_name = layer_target_prefix + layer.layer
fidl_cpp_library(layer_target_name) {
forward_variables_from(invoker,
[
"testonly",
"visibility",
"public_configs",
"public_deps",
"fidl_gen_dir",
])
generation_target_prefix = "${invoker.target_name}_cpp"
bindings_flavor = "cpp"
bindings_layer = layer.layer
if (defined(layer.headers)) {
generated_headers = layer.headers
}
if (defined(layer.sources)) {
generated_sources = layer.sources
}
if (defined(layer.testonly)) {
testonly = layer.testonly
}
additional_public_deps = []
if (defined(layer.public_deps)) {
additional_public_deps += layer.public_deps
}
if (defined(layer.layer_deps)) {
foreach(layer_dep, layer.layer_deps) {
additional_public_deps += [ ":${layer_target_prefix}${layer_dep}" ]
}
}
}
}
}