blob: 697d1ebed7ef1fafc585a435713a75cc4dd02587 [file] [log] [blame]
# Part of the Crubit project, under the Apache License v2.0 with LLVM
# Exceptions. See /LICENSE for license information.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
"""Utility module for sharing logic between rules and aspects that generate Rust bindings from C++.
"""
load(
"//cc_bindings_from_rs/bazel_support:providers.bzl",
"CcBindingsFromRustInfo",
)
load("@@//rs_bindings_from_cc/bazel_support:compile_cc.bzl", "compile_cc")
load("@@//rs_bindings_from_cc/bazel_support:compile_rust.bzl", "compile_rust")
load(
"@@//rs_bindings_from_cc/bazel_support:generate_bindings.bzl",
"escape_cpp_target_name",
"generate_bindings",
)
load(
"@@//rs_bindings_from_cc/bazel_support:providers.bzl",
"GeneratedBindingsInfo",
"RustBindingsFromCcInfo",
)
load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain")
def generate_and_compile_bindings(
ctx,
attr,
compilation_context,
public_hdrs,
header_includes,
action_inputs,
target_args,
extra_rs_srcs,
deps_for_cc_file,
deps_for_rs_file,
extra_cc_compilation_action_inputs = [],
extra_rs_bindings_from_cc_cli_flags = []):
"""Runs the bindings generator.
Args:
ctx: The rule context.
attr: The current rule's attributes.
compilation_context: The current compilation context.
public_hdrs: A list of headers to be passed to the tool via the "--public_headers" flag.
header_includes: A list of flags to be passed to the command line with "-include".
action_inputs: A depset of inputs to the bindings generating action.
target_args: A depset of strings, each one representing mapping of target to
its per-target arguments (headers, features) in json format.
extra_rs_srcs: list[file]: Additional source files for the Rust crate.
deps_for_cc_file: list[CcInfo]: CcInfos needed by the generated C++ source file.
deps_for_rs_file: list[DepVariantInfo]: DepVariantInfos needed by the generated Rust source file.
extra_cc_compilation_action_inputs: A list of input files for the C++ compilation action.
extra_rs_bindings_from_cc_cli_flags: CLI flags to pass to `rs_bindings_from_cc`, in addition
to the flags that are passed by the build rule.
Returns:
A RustBindingsFromCcInfo containing the result of the compilation of the generated source
files, as well a GeneratedBindingsInfo provider containing the generated source files.
"""
cc_toolchain = find_cpp_toolchain(ctx)
feature_configuration_for_bindings = cc_common.configure_features(
ctx = ctx,
cc_toolchain = cc_toolchain,
requested_features = ctx.features + ["compiler_param_file"],
unsupported_features = ctx.disabled_features + ["module_maps"],
)
cc_output, rs_output, namespaces_output, error_report_output = generate_bindings(
ctx = ctx,
attr = attr,
cc_toolchain = cc_toolchain,
feature_configuration = feature_configuration_for_bindings,
compilation_context = compilation_context,
public_hdrs = public_hdrs,
header_includes = header_includes,
action_inputs = action_inputs,
target_args = target_args,
extra_rs_srcs = extra_rs_srcs,
extra_rs_bindings_from_cc_cli_flags = extra_rs_bindings_from_cc_cli_flags,
)
# Relocate the rs files so that they can be read by rustc using relative paths.
extra_rs_srcs_relocated = []
for file in extra_rs_srcs:
new_file = ctx.actions.declare_file(file.path, sibling = rs_output)
ctx.actions.symlink(output = new_file, target_file = file)
extra_rs_srcs_relocated.append(new_file)
# We use a separate feature_configuration for the clang compile action as the feature
# configuration for bindings generation needs to use a param file. The clang wrapper script
# however does not handle param files well today (b/326976757)
feature_configuration_for_cc_compile = cc_common.configure_features(
ctx = ctx,
cc_toolchain = cc_toolchain,
requested_features = ctx.features,
unsupported_features = ctx.disabled_features + ["module_maps"],
)
# Compile the "_rust_api_impl.cc" file
cc_info = compile_cc(
ctx,
attr,
cc_toolchain,
feature_configuration_for_cc_compile,
cc_output,
deps_for_cc_file,
extra_cc_compilation_action_inputs,
)
# TODO(b/216587072): Remove this hacky escaping and use the import! macro once available
crate_name = escape_cpp_target_name(ctx.label.package, ctx.label.name)
# Compile the "_rust_api.rs" file together with extra_rs_srcs.
dep_variant_info = compile_rust(
ctx,
attr,
rs_output,
extra_rs_srcs_relocated,
deps_for_rs_file,
crate_name,
# TODO(b/322303104) For now, we don't generate baseline_coverage.dat for generated rust
# bindings, because the baseline_coverage.dat this compile action generates conflicts with
# the .dat file with the underlying cc_library. Once bazel supports baseline_coverage.dat
# for aspects, we can remove this option.
include_coverage = False,
)
return [
RustBindingsFromCcInfo(
cc_info = cc_info,
dep_variant_info = dep_variant_info,
target_args = target_args,
namespaces = namespaces_output,
),
GeneratedBindingsInfo(
cc_file = cc_output,
rust_file = rs_output,
namespaces_file = namespaces_output,
),
OutputGroupInfo(out = depset([x for x in [cc_output, rs_output, namespaces_output, error_report_output] if x != None])),
# The C++ bindings of the generated Rust bindings are the original C++ file.
CcBindingsFromRustInfo(
cc_info = cc_info,
crate_key = dep_variant_info.crate_info.name,
headers = public_hdrs,
),
]
bindings_attrs = {
"_cc_toolchain": attr.label(
default = "@bazel_tools//tools/cpp:current_cc_toolchain",
),
"_generator": attr.label(
default = "@@//rs_bindings_from_cc/bazel_support:rust_bindings_from_cc_target",
executable = True,
allow_single_file = True,
cfg = "exec",
),
"_deps_for_bindings": attr.label(
doc = "Dependencies that are needed to compile the generated .cc and .rs file.",
default = "@@//rs_bindings_from_cc/bazel_support:deps_for_bindings",
),
"_clang_format": attr.label(
default = "//third_party/crosstool/google3_users:stable_clang-format",
executable = True,
allow_single_file = True,
cfg = "exec",
),
"_rustfmt": attr.label(
default = "//third_party/crosstool/rust/unstable:genrustfmt_for_crubit_aspects",
executable = True,
allow_single_file = True,
cfg = "exec",
),
"_rustfmt_cfg": attr.label(
default = "//nowhere:rustfmt.toml",
allow_single_file = True,
),
# TODO(hlopko): Either 1) remove the unneeded `_error_format` and
# `_extra_rustc_flags` attributes below *or* 2) actually start using them
# (both for `rs_bindings_from_cc` and for `cc_bindings_from_rs`).
"_error_format": attr.label(
default = "@rules_rust//:error_format",
),
"_extra_rustc_flags": attr.label(
default = "@rules_rust//:extra_rustc_flags",
),
"_process_wrapper": attr.label(
default = "@rules_rust//util/process_wrapper",
executable = True,
allow_single_file = True,
cfg = "exec",
),
"_builtin_hdrs": attr.label(
default = "//rs_bindings_from_cc:builtin_headers",
),
"_generate_error_report": attr.label(
default = "@@//rs_bindings_from_cc/bazel_support:generate_error_report",
),
}