| # Copyright 2026 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. |
| |
| """A cc_library backed by a FIDL library.""" |
| |
| load("@bazel_skylib//lib:paths.bzl", "paths") |
| load("@rules_cc//cc:cc_library.bzl", "cc_library") |
| |
| visibility("private") |
| |
| _FidlCcCodegenInfo = provider( |
| "Carries lists of `File`s generated by the FIDL bindings code generation.", |
| fields = { |
| "headers": "A depset of generated header files.", |
| "sources": "A depset of generated source files.", |
| "testing_headers": "A depset of generated testing header files.", |
| "conversion_headers": "A depset of generated HLCPP conversion header files.", |
| }, |
| ) |
| |
| def _get_deps_with_suffix(deps, dep_suffix): |
| """Converts a list of FIDL library labels to cc_library() labels with a suffix appended. |
| |
| Args: |
| deps: List of `Label`s, each representing a FIDL library target. |
| dep_suffix: String suffix to append to the FIDL library label. |
| |
| Returns: |
| List of `Label`s, where each original FIDL library label is transformed |
| into the corresponding cc_library() label with the suffix appended. |
| """ |
| result = [] |
| for dep in deps: |
| # Skip deps on the "zx" library, for which bindings are not generated |
| # with C++ fidlgens. Normalize the dep when comparing. |
| if Label(dep) == Label("//zircon/vdso/zx"): |
| continue |
| dep_label = _get_name_with_suffix(dep.name, dep_suffix) |
| dep_with_binding = "//%s:%s" % (dep.package, dep_label) |
| result.append(dep_with_binding) |
| return result |
| |
| def _get_fidl_cc_lib_name(fidl_target_name, bindings_flavor): |
| """Returns the cc_library() name for a FIDL library and binding flavor. |
| |
| Args: |
| fidl_target_name: String name of the FIDL library target. |
| bindings_flavor: String indicating the binding flavor (e.g., "cpp"). |
| |
| Returns: |
| String name of the cc_library() target. |
| """ |
| return _get_name_with_suffix(fidl_target_name, bindings_flavor) |
| |
| def _get_name_with_suffix(name, suffix): |
| """Returns a name with a suffix in target name format. |
| |
| Args: |
| name: String name. |
| suffix: String suffix to append to the target name. |
| |
| Returns: |
| String name with the suffix appended. |
| """ |
| return "{name}_{suffix}".format(name = name, suffix = suffix) |
| |
| def _get_root_path(bindings_flavor): |
| """Returns the root path for the generated FIDL bindings files. |
| |
| Args: |
| bindings_flavor: String indicating the binding flavor (e.g., "cpp"). |
| |
| Returns: |
| String root path for the generated FIDL bindings files. |
| """ |
| return "bindings/" + bindings_flavor |
| |
| def fidl_cpp_family( |
| *, |
| name, |
| fidl_library_name, |
| fidl_ir_json, |
| deps, |
| contains_drivers, |
| enable_cpp, |
| enable_hlcpp, |
| hlcpp_lib_deps, |
| define_idk_atom_aliases, |
| testonly, |
| visibility): |
| """Generates instances of `cc_library()` providing the generated C++ bindings for a given FIDL library. |
| |
| Args: |
| name: String base name of the `cc_library()` targets. |
| fidl_library_name: String name of the FIDL library for which bindings are generated. |
| fidl_ir_json: `Label` pointing to a single file containing the FIDL IR |
| representation of the `fidl_library_name` library. |
| deps: List of `Label`s for FIDL libraries that the `fidl_library_name` library depends on. |
| contains_drivers: Boolean indicating whether the `fidl_library_name` |
| library supports drivers. |
| enable_cpp: Boolean indicating whether to generate C++ bindings. |
| enable_hlcpp: Boolean indicating whether to generate HLCPP bindings. |
| testonly: Usual meaning. |
| visibility: Usual meaning. |
| """ |
| if not enable_cpp and not enable_hlcpp: |
| fail("At least one of `enable_cpp` or `enable_hlcpp` must be true.") |
| |
| hlcpp_bindings_flavor = "hlcpp" |
| hlcpp_lib_name = _get_fidl_cc_lib_name(name, hlcpp_bindings_flavor) |
| |
| if enable_cpp: |
| cpp_bindings_flavor = "cpp" |
| cpp_lib_name = _get_fidl_cc_lib_name(name, cpp_bindings_flavor) |
| |
| cpp_codegen_name = "%s_generated_fidl_cc_bindings" % cpp_lib_name |
| cpp_sources_name = "%s_sources" % cpp_lib_name |
| cpp_testing_headers_name = "%s_testing_headers" % cpp_lib_name |
| |
| generated_header_files = [ |
| "common_types.h", |
| "common_types_format.h", |
| "fidl.h", |
| "markers.h", |
| "natural_messaging.h", |
| "natural_ostream.h", |
| "natural_types.h", |
| "type_conversions.h", |
| "wire_messaging.h", |
| "wire_types.h", |
| "wire.h", |
| ] |
| generated_source_files = [ |
| "common_types.cc", |
| "natural_ostream.cc", |
| "natural_types.cc", |
| "type_conversions.cc", |
| "wire_types.cc", |
| ] + select({ |
| "@platforms//os:fuchsia": [ |
| "natural_messaging.cc", |
| "wire_messaging.cc", |
| ], |
| "//conditions:default": [], |
| }) |
| generated_testing_header_files = [ |
| "test_base.h", |
| "wire_test_base.h", |
| ] |
| additional_deps = [ |
| "//sdk/lib/fidl/cpp:cpp_base", |
| "//sdk/lib/fidl/cpp:natural_ostream", |
| "//sdk/lib/fidl/cpp/wire", |
| "//sdk/lib/fit", |
| ] + select({ |
| "@platforms//os:fuchsia": [ |
| "//sdk/lib/fidl", |
| "//sdk/lib/fidl/cpp", |
| ], |
| "//conditions:default": [], |
| }) |
| |
| if contains_drivers: |
| # TODO(https://fxbug.dev/503359085): Implement driver transport |
| # support and uncomment these lines. |
| # generated_header_files += ["driver/wire.h"] + select({ |
| # "@platforms//os:fuchsia": [ |
| # "driver/fidl.h", |
| # "driver/natural_messaging.h", |
| # "driver/wire_messaging.h", |
| # ], |
| # "//conditions:default": [], |
| # }) |
| # generated_source_files += select({ |
| # "@platforms//os:fuchsia": [ |
| # "driver/natural_messaging.cc", |
| # "driver/wire_messaging.cc", |
| # ], |
| # "//conditions:default": [], |
| # }) |
| # generated_testing_header_files += [ |
| # "driver/test_base.h", |
| # "driver/wire_test_base.h", |
| # ] |
| # additional_deps += [ |
| # "//sdk/lib/fidl_driver", |
| # "//sdk/lib/fidl_driver:fidl_driver_natural", |
| # ] |
| pass |
| |
| generated_hlcpp_conversion_header_files = [] |
| if enable_hlcpp: |
| generated_hlcpp_conversion_header_files = ["hlcpp_conversion.h"] |
| |
| _generate_fidl_cc_bindings( |
| name = cpp_codegen_name, |
| fidl_library_name = fidl_library_name, |
| fidl_ir_json = fidl_ir_json, |
| bindings_flavor = cpp_bindings_flavor, |
| contains_drivers = contains_drivers, |
| generated_files_base = "fidl/" + fidl_library_name + "/cpp", |
| generated_header_files = generated_header_files, |
| generated_source_files = generated_source_files, |
| generated_testing_header_files = generated_testing_header_files, |
| generated_conversion_header_files = generated_hlcpp_conversion_header_files, |
| fidlgen_tool = "@//tools/fidl/fidlgen_cpp:fidlgen_cpp", |
| testonly = testonly, |
| ) |
| |
| _sources_wrapper( |
| name = cpp_sources_name, |
| generated_fidl_cc_bindings = ":%s" % cpp_codegen_name, |
| testonly = testonly, |
| ) |
| |
| _fidl_cc_library( |
| name = cpp_lib_name, |
| fidl_library_name = fidl_library_name, |
| fidl_deps = deps, |
| bindings_flavor = cpp_bindings_flavor, |
| hdrs = [":%s" % cpp_codegen_name], |
| srcs = [":%s" % cpp_sources_name], |
| additional_deps = additional_deps, |
| testonly = testonly, |
| visibility = visibility, |
| ) |
| |
| if define_idk_atom_aliases: |
| native.alias( |
| name = cpp_lib_name + "_idk", |
| actual = name + "_idk", |
| visibility = visibility, |
| ) |
| |
| _testing_headers_wrapper( |
| name = cpp_testing_headers_name, |
| generated_fidl_cc_bindings = ":%s" % cpp_codegen_name, |
| testonly = testonly, |
| ) |
| |
| testing_suffix = "testing" |
| cpp_testing_lib_name = _get_name_with_suffix(cpp_lib_name, testing_suffix) |
| _fidl_cc_library( |
| name = cpp_testing_lib_name, |
| fidl_library_name = fidl_library_name, |
| fidl_deps = deps, |
| bindings_flavor = cpp_bindings_flavor, |
| hdrs = [":%s" % cpp_testing_headers_name], |
| srcs = [], |
| additional_deps = [":%s" % cpp_lib_name], |
| extra_dep_suffix = testing_suffix, |
| target_compatible_with = ["@platforms//os:fuchsia"], |
| testonly = testonly, |
| visibility = visibility, |
| ) |
| |
| if define_idk_atom_aliases: |
| native.alias( |
| name = cpp_testing_lib_name + "_idk", |
| actual = name + "_idk", |
| visibility = visibility, |
| ) |
| |
| if enable_hlcpp: |
| cpp_hlcpp_conversion_headers_name = "%s_hlcpp_conversion_headers" % cpp_lib_name |
| _conversion_headers_wrapper( |
| name = cpp_hlcpp_conversion_headers_name, |
| generated_fidl_cc_bindings = ":%s" % cpp_codegen_name, |
| testonly = testonly, |
| ) |
| |
| cpp_hlcpp_conversion_suffix = "hlcpp_conversion" |
| hlcpp_conversion_lib_name = _get_name_with_suffix(cpp_lib_name, cpp_hlcpp_conversion_suffix) |
| _fidl_cc_library( |
| name = hlcpp_conversion_lib_name, |
| fidl_library_name = fidl_library_name, |
| fidl_deps = deps, |
| bindings_flavor = cpp_bindings_flavor, |
| hdrs = [":%s" % cpp_hlcpp_conversion_headers_name], |
| srcs = [], |
| additional_deps = [ |
| ":%s" % cpp_lib_name, |
| ":%s" % hlcpp_lib_name, |
| "//sdk/lib/fidl/cpp:hlcpp_conversion", |
| ], |
| extra_dep_suffix = cpp_hlcpp_conversion_suffix, |
| testonly = testonly, |
| visibility = visibility, |
| ) |
| |
| if define_idk_atom_aliases: |
| native.alias( |
| name = hlcpp_conversion_lib_name + "_idk", |
| actual = name + "_idk", |
| visibility = visibility, |
| ) |
| |
| if enable_hlcpp: |
| hlcpp_codegen_name = "%s_generated_fidl_cc_bindings" % hlcpp_lib_name |
| hlcpp_sources_name = "%s_sources" % hlcpp_lib_name |
| |
| library_name_slashes = fidl_library_name.replace(".", "/") |
| |
| generated_header_files = [ |
| "fidl.h", |
| "fidl_test_base.h", |
| ] |
| generated_source_files = [ |
| "fidl.cc", |
| "tables.c", |
| ] |
| additional_deps = ["//sdk/lib/fidl_base"] + hlcpp_lib_deps |
| |
| _generate_fidl_cc_bindings( |
| name = hlcpp_codegen_name, |
| fidl_library_name = fidl_library_name, |
| fidl_ir_json = fidl_ir_json, |
| bindings_flavor = hlcpp_bindings_flavor, |
| contains_drivers = contains_drivers, |
| generated_files_base = library_name_slashes + "/cpp", |
| generated_header_files = generated_header_files, |
| generated_source_files = generated_source_files, |
| fidlgen_tool = "@//tools/fidl/fidlgen_hlcpp:fidlgen_hlcpp", |
| testonly = testonly, |
| ) |
| |
| _sources_wrapper( |
| name = hlcpp_sources_name, |
| generated_fidl_cc_bindings = ":%s" % hlcpp_codegen_name, |
| testonly = testonly, |
| ) |
| |
| # TODO(https://fxbug.dev/454977301): Implement `hlcpp_visibility`. |
| hlcpp_visibility = visibility |
| |
| _fidl_cc_library( |
| name = hlcpp_lib_name, |
| fidl_library_name = fidl_library_name, |
| fidl_deps = deps, |
| bindings_flavor = hlcpp_bindings_flavor, |
| hdrs = [":%s" % hlcpp_codegen_name], |
| srcs = [":%s" % hlcpp_sources_name], |
| additional_deps = additional_deps, |
| testonly = testonly, |
| visibility = hlcpp_visibility, |
| ) |
| |
| if define_idk_atom_aliases: |
| native.alias( |
| name = hlcpp_lib_name + "_idk", |
| actual = name + "_idk", |
| visibility = hlcpp_visibility, |
| ) |
| |
| def _fidl_cc_library( |
| name, |
| fidl_library_name, |
| fidl_deps, |
| bindings_flavor, |
| hdrs, |
| srcs, |
| additional_deps, |
| testonly, |
| visibility, |
| extra_dep_suffix = "", |
| target_compatible_with = []): |
| """Generate a `cc_library()` providing the generated C++ bindings for a given FIDL library. |
| |
| Args: |
| name: String name of the `cc_library()` target. |
| fidl_library_name: String name of the FIDL library for which bindings are generated. |
| fidl_deps: List of `Label`s for FIDL libraries that the |
| `fidl_library_name` library depends on. |
| bindings_flavor: String name of the FIDL bindings flavor (e.g., "cpp"). |
| hdrs: List of `Label`s for the generated header files. |
| srcs: List of `Label`s for the generated source files. |
| additional_deps: List of `Label`s for additional dependencies of the generated files. |
| testonly: Usual meaning. |
| visibility: Usual meaning. |
| extra_dep_suffix: Additional string suffix to append to the |
| `bindings_flavor` to form the dependency suffix. Optional. |
| target_compatible_with: Usual meaning. Optional. |
| """ |
| if fidl_library_name == "zx": |
| # The zx FIDL library isn't generated with C++ fidlgens. |
| # Create an empty library. |
| if fidl_deps != []: |
| fail("zx FIDL library should not have any dependencies.") |
| cc_library( |
| name = name, |
| testonly = testonly, |
| visibility = visibility, |
| ) |
| else: |
| if extra_dep_suffix: |
| dep_suffix = _get_name_with_suffix(bindings_flavor, extra_dep_suffix) |
| else: |
| dep_suffix = bindings_flavor |
| cc_library( |
| name = name, |
| hdrs = hdrs, |
| srcs = srcs, |
| deps = _get_deps_with_suffix(fidl_deps, dep_suffix) + additional_deps, |
| # This is necessary in order to locate generated headers. |
| strip_include_prefix = _get_root_path(bindings_flavor), |
| target_compatible_with = target_compatible_with, |
| testonly = testonly, |
| visibility = visibility, |
| ) |
| |
| def _generate_fidl_cc_bindings_impl(ctx): |
| ir = ctx.file.fidl_ir_json |
| |
| root_path = _get_root_path(ctx.attr.bindings_flavor) |
| dir = root_path + "/" + ctx.attr.generated_files_base |
| |
| headers = [] |
| sources = [] |
| testing_headers = [] |
| conversion_headers = [] |
| for header in ctx.attr.generated_header_files: |
| headers.append(ctx.actions.declare_file(dir + "/" + header)) |
| for source in ctx.attr.generated_source_files: |
| sources.append(ctx.actions.declare_file(dir + "/" + source)) |
| for testing_header in ctx.attr.generated_testing_header_files: |
| testing_headers.append(ctx.actions.declare_file(dir + "/" + testing_header)) |
| for conversion_header in ctx.attr.generated_conversion_header_files: |
| conversion_headers.append(ctx.actions.declare_file(dir + "/" + conversion_header)) |
| |
| ctx.actions.run( |
| executable = ctx.executable.fidlgen_tool, |
| arguments = [ |
| "--json", |
| ir.path, |
| "--clang-format-path", |
| ctx.executable._clang_format.path, |
| "--root", |
| paths.join(ctx.bin_dir.path, ctx.label.workspace_root, ctx.label.package, root_path), |
| |
| # TODO(https://fxbug.dev/454977301): Support experiments. |
| # if (defined(invoker.experiments)) { |
| # foreach(experiment, invoker.experiments) { |
| # args += [ |
| # "--experiment", |
| # experiment, |
| # ] |
| # } |
| # } |
| ], |
| inputs = [ir, ctx.executable._clang_format], |
| outputs = headers + sources + testing_headers + conversion_headers, |
| mnemonic = "FidlGenCc", |
| ) |
| |
| return [ |
| _FidlCcCodegenInfo( |
| headers = depset(headers), |
| sources = depset(sources), |
| testing_headers = depset(testing_headers), |
| conversion_headers = depset(conversion_headers), |
| ), |
| DefaultInfo(files = depset(headers)), |
| ] |
| |
| _generate_fidl_cc_bindings = rule( |
| doc = "Runs fidlgen to produce both the header files and source files. " + |
| "Only exposes the header files in `DefaultInfo`, as the two files need to be " + |
| "consumed by `cc_library()` as two separate rules.", |
| implementation = _generate_fidl_cc_bindings_impl, |
| attrs = { |
| "fidl_library_name": attr.string( |
| doc = "Name of the FIDL library.", |
| mandatory = True, |
| ), |
| "fidl_ir_json": attr.label( |
| doc = "The FIDL IR for which to generate code.", |
| allow_single_file = True, |
| mandatory = True, |
| ), |
| "bindings_flavor": attr.string( |
| doc = "The flavor of bindings to generate.", |
| mandatory = True, |
| values = ["cpp", "hlcpp"], |
| ), |
| "contains_drivers": attr.bool( |
| doc = "Indicates if any of the FIDL files contain the driver transport or " + |
| "references to the driver transport.", |
| mandatory = True, |
| ), |
| "generated_files_base": attr.string( |
| doc = "Base path for generated files. The files will be generated" + |
| " at this path under the root path for the bindings flavor", |
| mandatory = True, |
| ), |
| "generated_header_files": attr.string_list( |
| doc = "List of header files that will be generated.", |
| mandatory = True, |
| ), |
| "generated_source_files": attr.string_list( |
| doc = "List of source files that will be generated.", |
| mandatory = True, |
| ), |
| "generated_testing_header_files": attr.string_list( |
| doc = "List of header files for testing that will be generated.", |
| default = [], |
| ), |
| "generated_conversion_header_files": attr.string_list( |
| doc = "List of header files for HLCPP conversion that will be generated.", |
| default = [], |
| ), |
| "fidlgen_tool": attr.label( |
| doc = "fidlgen tool.", |
| mandatory = True, |
| executable = True, |
| cfg = "exec", |
| ), |
| "_clang_format": attr.label( |
| doc = "clang-format tool.", |
| executable = True, |
| allow_single_file = True, |
| cfg = "exec", |
| default = "@fuchsia_clang//:bin/clang-format", |
| ), |
| }, |
| ) |
| |
| def _sources_wrapper_impl(ctx): |
| return [DefaultInfo(files = ctx.attr.generated_fidl_cc_bindings[_FidlCcCodegenInfo].sources)] |
| |
| _sources_wrapper = rule( |
| doc = "Simply declares the source files generated by the " + |
| "`_generate_fidl_cc_bindings` target as outputs. This allows the " + |
| "source files to be exposed as sources in their own rule.", |
| implementation = _sources_wrapper_impl, |
| attrs = { |
| "generated_fidl_cc_bindings": attr.label( |
| doc = "The `_generate_fidl_cc_bindings` target generating the source files", |
| mandatory = True, |
| allow_files = False, |
| providers = [_FidlCcCodegenInfo], |
| ), |
| }, |
| ) |
| |
| def _testing_headers_wrapper_impl(ctx): |
| return [DefaultInfo( |
| files = ctx.attr.generated_fidl_cc_bindings[_FidlCcCodegenInfo].testing_headers, |
| )] |
| |
| _testing_headers_wrapper = rule( |
| doc = "Simply declares the testing header files generated by the " + |
| "`_generate_fidl_cc_bindings` target as outputs. This allows the " + |
| "testing header files to be exposed as sources in their own rule.", |
| implementation = _testing_headers_wrapper_impl, |
| attrs = { |
| "generated_fidl_cc_bindings": attr.label( |
| doc = "The `_generate_fidl_cc_bindings` target generating the testing header files.", |
| mandatory = True, |
| allow_files = False, |
| providers = [_FidlCcCodegenInfo], |
| ), |
| }, |
| ) |
| |
| def _conversion_headers_wrapper_impl(ctx): |
| return [DefaultInfo( |
| files = ctx.attr.generated_fidl_cc_bindings[_FidlCcCodegenInfo].conversion_headers, |
| )] |
| |
| _conversion_headers_wrapper = rule( |
| doc = "Simply declares the HLCPP conversion header files generated by the " + |
| "`_generate_fidl_cc_bindings` target as outputs. This allows the " + |
| "HLCPP conversion header files to be exposed as sources in their own rule.", |
| implementation = _conversion_headers_wrapper_impl, |
| attrs = { |
| "generated_fidl_cc_bindings": attr.label( |
| doc = "The `_generate_fidl_cc_bindings` target generating the HLCPP conversion header files.", |
| mandatory = True, |
| allow_files = False, |
| providers = [_FidlCcCodegenInfo], |
| ), |
| }, |
| ) |