Skip to content

Commit 64bdbdf

Browse files
authored
bindgen: Pass -resource-dir Clang flag to bindgen-cli. (#3591)
For some cc_toolchain configurations, this is required to find the builtin headers. So far, the bindgen rules had assumed that the builtin headers can be found through `cc_toolchain.built_in_include_directories`. This is, however, not guaranteed to be the case; indeed, `built_in_include_directories` is not really intended for finding builtin headers but merely for filtering out diagnostics in builtin headers. Clang itself finds the resource directory relative to its own binary, and then finds the builtin headers in the "include" subdirectory of the resource directory. bindgen-cli may, however, be located in a different directory than Clang, so we pass a `-resource-dir` flag on the command line.
1 parent 6d532fd commit 64bdbdf

File tree

2 files changed

+115
-1
lines changed

2 files changed

+115
-1
lines changed

extensions/bindgen/private/bindgen.bzl

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
"""Rust Bindgen rules"""
1616

17+
load("@bazel_skylib//lib:paths.bzl", "paths")
1718
load(
1819
"@bazel_tools//tools/build_defs/cc:action_names.bzl",
1920
"CPP_COMPILE_ACTION_NAME",
@@ -187,6 +188,23 @@ def _generate_cc_link_build_info(ctx, cc_lib):
187188
rustc_env = None,
188189
)
189190

191+
def _get_resource_dir(cc_toolchain):
192+
"""Returns the resource directory for the given cc_toolchain."""
193+
194+
# We use a bit of a hack to find the resource directory: We know that the builtin header
195+
# stdbool.h (chosen relatively arbitrarily) needs to appear in `cc_toolchain.all_files`, so we
196+
# search for it and use the directory above the include directory as the resource directory.
197+
# This isn't ideal, but [email protected] believes there is no more direct way of doing this.
198+
for f in cc_toolchain.all_files.to_list():
199+
if f.basename == "stdbool.h":
200+
path = f.path
201+
for _ in range(path.count("/") + 1):
202+
if paths.basename(path) == "include":
203+
return paths.dirname(path)
204+
path = paths.dirname(path)
205+
206+
return None
207+
190208
def _rust_bindgen_impl(ctx):
191209
# nb. We can't grab the cc_library`s direct headers, so a header must be provided.
192210
cc_lib = ctx.attr.cc_lib
@@ -254,6 +272,10 @@ def _rust_bindgen_impl(ctx):
254272
# Configure Clang Arguments
255273
args.add("--")
256274

275+
resource_dir = _get_resource_dir(cc_toolchain)
276+
if resource_dir:
277+
args.add("-resource-dir=%s" % resource_dir)
278+
257279
compile_variables = cc_common.create_compile_variables(
258280
cc_toolchain = cc_toolchain,
259281
feature_configuration = feature_configuration,

extensions/bindgen/test/bindgen_test.bzl

Lines changed: 93 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,64 @@
11
"""Analysis test for for rust_bindgen_library rule."""
22

3-
load("@rules_cc//cc:defs.bzl", "cc_library")
3+
load("@bazel_skylib//rules:write_file.bzl", "write_file")
4+
load("@rules_cc//cc:defs.bzl", "cc_library", "cc_toolchain")
5+
load("@rules_cc//cc/common:cc_common.bzl", "cc_common")
46
load("@rules_rust//rust:defs.bzl", "rust_binary")
57
load("@rules_rust_bindgen//:defs.bzl", "rust_bindgen_library")
68
load("@rules_testing//lib:analysis_test.bzl", "analysis_test", "test_suite")
9+
load("@rules_testing//lib:truth.bzl", "matching")
10+
11+
def _fake_cc_toolchain_config_impl(ctx):
12+
return cc_common.create_cc_toolchain_config_info(
13+
ctx = ctx,
14+
toolchain_identifier = "fake-toolchain",
15+
host_system_name = "unknown",
16+
target_system_name = "unknown",
17+
target_cpu = "unknown",
18+
target_libc = "unknown",
19+
compiler = "unknown",
20+
abi_version = "unknown",
21+
abi_libc_version = "unknown",
22+
)
23+
24+
_fake_cc_toolchain_config = rule(
25+
implementation = _fake_cc_toolchain_config_impl,
26+
attrs = {},
27+
provides = [CcToolchainConfigInfo],
28+
)
29+
30+
def _fake_cc_toolchain(name):
31+
_fake_cc_toolchain_config(name = name + "_toolchain_config")
32+
33+
empty_filegroup = name + "_empty_filegroup"
34+
native.filegroup(name = empty_filegroup)
35+
36+
stdbool_file = name + "_stdbool"
37+
write_file(
38+
name = stdbool_file,
39+
content = [],
40+
out = "my/resource/dir/include/stdbool.h",
41+
)
42+
43+
all_files = name + "_all_files"
44+
native.filegroup(name = all_files, srcs = [stdbool_file])
45+
46+
cc_toolchain(
47+
name = name + "_cc_toolchain",
48+
toolchain_config = name + "_toolchain_config",
49+
all_files = all_files,
50+
dwp_files = empty_filegroup,
51+
compiler_files = empty_filegroup,
52+
linker_files = empty_filegroup,
53+
objcopy_files = empty_filegroup,
54+
strip_files = empty_filegroup,
55+
)
56+
57+
native.toolchain(
58+
name = name,
59+
toolchain = name + "_cc_toolchain",
60+
toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
61+
)
762

863
def _test_cc_linkopt_impl(env, target):
964
# Assert
@@ -100,12 +155,49 @@ def _test_cc_lib_object_merging_disabled(name):
100155
impl = _test_cc_lib_object_merging_disabled_impl,
101156
)
102157

158+
def _test_resource_dir_impl(env, target):
159+
env.expect.that_int(len(target.actions)).is_greater_than(0)
160+
env.expect.that_action(target.actions[0]).mnemonic().contains("RustBindgen")
161+
env.expect.that_action(target.actions[0]).argv().contains_predicate(
162+
matching.all(
163+
matching.str_startswith("-resource-dir="),
164+
matching.str_endswith("my/resource/dir"),
165+
),
166+
)
167+
168+
def _test_resource_dir(name):
169+
_fake_cc_toolchain(name + "_toolchain")
170+
171+
cc_library(
172+
name = name + "_cc",
173+
hdrs = ["simple.h"],
174+
srcs = ["simple.cc"],
175+
)
176+
177+
rust_bindgen_library(
178+
name = name + "_rust_bindgen",
179+
cc_lib = name + "_cc",
180+
header = "simple.h",
181+
tags = ["manual"],
182+
edition = "2021",
183+
)
184+
185+
analysis_test(
186+
name = name,
187+
target = name + "_rust_bindgen__bindgen",
188+
impl = _test_resource_dir_impl,
189+
config_settings = {
190+
"//command_line_option:extra_toolchains": [str(native.package_relative_label(name + "_toolchain"))],
191+
},
192+
)
193+
103194
def bindgen_test_suite(name):
104195
test_suite(
105196
name = name,
106197
tests = [
107198
_test_cc_linkopt,
108199
_test_cc_lib_object_merging,
109200
_test_cc_lib_object_merging_disabled,
201+
_test_resource_dir,
110202
],
111203
)

0 commit comments

Comments
 (0)