blob: e6bed4497b62d4a66b242694e6c075350dbecd7d [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.
import("//build/compiled_action.gni")
import("//build/config/clang/clang.gni")
import("//build/cpp/hlcpp_visibility.gni")
import("//build/fidl/toolchain.gni")
import("//build/sdk/sdk_atom_alias.gni")
# Define the include patterns for various binding flavors.
# Includes will be of the form <my/library/{output-stem}.h>
_hlcpp_output_stem = "cpp/fidl"
template("_fidl_cpp_codegen_impl") {
generation_target_name = "${target_name}_generate"
root = "${invoker.fidl_gen_dir}/${invoker.bindings_flavor}"
generation_visibility = [
":$target_name",
"${invoker.fidlgen_tool}:*",
]
if (defined(invoker.additional_visibility)) {
generation_visibility += invoker.additional_visibility
}
compiled_action(generation_target_name) {
# supply defaults for various options
forward_variables_from(invoker,
[
"applicable_licenses",
"testonly",
"fidl_ir_json",
"fidl_ir_target",
])
visibility = generation_visibility
tool = invoker.fidlgen_tool
mnemonic = "FIDLGEN"
inputs = [
fidl_ir_json,
"${clang_prefix}/clang-format",
]
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" ]
}
}
args = [
"--json",
rebase_path(fidl_ir_json, root_build_dir),
"--clang-format-path",
"${rebased_clang_prefix}/clang-format",
"--root",
rebase_path(root, root_build_dir),
]
if (defined(invoker.experiments)) {
foreach(experiment, invoker.experiments) {
args += [
"--experiment",
experiment,
]
}
}
deps = [ fidl_ir_target ]
metadata = {
generated_sources = rebase_path(outputs, root_build_dir)
}
}
}
# Generates C++ code for a given FIDL library: new C++ bindings,
# or high-level C++ bindings.
#
# 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.
#
# dep_suffix (optional)
# What to add to the end of FIDL dependency labels to get the label for bindings.
# 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.
#
# 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") {
if (is_fidl_toolchain) {
_fidl_cpp_codegen_impl(target_name) {
forward_variables_from(invoker, "*")
}
} else {
# Code generation only happens under the FIDL toolchain.
not_needed([ "target_name" ])
not_needed(invoker, "*")
}
}
template("_fidl_cpp_library_impl") {
forward_variables_from(invoker,
[
"bindings_flavor",
"fidl_target",
"fidl_gen_dir",
])
assert(defined(bindings_flavor))
assert(defined(fidl_target))
assert(defined(fidl_gen_dir))
# Instances, such as tests, that do not have their own `fidl_cpp_codegen()`
# target need to override the generation target base name to be match the
# codegen target being used. The name should correspond to `bindings_flavor`.
if (defined(invoker.codegen_target_base_name)) {
codegen_target_base_name = invoker.codegen_target_base_name
} else {
codegen_target_base_name = target_name
}
generation_target_name = "${codegen_target_base_name}_generate"
root = "$fidl_gen_dir/${bindings_flavor}"
not_needed([ "root" ])
if (defined(invoker.generated_headers)) {
config_target_name = "${target_name}__config"
config(config_target_name) {
include_dirs = [ root ]
}
}
source_set(target_name) {
forward_variables_from(invoker,
[
"applicable_licenses",
"defines",
"testonly",
"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" ]
}
}
# The generated bindings code is part of the SDK surface. Our customers compile
# the generated code with potentially stricter warnings, so we need to ensure
# that the code works in their diverse environments.
cflags_cc = [ "-Wshadow" ]
configs += [ "//build/config:sdk_extra_warnings" ]
if (defined(invoker.additional_configs)) {
configs += invoker.additional_configs
}
if (defined(invoker.generated_headers)) {
# Let dependencies use `#include "$file_stem.h"`.
public_configs = [ ":$config_target_name" ]
}
public_deps = [
":$generation_target_name($fidl_toolchain)",
":${fidl_target}($fidl_toolchain)",
]
# Map FIDL library dependencies to generated library dependencies
# of the same type (identified by `bindings_flavor` or `dep_suffix`).
dep_suffix = "_${bindings_flavor}"
if (defined(invoker.dep_suffix)) {
dep_suffix = invoker.dep_suffix
}
not_needed([ "dep_suffix" ])
if (defined(invoker.public_deps)) {
if (invoker.public_deps != []) {
foreach(dep, invoker.public_deps) {
label = get_label_info(dep, "label_no_toolchain")
if (label != "//zircon/vdso/zx:zx") {
public_deps += [ "${label}${dep_suffix}" ]
}
}
}
}
if (defined(invoker.additional_public_deps)) {
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
#
# library_name (required)
# Name of the FIDL library.
#
# fidl_target (required)
# Name of the GN target corresponding to the 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.
#
# 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.
#
# header_only (optional)
# If true, the generated library only has a header.
#
# source_only (optional)
# If true, the generated library only has a source file.
#
# additional_configs (optional)
# A list of config labels to add to the source_set for generated C++ bindings.
#
template("fidl_cpp_library") {
if (!is_fidl_toolchain) {
if (invoker.library_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, "*")
}
not_needed(invoker, [ "library_name" ])
}
} else {
# No-op under FIDL toolchain
not_needed([ "target_name" ])
not_needed(invoker, "*")
}
}
# Generates various C++ FIDL bindings: New C++ bindings and HLCPP.
#
# Parameters
#
# * library_name
# - Required: The name of the FIDL library.
# - Type: string
#
# * fidl_target
# - Required: The name of the associated fidl() target.
# - Type: string
#
# * fidl_ir_json
# - Required: The path to the associated FIDL IR JSON file.
# - Type: path
#
# * fidl_ir_target
# - Required: The label of the target that generates the FIDL IR JSON file.
# - Type: label
#
# * declare_sdk_atom_aliases
# - Required: Whether to declare aliases to "${target_name}_sdk".
# - Type: boolean
#
# * enable_hlcpp
# - Required: See //build/fidl/fidl.gni for a description.
# - Type: boolean
#
# * enable_cpp
# - Optional: See //build/fidl/fidl.gni for a description.
# - Type: boolean
#
# * additional_cpp_configs
# - Optional: See //build/fidl/fidl.gni for a description.
# - Type: list of labels
#
# * testonly, visibility, public_deps
# - Optional: Usual GN meanings.
# Note:
# - Under the FIDL toolchain, we would create action targets that
# generate the C++ bindings.
# - Under other toolchains, we would create library targets that
# reference the generated code.
#
template("fidl_cpp_family") {
assert(defined(invoker.library_name),
"fidl_cpp_family(\"$target_name\") must define `library_name`")
assert(defined(invoker.fidl_target),
"fidl_cpp_family(\"$target_name\") must define `fidl_target`")
assert(defined(invoker.fidl_ir_json),
"fidl_cpp_family(\"$target_name\") must define `fidl_ir_json`")
assert(defined(invoker.fidl_ir_target),
"fidl_cpp_family(\"$target_name\") must define `fidl_ir_target`")
assert(
defined(invoker.declare_sdk_atom_aliases),
"fidl_cpp_family(\"$target_name\") must define `declare_sdk_atom_aliases`")
assert(defined(invoker.enable_hlcpp),
"fidl_cpp_family(\"$target_name\") must define `enable_hlcpp`")
forward_variables_from(invoker,
[
"library_name",
"enable_hlcpp",
])
enable_cpp = !defined(invoker.enable_cpp) || invoker.enable_cpp
if (enable_hlcpp) {
#
# HLCPP Bindings
#
# Define HLCPP target.
library_name_slashes = string_replace(library_name, ".", "/")
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",
]
}
_hlcpp_target = "${target_name}_hlcpp"
# Note that this is not the `_hlcpp_target` as the template adds a suffix.
fidl_cpp_codegen(_hlcpp_target) {
forward_variables_from(invoker,
[
"applicable_licenses",
"testonly",
"fidl_gen_dir",
"fidl_ir_json",
"fidl_ir_target",
])
forward_variables_from(hlcpp_options, "*")
fidlgen_tool = "//tools/fidl/fidlgen_hlcpp"
}
fidl_cpp_library(_hlcpp_target) {
forward_variables_from(invoker,
[
"applicable_licenses",
"testonly",
"visibility",
"public_deps",
"fidl_target",
"fidl_gen_dir",
])
forward_variables_from(hlcpp_options, "*")
if (is_fuchsia) {
additional_public_deps = [ "//sdk/lib/fidl/hlcpp" ]
} else {
additional_public_deps = [ "//sdk/lib/fidl/hlcpp:hlcpp_base" ]
}
if (!defined(visibility) && !(defined(testonly) && testonly)) {
visibility = hlcpp_visibility
}
}
}
if (invoker.declare_sdk_atom_aliases) {
# Set up an HLCPP SDK item for this library
# Instead of depending on the generated bindings, set up a dependency on
# the original library.
sdk_target_name = "${target_name}_sdk"
sdk_atom_alias("${target_name}_hlcpp_sdk") {
forward_variables_from(invoker, [ "testonly" ])
atom = ":$sdk_target_name($fidl_toolchain)"
}
}
#
# New C++ bindings
#
if (enable_cpp) {
_cpp_target = "${target_name}_cpp"
fidl_cpp_library(_cpp_target) {
forward_variables_from(invoker,
[
"applicable_licenses",
"testonly",
"visibility",
"public_configs",
"public_deps",
"fidl_target",
"fidl_gen_dir",
])
bindings_flavor = "cpp"
generated_headers = [
"fidl/$library_name/cpp/common_types.h",
"fidl/$library_name/cpp/common_types_format.h",
"fidl/$library_name/cpp/markers.h",
"fidl/$library_name/cpp/wire_types.h",
"fidl/$library_name/cpp/natural_types.h",
"fidl/$library_name/cpp/wire.h",
"fidl/$library_name/cpp/natural_ostream.h",
"fidl/$library_name/cpp/type_conversions.h",
"fidl/$library_name/cpp/fidl.h",
]
generated_sources = [
"fidl/$library_name/cpp/common_types.cc",
"fidl/$library_name/cpp/natural_ostream.cc",
"fidl/$library_name/cpp/natural_types.cc",
"fidl/$library_name/cpp/type_conversions.cc",
"fidl/$library_name/cpp/wire_types.cc",
]
additional_public_deps = [
"//sdk/lib/fidl/cpp:cpp_base",
"//sdk/lib/fidl/cpp:natural_ostream",
"//sdk/lib/fidl/cpp/wire",
"//sdk/lib/fit",
]
if (is_fuchsia) {
generated_headers += [
"fidl/$library_name/cpp/wire_messaging.h",
"fidl/$library_name/cpp/natural_messaging.h",
]
generated_sources += [
"fidl/$library_name/cpp/natural_messaging.cc",
"fidl/$library_name/cpp/wire_messaging.cc",
]
additional_public_deps += [
"//sdk/lib/fidl",
"//sdk/lib/fidl/cpp",
]
}
if (defined(invoker.contains_drivers) && invoker.contains_drivers) {
generated_headers += [ "fidl/$library_name/cpp/driver/wire.h" ]
additional_public_deps += [
"//sdk/lib/fidl_driver",
"//sdk/lib/fidl_driver:fidl_driver_natural",
]
if (is_fuchsia) {
generated_headers += [
"fidl/$library_name/cpp/driver/wire_messaging.h",
"fidl/$library_name/cpp/driver/natural_messaging.h",
]
generated_sources += [
"fidl/$library_name/cpp/driver/natural_messaging.cc",
"fidl/$library_name/cpp/driver/wire_messaging.cc",
]
}
}
if (defined(invoker.additional_cpp_configs)) {
additional_configs = invoker.additional_cpp_configs
}
}
# Testing target
fidl_cpp_library("${_cpp_target}_testing") {
testonly = true
forward_variables_from(invoker,
[
"applicable_licenses",
"visibility",
"public_configs",
"fidl_target",
"fidl_gen_dir",
"public_deps",
])
bindings_flavor = "cpp"
codegen_target_base_name = _cpp_target
dep_suffix = "_cpp_testing"
generated_headers = [
"fidl/$library_name/cpp/test_base.h",
"fidl/$library_name/cpp/wire_test_base.h",
]
additional_public_deps = [ ":${_cpp_target}" ]
if (defined(invoker.additional_cpp_configs)) {
additional_configs = invoker.additional_cpp_configs
}
}
# SDK atoms for the new c++ bindings core and testing.
if (invoker.declare_sdk_atom_aliases) {
sdk_atom_alias("${_cpp_target}_sdk") {
forward_variables_from(invoker, [ "testonly" ])
atom = ":$sdk_target_name($fidl_toolchain)"
}
sdk_atom_alias("${_cpp_target}_testing_sdk") {
forward_variables_from(invoker, [ "testonly" ])
atom = ":$sdk_target_name($fidl_toolchain)"
}
}
}
if (enable_hlcpp) {
fidl_cpp_library("${target_name}_cpp_hlcpp_conversion") {
forward_variables_from(invoker,
[
"applicable_licenses",
"testonly",
"visibility",
"public_configs",
"fidl_target",
"fidl_gen_dir",
"public_deps",
])
bindings_flavor = "cpp"
codegen_target_base_name = _cpp_target
dep_suffix = "_cpp_hlcpp_conversion"
generated_headers = [ "fidl/$library_name/cpp/hlcpp_conversion.h" ]
additional_public_deps = [
":${_cpp_target}",
":${_hlcpp_target}",
"//sdk/lib/fidl/cpp:hlcpp_conversion",
]
}
if (invoker.declare_sdk_atom_aliases) {
sdk_atom_alias("${target_name}_cpp_hlcpp_conversion_sdk") {
forward_variables_from(invoker, [ "testonly" ])
atom = ":$sdk_target_name($fidl_toolchain)"
}
}
}
# Note that this is not the `_cpp_target` as the template adds a suffix.
fidl_cpp_codegen(_cpp_target) {
forward_variables_from(invoker,
[
"applicable_licenses",
"testonly",
"fidl_gen_dir",
"fidl_ir_json",
"fidl_ir_target",
])
bindings_flavor = "cpp"
fidlgen_tool = "//tools/fidl/fidlgen_cpp"
generated_headers = [
"fidl/$library_name/cpp/common_types_format.h",
"fidl/$library_name/cpp/common_types.h",
"fidl/$library_name/cpp/driver/natural_messaging.h",
"fidl/$library_name/cpp/driver/wire_messaging.h",
"fidl/$library_name/cpp/driver/wire.h",
"fidl/$library_name/cpp/fidl.h",
"fidl/$library_name/cpp/hlcpp_conversion.h",
"fidl/$library_name/cpp/markers.h",
"fidl/$library_name/cpp/natural_messaging.h",
"fidl/$library_name/cpp/natural_ostream.h",
"fidl/$library_name/cpp/natural_types.h",
"fidl/$library_name/cpp/test_base.h",
"fidl/$library_name/cpp/type_conversions.h",
"fidl/$library_name/cpp/wire_messaging.h",
"fidl/$library_name/cpp/wire_test_base.h",
"fidl/$library_name/cpp/wire_types.h",
"fidl/$library_name/cpp/wire.h",
]
generated_sources = [
"fidl/$library_name/cpp/common_types.cc",
"fidl/$library_name/cpp/driver/natural_messaging.cc",
"fidl/$library_name/cpp/driver/wire_messaging.cc",
"fidl/$library_name/cpp/natural_messaging.cc",
"fidl/$library_name/cpp/natural_ostream.cc",
"fidl/$library_name/cpp/natural_types.cc",
"fidl/$library_name/cpp/type_conversions.cc",
"fidl/$library_name/cpp/wire_messaging.cc",
"fidl/$library_name/cpp/wire_types.cc",
]
additional_visibility = [
":${target_name}",
":${target_name}_testing",
":${target_name}_hlcpp_conversion",
]
}
}