| # 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/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> |
| _llcpp_output_stem = "llcpp/fidl" |
| _hlcpp_output_stem = "cpp/fidl" |
| _natural_types_output_stem = "cpp/natural_types" |
| _unified_cpp_output_stem = "cpp/fidl_v2" |
| _libfuzzer_output_stem = "cpp/libfuzzer" |
| |
| template("_fidl_cpp_codegen_impl") { |
| generation_target_name = "${target_name}_generate" |
| fidl_target_name = invoker.fidl_target_name |
| |
| fidl_target_gen_dir = |
| get_label_info(":${fidl_target_name}($fidl_toolchain)", "target_gen_dir") |
| |
| library_name = invoker.library_name |
| include_base = |
| "$fidl_target_gen_dir/$fidl_target_name/${invoker.bindings_flavor}" |
| include_stem = |
| string_replace(library_name, ".", "/") + "/" + invoker.output_stem |
| file_stem = "$include_base/$include_stem" |
| |
| json_representation = "$fidl_target_gen_dir/$fidl_target_name.fidl.json" |
| |
| generation_visibility = [ |
| ":$target_name", |
| "${invoker.fidlgen_tool}:*", |
| ] |
| if (defined(invoker.fuzzers)) { |
| foreach(fuzzer, invoker.fuzzers) { |
| assert( |
| defined(fuzzer.protocol), |
| "FIDL protocol fuzzers must set protocol: the fully-qualified name of the protocol to be fuzzed.") |
| |
| protocol_suffix = "_" + string_replace(fuzzer.protocol, ".", "_") |
| if (defined(fuzzer.methods)) { |
| foreach(method, fuzzer.methods) { |
| protocol_suffix = "${protocol_suffix}_${method}" |
| } |
| } |
| generation_visibility += [ ":${target_name}${protocol_suffix}" ] |
| } |
| } |
| |
| compiled_action(generation_target_name) { |
| # supply defaults for various options |
| forward_variables_from(invoker, |
| [ |
| "testonly", |
| "experimental_split_generation_domain_objects", |
| "generates_test_base_header", |
| "generates_decoder_encoders", |
| "additional_includes_natural_types", |
| "additional_includes_hlcpp_bindings", |
| "additional_includes_wire_bindings", |
| ]) |
| if (!defined(experimental_split_generation_domain_objects)) { |
| experimental_split_generation_domain_objects = false |
| } |
| if (!defined(generates_decoder_encoders)) { |
| generates_decoder_encoders = false |
| } |
| if (!defined(additional_includes_natural_types)) { |
| additional_includes_natural_types = false |
| } |
| if (!defined(additional_includes_hlcpp_bindings)) { |
| additional_includes_hlcpp_bindings = false |
| } |
| if (!defined(additional_includes_wire_bindings)) { |
| additional_includes_wire_bindings = false |
| } |
| |
| visibility = generation_visibility |
| |
| tool = invoker.fidlgen_tool |
| |
| inputs = [ json_representation ] |
| |
| args = [ |
| "--json", |
| rebase_path(json_representation, root_build_dir), |
| "--include-base", |
| rebase_path(include_base, root_build_dir), |
| "--include-stem", |
| invoker.output_stem, |
| "--clang-format-path", |
| rebase_path("${clang_prefix}/clang-format", "", root_build_dir), |
| ] |
| |
| header_file = "${file_stem}.h" |
| source_file = "${file_stem}.cc" |
| outputs = [ |
| header_file, |
| source_file, |
| ] |
| args += [ |
| "--header", |
| rebase_path(header_file, root_build_dir), |
| "--source", |
| rebase_path(source_file, root_build_dir), |
| ] |
| |
| if (generates_test_base_header) { |
| test_base_file = "${file_stem}_test_base.h" |
| outputs += [ test_base_file ] |
| args += [ |
| "--test-base", |
| rebase_path(test_base_file, root_build_dir), |
| ] |
| } |
| if (generates_decoder_encoders) { |
| decoder_encoder_header_file = "${file_stem}_decode_encode.h" |
| decoder_encoder_source_file = "${file_stem}_decode_encode.cc" |
| outputs += [ |
| decoder_encoder_header_file, |
| decoder_encoder_source_file, |
| ] |
| args += [ |
| "--decoder-encoder-header", |
| rebase_path(decoder_encoder_header_file, root_build_dir), |
| "--decoder-encoder-source", |
| rebase_path(decoder_encoder_source_file, root_build_dir), |
| ] |
| } |
| |
| # test base header is omitted when only generating domain objects. |
| if (experimental_split_generation_domain_objects) { |
| assert(!generates_test_base_header) |
| args += [ "--experimental-split-generation-domain-objects" ] |
| } |
| |
| if (additional_includes_natural_types) { |
| args += [ |
| "--natural-domain-objects-include-stem", |
| _natural_types_output_stem, |
| ] |
| } |
| if (additional_includes_hlcpp_bindings) { |
| args += [ |
| "--hlcpp-bindings-include-stem", |
| _hlcpp_output_stem, |
| ] |
| } |
| if (additional_includes_wire_bindings) { |
| args += [ |
| "--wire-bindings-include-stem", |
| _llcpp_output_stem, |
| ] |
| } |
| |
| deps = [ ":$fidl_target_name($fidl_toolchain)" ] |
| |
| metadata = { |
| generated_sources = rebase_path(outputs, root_build_dir) |
| } |
| } |
| } |
| |
| # Generates C++ code for a given FIDL library: low-level C++ bindings, |
| # high-level C++ bindings, natural domain objects, unified C++ bindings, |
| # or the fuzzer header library. |
| # |
| # Parameters |
| # |
| # library_name (required) |
| # Name of the FIDL library. |
| # |
| # fidl_target_name (required) |
| # Name of the GN target corresponding to the FIDL library. |
| # |
| # output_stem (required) |
| # A suffix to name generated files, after library path, and before |
| # any file extension. |
| # |
| # fidlgen_tool (required) |
| # The code generation tool to use, as an absolute GN label. |
| # |
| # bindings_flavor (required) |
| # Identifies which kind of library (hlcpp, llcpp, ...). |
| # This should be the same suffix as the one used when instantiating |
| # the fidl_cpp_library template. |
| # |
| # fuzzers (optional) |
| # A list of { protocol = ..., methods = ... } scopes declaring which |
| # methods will be fuzzed by a fuzzer. |
| # |
| # experimental_split_generation_domain_objects (optional) |
| # If true, only generate the domain objects (structs, tables, ...) |
| # for this library. |
| # |
| # generates_test_base_header (required) |
| # Specifies if the tool will generate a test base header. |
| # If experimental_split_generation_domain_objects is true, then this |
| # parameter must be false, as only protocols require a test base. |
| # This is required to support hermetic actions. |
| # |
| # generates_decoder_encoders (optional) |
| # Specifies if the tool will generate fuzzer decoder encoder |
| # wrapper implementations. |
| # |
| # additional_includes_natural_types (optional) |
| # If true, the generated code depends on the natural domain object types |
| # in addition to its own headers. Informs the tool the natural types |
| # include stem. |
| # |
| # additional_includes_hlcpp_bindings (optional) |
| # If true, the generated code depends on the HLCPP bindings in addition to |
| # its own headers. Informs the tool the HLCPP bindings include stem. |
| # |
| # additional_includes_wire_bindings (optional) |
| # If true, the generated code depends on the wire bindings in addition to |
| # its own headers. Informs the tool the wire bindings include stem. |
| # |
| template("fidl_cpp_codegen") { |
| if (current_toolchain == 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") { |
| config_target_name = "${target_name}__config" |
| |
| generation_target_name = |
| "${invoker.fidl_target_name}_${invoker.bindings_flavor}_generate" |
| |
| library_name = invoker.library_name |
| fidl_target_name = invoker.fidl_target_name |
| fidl_target_gen_dir = |
| get_label_info(":$target_name($fidl_toolchain)", "target_gen_dir") |
| |
| include_base = |
| "$fidl_target_gen_dir/$fidl_target_name/${invoker.bindings_flavor}" |
| include_stem = |
| string_replace(library_name, ".", "/") + "/" + invoker.output_stem |
| file_stem = "$include_base/$include_stem" |
| |
| config(config_target_name) { |
| include_dirs = [ include_base ] |
| } |
| |
| source_set(target_name) { |
| forward_variables_from(invoker, |
| [ |
| "defines", |
| "testonly", |
| "visibility", |
| ]) |
| |
| if (defined(invoker.header_only) && invoker.header_only) { |
| sources = [ "$file_stem.h" ] |
| } else if (defined(invoker.source_only) && invoker.source_only) { |
| sources = [ "$file_stem.cc" ] |
| } else { |
| sources = [ |
| "$file_stem.cc", |
| "$file_stem.h", |
| ] |
| } |
| |
| # Note: decoder/encoders are completely enabled/disabled by `invoker.includes_decoder_encoders`. |
| # Its sources and headers are do not honour `invoker.(header|source)_only`. |
| if (defined(invoker.includes_decoder_encoders) && |
| invoker.includes_decoder_encoders) { |
| sources += [ |
| "${file_stem}_decode_encode.cc", |
| "${file_stem}_decode_encode.h", |
| ] |
| } |
| |
| # TODO(fxbug.dev/56257): Remove this line when `-Wextra-semi` is on |
| # for all of Fuchsia by default. |
| cflags_cc = [ "-Wextra-semi" ] |
| |
| # TODO(fxbug.dev/69585): We suppress deprecated raw channel usage |
| # in LLCPP generated code itself. Delete this line after everything |
| # migrates to typed channels. |
| configs += [ "//build/cpp:fidl-llcpp-deprecated-raw-channels-reserved-for-llcpp-generated-code-only" ] |
| |
| # Let dependencies use `#include "$file_stem.h"`. |
| public_configs = [ ":$config_target_name" ] |
| |
| public_deps = [ |
| ":$generation_target_name($fidl_toolchain)", |
| ":${invoker.fidl_target_name}($fidl_toolchain)", |
| ":${invoker.fidl_target_name}_tables", |
| ] |
| |
| # Map FIDL library dependencies to generated library dependencies |
| # of the same type (identified by bindings_flavor). |
| not_needed(invoker, [ "bindings_flavor" ]) |
| if (defined(invoker.public_deps)) { |
| foreach(dep, invoker.public_deps) { |
| label = get_label_info(dep, "label_no_toolchain") |
| public_deps += [ "${label}_${invoker.bindings_flavor}" ] |
| } |
| } |
| |
| public_deps += invoker.additional_public_deps |
| |
| if (defined(invoker.deps)) { |
| public_deps += invoker.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_name (required) |
| # Name of the GN target corresponding to the FIDL library. |
| # |
| # bindings_flavor (required) |
| # Identifies which kind of library (hlcpp, llcpp, ...). |
| # This should be the same suffix as the one used when instantiating |
| # the fidl_cpp_codegen template. |
| # |
| # 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. |
| # |
| template("fidl_cpp_library") { |
| if (current_toolchain != fidl_toolchain) { |
| _fidl_cpp_library_impl(target_name) { |
| forward_variables_from(invoker, "*") |
| } |
| } else { |
| # No-op under FIDL toolchain |
| not_needed([ "target_name" ]) |
| not_needed(invoker, "*") |
| } |
| } |
| |
| template("_fidl_cpp_fuzzer") { |
| fuzzer = invoker.fuzzer |
| |
| assert( |
| defined(fuzzer.protocol), |
| "FIDL protocol fuzzers must set protocol: the fully-qualified name of the protocol to be fuzzed.") |
| |
| protocol_suffix = "_" + string_replace(fuzzer.protocol, ".", "_") |
| |
| library_defines = [ "PROTOCOL${protocol_suffix}" ] |
| if (defined(invoker.defines)) { |
| library_defines += invoker.defines |
| } |
| if (defined(fuzzer.methods)) { |
| foreach(method, fuzzer.methods) { |
| library_defines += [ "METHOD_${method}" ] |
| } |
| } else { |
| library_defines += [ "ALL_METHODS" ] |
| } |
| |
| bindings_flavor = "libfuzzer" |
| fuzzer_lib_name = "${target_name}_${bindings_flavor}${protocol_suffix}" |
| |
| fidl_cpp_library(fuzzer_lib_name) { |
| defines = library_defines |
| library_name = invoker.library_name |
| forward_variables_from(invoker, |
| [ |
| "testonly", |
| "visibility", |
| "public_deps", |
| "fidl_target_name", |
| ]) |
| output_stem = _libfuzzer_output_stem |
| bindings_flavor = bindings_flavor |
| additional_public_deps = [ ":${invoker.fidl_target_name}_libfuzzer" ] |
| source_only = true |
| } |
| } |
| |
| # Generates various C++ FIDL bindings: HLCPP, LLCPP, Unified C++, and fuzzers. |
| # |
| # 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") { |
| # Allow users to override the library name by specifying a |
| # "name" variable in the `fidl("my_lib")` template invocation. |
| # Otherwise, default to the `target_name` of the FIDL library. |
| # |
| # Note that library names will have implication on the generated |
| # include paths, hence should be separate from `target_name`. |
| library_name = target_name |
| if (defined(invoker.name)) { |
| library_name = invoker.name |
| } |
| |
| # `target_name` becomes clobbered in template invocation scopes; |
| # back it up here. |
| fidl_target_name = target_name |
| |
| # `sources` is only required to invoke `fidlc`; |
| # the bindings code generation consumes the JSON IR instead. |
| not_needed(invoker, [ "sources" ]) |
| |
| # Determine the C++ bindings dependencies based on Fuchsia/host. |
| # Additionally, an empty llcpp_public_deps indicates that the LLCPP |
| # bindings for this library is not needed. |
| llcpp_public_deps = [] |
| if (is_fuchsia) { |
| not_needed(invoker, [ "host_llcpp" ]) |
| hlcpp_public_deps = [ "//sdk/lib/fidl/cpp" ] |
| llcpp_public_deps = [ |
| "//sdk/lib/fit", |
| "//zircon/public/lib/fidl", |
| "//zircon/public/lib/fidl-llcpp", |
| ] |
| } else { |
| # On host. |
| hlcpp_public_deps = [ "//sdk/lib/fidl/cpp:cpp_base" ] |
| if (defined(invoker.host_llcpp) && invoker.host_llcpp) { |
| llcpp_public_deps = [ |
| "//sdk/lib/fit", |
| "//zircon/public/lib/fidl-llcpp", |
| ] |
| } else { |
| # Do not generate LLCPP if not requested. |
| llcpp_public_deps = [] |
| } |
| } |
| |
| common_options = { |
| fidl_target_name = fidl_target_name |
| library_name = library_name |
| forward_variables_from(invoker, [ "testonly" ]) |
| } |
| |
| natural_types_public_deps = [ "//sdk/lib/fidl/cpp:cpp_base" ] |
| |
| # |
| # HLCPP Bindings |
| # |
| |
| # Define C++ natural types target. |
| # They are generated using the HLCPP backend. |
| fidl_cpp_codegen("${target_name}_cpp_natural_types") { |
| forward_variables_from(common_options, "*") |
| output_stem = _natural_types_output_stem |
| bindings_flavor = "cpp_natural_types" |
| fidlgen_tool = "//tools/fidl/fidlgen_hlcpp" |
| experimental_split_generation_domain_objects = true |
| generates_test_base_header = false |
| generates_decoder_encoders = false |
| } |
| fidl_cpp_library("${target_name}_cpp_natural_types") { |
| forward_variables_from(invoker, |
| [ |
| "public_deps", |
| "visibility", |
| ]) |
| forward_variables_from(common_options, "*") |
| output_stem = _natural_types_output_stem |
| bindings_flavor = "cpp_natural_types" |
| additional_public_deps = natural_types_public_deps |
| } |
| |
| # Define HLCPP target. |
| # TODO(fxbug.dev/64093): Currently the HLCPP generated code embeds the |
| # natural types inline. Change this to depend on the dedicated natural types |
| # target when the unified bindings and HLCPP are used in one program. |
| fidl_cpp_codegen("${target_name}_hlcpp") { |
| forward_variables_from(common_options, "*") |
| output_stem = _hlcpp_output_stem |
| bindings_flavor = "hlcpp" |
| fidlgen_tool = "//tools/fidl/fidlgen_hlcpp" |
| generates_test_base_header = true |
| generates_decoder_encoders = false |
| } |
| fidl_cpp_library("${target_name}_hlcpp") { |
| forward_variables_from(invoker, |
| [ |
| "public_deps", |
| "visibility", |
| ]) |
| forward_variables_from(common_options, "*") |
| output_stem = _hlcpp_output_stem |
| bindings_flavor = "hlcpp" |
| additional_public_deps = hlcpp_public_deps |
| } |
| if (current_toolchain != fidl_toolchain) { |
| # Set up an alias from ":my_lib_hlcpp" to ":my_lib" |
| group(target_name) { |
| forward_variables_from(invoker, [ "testonly" ]) |
| public_deps = [ ":${target_name}_hlcpp" ] |
| } |
| |
| # Set up an SDK item for this library |
| if (defined(invoker.sdk_category) && invoker.sdk_category != "excluded") { |
| # Instead of depending on the generated bindings, set up a dependency on |
| # the original library. |
| sdk_target_name = "${target_name}_sdk" |
| sdk_atom_alias(sdk_target_name) { |
| atom = ":$sdk_target_name($fidl_toolchain)" |
| } |
| } |
| } |
| |
| # |
| # LLCPP Bindings |
| # |
| |
| # Define LLCPP target, if requested. |
| if (llcpp_public_deps != []) { |
| fidl_cpp_codegen("${target_name}_llcpp") { |
| forward_variables_from(common_options, "*") |
| output_stem = _llcpp_output_stem |
| bindings_flavor = "llcpp" |
| fidlgen_tool = "//tools/fidl/fidlgen_llcpp" |
| generates_test_base_header = true |
| } |
| fidl_cpp_library("${target_name}_llcpp") { |
| forward_variables_from(invoker, |
| [ |
| "public_deps", |
| "visibility", |
| ]) |
| forward_variables_from(common_options, "*") |
| output_stem = _llcpp_output_stem |
| bindings_flavor = "llcpp" |
| additional_public_deps = llcpp_public_deps |
| } |
| } |
| |
| # Unified C++ Bindings |
| # |
| # The unified bindings imports the natural types from HLCPP and the |
| # entire LLCPP bindings, and extends it with messaging APIs that works |
| # with the natural types. |
| # |
| |
| # Define the unified bindings target. |
| # Note that we also check llcpp_public_deps here, because we would not |
| # generate the corresponding LLCPP bindings if it was empty. |
| if (llcpp_public_deps != []) { |
| fidl_cpp_codegen("${target_name}_cpp") { |
| forward_variables_from(common_options, "*") |
| output_stem = _unified_cpp_output_stem |
| bindings_flavor = "cpp" |
| fidlgen_tool = "//tools/fidl/fidlgen_cpp" |
| generates_test_base_header = false |
| additional_includes_natural_types = true |
| additional_includes_wire_bindings = true |
| } |
| fidl_cpp_library("${target_name}_cpp") { |
| forward_variables_from(invoker, |
| [ |
| "public_deps", |
| "visibility", |
| ]) |
| forward_variables_from(common_options, "*") |
| output_stem = _unified_cpp_output_stem |
| bindings_flavor = "cpp" |
| additional_public_deps = [ |
| ":${fidl_target_name}_cpp_natural_types", |
| ":${fidl_target_name}_llcpp", |
| ] |
| } |
| } |
| |
| # |
| # Fuzzers (also dependent on HLCPP and LLCPP) |
| # |
| |
| # Define fuzzer targets. |
| fidl_cpp_codegen("${target_name}_libfuzzer") { |
| testonly = true |
| forward_variables_from(invoker, [ "fuzzers" ]) |
| forward_variables_from(common_options, "*") |
| output_stem = _libfuzzer_output_stem |
| bindings_flavor = "libfuzzer" |
| fidlgen_tool = "//tools/fidl/fidlgen_libfuzzer" |
| generates_test_base_header = false |
| |
| # Note: Must have matching `includes_decoder_encoders` in `fidl_cpp_library` below. |
| generates_decoder_encoders = true |
| additional_includes_hlcpp_bindings = true |
| additional_includes_wire_bindings = true |
| } |
| |
| # Define fuzzer header library. |
| fidl_cpp_library("${target_name}_libfuzzer") { |
| testonly = true |
| forward_variables_from(invoker, |
| [ |
| "public_deps", |
| "visibility", |
| ]) |
| forward_variables_from(common_options, "*") |
| output_stem = _libfuzzer_output_stem |
| bindings_flavor = "libfuzzer" |
| additional_public_deps = [ |
| "//sdk/lib/fidl/cpp/fuzzing", |
| "//zircon/system/ulib/async-default", |
| "//zircon/system/ulib/async-loop:async-loop-cpp", |
| "//zircon/system/ulib/async-loop:async-loop-default", |
| |
| # The generated headers `#include` the hlcpp and llcpp bindings headers |
| # generated by the clauses above, so the generated target needs |
| # that bindings library target in its public_deps. |
| ":${fidl_target_name}_hlcpp", |
| ":${fidl_target_name}_llcpp", |
| ] |
| |
| # Note: `.../libfuzzer.cc` is linked with different build-time parameters below in loop |
| # over `invoker.fuzzers`. The library itself contains headers only. |
| header_only = true |
| |
| # Note: Must have matching `generates_decoder_encoders` in `fidl_cpp_codegen` above. |
| # Note: decoder/encoders are completely enabled/disabled by `invoker.includes_decoder_encoders`. |
| # Its sources and headers do not honour `invoker.(header|source)_only`. |
| includes_decoder_encoders = true |
| } |
| |
| # Define fuzzer implementation libraries (one per fuzzed protocol). |
| # The source file is the same - different macro definitions |
| # are used to customize the fuzzing configuration. |
| if (defined(invoker.fuzzers)) { |
| foreach(fuzzer, invoker.fuzzers) { |
| _fidl_cpp_fuzzer(target_name) { |
| testonly = true |
| forward_variables_from(invoker, "*") |
| fidl_target_name = fidl_target_name |
| } |
| } |
| } |
| } |