blob: 7daf4d6282a55bb5bf9d223eb1b270dd18afa350 [file]
# 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
"""Generates bindings for the toolchain headers."""
load("@rules_cc//cc/common:cc_info.bzl", "CcInfo")
load(
"@@//rs_bindings_from_cc/bazel_support:providers.bzl",
"AdditionalRustSrcsProviderInfo",
"DepsForBindingsInfo",
"RustToolchainHeadersInfo",
)
load(
"@@//rs_bindings_from_cc/bazel_support:rust_bindings_from_cc_utils.bzl",
"bindings_attrs",
"generate_and_compile_bindings",
)
def _has_suffix(input, suffixes):
for suffix in suffixes:
if input.short_path.endswith(suffix):
return True
return False
def _filter_headers_with_suffixes(input_list, suffixes):
return [hdr for hdr in input_list if _has_suffix(hdr, suffixes)]
def _filter_headers_without_suffixes(input_list, suffixes):
return [hdr for hdr in input_list if not _has_suffix(hdr, suffixes)]
def _add_prefix(strings, prefix):
return [prefix + s for s in strings]
def _bindings_for_toolchain_headers_impl(ctx):
toolchain = ctx.toolchains["@@//rs_bindings_from_cc/bazel_support:toolchain_type"].rs_bindings_from_cc_toolchain_info
builtin_headers = toolchain.builtin_headers
stl_headers = depset(toolchain.stl_headers + ctx.files.extra_hdrs)
# TODO(b/803417336): depset(...).to_list() is necessary to deduplicate header files.
std_files = depset(transitive = [ctx.attr._stl[CcInfo].compilation_context.headers, stl_headers]).to_list()
std_and_builtin_files = depset(builtin_headers, transitive = [stl_headers, ctx.attr._stl[CcInfo].compilation_context.headers])
prefixed_libcxx_hdrs = _add_prefix(ctx.attr.public_libcxx_hdrs, "c++/v1/")
# The clang builtin headers also contain some libc++ headers. We consider those part of
# the libc++ target, so we generate bindings for them.
builtin_libcxx_files = _filter_headers_with_suffixes(builtin_headers, prefixed_libcxx_hdrs)
builtin_nonstd_files = _filter_headers_without_suffixes(
builtin_headers,
ctx.attr.public_libcxx_hdrs,
)
target_args = depset(
direct = [
json.encode({
"t": str(ctx.label),
"h": [hdr.path for hdr in std_files + builtin_libcxx_files],
"f": ["all"],
}),
json.encode({
"t": "//:_nothing_should_depend_on_private_builtin_hdrs",
"h": [h.path for h in builtin_nonstd_files],
}),
],
)
public_libcxx_files = _filter_headers_with_suffixes(std_files, prefixed_libcxx_hdrs)
public_libc_files = _filter_headers_with_suffixes(std_files, _add_prefix(ctx.attr.public_libc_hdrs, "v5/include/"))
header_includes = []
for hdr in ctx.attr.public_libcxx_hdrs + ctx.attr.public_libc_hdrs:
header_includes.append("-include")
header_includes.append(hdr)
extra_rs_srcs = []
extra_rs_deps = []
for target in ctx.attr.extra_rs_srcs:
if AdditionalRustSrcsProviderInfo in target:
for src in target[AdditionalRustSrcsProviderInfo].srcs:
extra_rs_srcs.extend([(f, target[AdditionalRustSrcsProviderInfo].namespace_path) for f in src.files.to_list()])
extra_rs_deps.extend(target[AdditionalRustSrcsProviderInfo].deps)
if target[AdditionalRustSrcsProviderInfo].cc_deps:
fail("toolchain_headers do not accept additional Rust cc_deps")
else:
extra_rs_srcs.extend([(f, "") for f in target.files.to_list()])
return [RustToolchainHeadersInfo(headers = std_and_builtin_files)] + generate_and_compile_bindings(
ctx,
ctx.attr,
compilation_context = ctx.attr._stl[CcInfo].compilation_context,
public_hdrs = public_libc_files + public_libcxx_files + ctx.files.extra_hdrs,
header_includes = header_includes,
action_inputs = std_and_builtin_files,
target_args = target_args,
extra_rs_srcs = extra_rs_srcs,
deps_for_cc_file = ctx.attr._deps_for_bindings[DepsForBindingsInfo].deps_for_cc_file,
deps_for_rs_file = depset(extra_rs_deps + ctx.attr._deps_for_bindings[DepsForBindingsInfo].deps_for_rs_file),
)
bindings_for_toolchain_headers = rule(
implementation = _bindings_for_toolchain_headers_impl,
attrs = bindings_attrs | {
# Additional internal headers that are not part of the standard library. These headers will
# receive bindings which are exposed along with the standard library bindings.
# Everything inside these under should be hidden within namespace `crubit_cc_std_internal`.
"extra_hdrs": attr.label_list(default = []),
"public_libc_hdrs": attr.string_list(),
"public_libcxx_hdrs": attr.string_list(),
"extra_rs_srcs": attr.label_list(allow_files = True),
# This isn't read directly by _bindings_for_toolchain_headers_impl, but is read by
# rules_rust when compiling the generated and additional Rust source code.
"crate_features": attr.string_list(),
"_stl": attr.label(default = "//third_party/stl:stl"),
# TODO: b/421934470 - Fix uses of exec groups and re-enable AEG
"_use_auto_exec_groups": attr.bool(default = False),
},
toolchains = [
"@rules_rust//rust:toolchain_type",
"@bazel_tools//tools/cpp:toolchain_type",
"@@//rs_bindings_from_cc/bazel_support:toolchain_type",
],
fragments = ["cpp", "google_cpp"],
)