Skip to content

Commit 886b803

Browse files
committed
Update rust_bindgen_library to only link cc_lib into the direct consumer
1 parent 3545dec commit 886b803

File tree

11 files changed

+203
-22
lines changed

11 files changed

+203
-22
lines changed

bindgen/private/bindgen.bzl

Lines changed: 97 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ load(
2020
)
2121
load("@rules_cc//cc:defs.bzl", "CcInfo")
2222
load("//rust:defs.bzl", "rust_library")
23+
load("//rust:rust_common.bzl", "BuildInfo")
2324

2425
# buildifier: disable=bzl-visibility
2526
load("//rust/private:rustc.bzl", "get_linker_and_args")
@@ -64,27 +65,100 @@ def rust_bindgen_library(
6465
if "tags" in kwargs:
6566
kwargs.pop("tags")
6667

68+
sub_tags = tags + ([] if "manual" in tags else ["manual"])
69+
6770
deps = kwargs.get("deps") or []
6871
if "deps" in kwargs:
6972
kwargs.pop("deps")
7073

74+
bindgen_kwargs = {}
75+
if "leak_symbols" in kwargs:
76+
bindgen_kwargs.update({"leak_symbols": kwargs.pop("leak_symbols")})
77+
7178
rust_bindgen(
7279
name = name + "__bindgen",
7380
header = header,
7481
cc_lib = cc_lib,
7582
bindgen_flags = bindgen_flags or [],
7683
clang_flags = clang_flags or [],
77-
tags = ["manual"],
84+
tags = sub_tags,
85+
**bindgen_kwargs
7886
)
7987

88+
for custom_tag in ["__bindgen", "no-clippy", "no-rustfmt"]:
89+
tags = tags + ([] if custom_tag in tags else [custom_tag])
90+
8091
rust_library(
8192
name = name,
8293
srcs = [name + "__bindgen.rs"],
83-
tags = tags + ["__bindgen", "noclippy"],
84-
deps = deps + [cc_lib],
94+
deps = deps + [name + "__bindgen"],
95+
tags = tags,
8596
**kwargs
8697
)
8798

99+
def _generate_cc_link_build_info(ctx, cc_lib):
100+
"""Produce the eqivilant cargo_build_script providers for use in linking the library.
101+
102+
Args:
103+
ctx (ctx): The rule's context object
104+
cc_lib (Target): The `rust_bindgen.cc_lib` target.
105+
106+
Returns:
107+
The `BuildInfo` provider.
108+
"""
109+
compile_data = []
110+
linker_flags = []
111+
linker_search_paths = []
112+
113+
for linker_input in cc_lib[CcInfo].linking_context.linker_inputs.to_list():
114+
for lib in linker_input.libraries:
115+
if lib.static_library:
116+
linker_flags.append("-lstatic={}".format(lib.static_library.owner.name))
117+
linker_search_paths.append(lib.static_library.dirname)
118+
compile_data.append(lib.static_library)
119+
elif lib.pic_static_library:
120+
linker_flags.append("-lstatic={}".format(lib.pic_static_library.owner.name))
121+
linker_search_paths.append(lib.pic_static_library.dirname)
122+
compile_data.append(lib.pic_static_library)
123+
124+
linker_flags.extend(linker_input.user_link_flags)
125+
126+
if not compile_data:
127+
fail("No static libraries found in {}".format(
128+
cc_lib.label,
129+
))
130+
131+
empty_file = ctx.actions.declare_file("{}.empty".format(ctx.label.name))
132+
ctx.actions.write(
133+
output = empty_file,
134+
content = "",
135+
)
136+
137+
link_flags = ctx.actions.declare_file("{}.link_flags".format(ctx.label.name))
138+
ctx.actions.write(
139+
output = link_flags,
140+
content = "\n".join(linker_flags),
141+
)
142+
143+
link_search_paths = ctx.actions.declare_file("{}.link_search_paths".format(ctx.label.name))
144+
ctx.actions.write(
145+
output = link_search_paths,
146+
content = "\n".join([
147+
"-Lnative=${{pwd}}/{}".format(path)
148+
for path in depset(linker_search_paths).to_list()
149+
]),
150+
)
151+
152+
return BuildInfo(
153+
out_dir = None,
154+
rustc_env = empty_file,
155+
dep_env = empty_file,
156+
flags = empty_file,
157+
link_flags = link_flags,
158+
link_search_paths = link_search_paths,
159+
compile_data = depset(compile_data),
160+
)
161+
88162
def _rust_bindgen_impl(ctx):
89163
# nb. We can't grab the cc_library`s direct headers, so a header must be provided.
90164
cc_lib = ctx.attr.cc_lib
@@ -200,6 +274,19 @@ def _rust_bindgen_impl(ctx):
200274
tools = tools,
201275
)
202276

277+
if ctx.attr.leak_symbols:
278+
providers = [cc_common.merge_cc_infos(
279+
direct_cc_infos = [cc_lib[CcInfo]],
280+
)]
281+
else:
282+
providers = [_generate_cc_link_build_info(ctx, cc_lib)]
283+
284+
return providers + [
285+
OutputGroupInfo(
286+
bindgen_bindings = depset([output]),
287+
),
288+
]
289+
203290
rust_bindgen = rule(
204291
doc = "Generates a rust source file from a cc_library and a header.",
205292
implementation = _rust_bindgen_impl,
@@ -220,6 +307,13 @@ rust_bindgen = rule(
220307
allow_single_file = True,
221308
mandatory = True,
222309
),
310+
"leak_symbols": attr.bool(
311+
doc = (
312+
"If True, `cc_lib` will be exposed and linked into all downstream consumers of the target vs. the " +
313+
"`rust_library` directly consuming it."
314+
),
315+
default = False,
316+
),
223317
"_cc_toolchain": attr.label(
224318
default = Label("@bazel_tools//tools/cpp:current_cc_toolchain"),
225319
),

cargo/private/cargo_build_script.bzl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,7 @@ def _cargo_build_script_impl(ctx):
301301
flags = flags_out,
302302
link_flags = link_flags,
303303
link_search_paths = link_search_paths,
304+
compile_data = depset([]),
304305
),
305306
OutputGroupInfo(
306307
streams = depset([streams.stdout, streams.stderr]),
@@ -449,6 +450,7 @@ def _cargo_dep_env_implementation(ctx):
449450
link_search_paths = empty_file,
450451
out_dir = out_dir,
451452
rustc_env = empty_file,
453+
compile_data = depset([]),
452454
))
453455
return [
454456
DefaultInfo(files = depset(ctx.files.src)),
@@ -465,8 +467,9 @@ def _cargo_dep_env_implementation(ctx):
465467
flags = empty_file,
466468
link_flags = empty_file,
467469
link_search_paths = empty_file,
468-
out_dir = empty_dir,
470+
out_dir = None,
469471
rustc_env = empty_file,
472+
compile_data = depset([]),
470473
),
471474
# Information here is used directly by dependencies, and it is an error to have more than
472475
# one dependency which sets this. This is the main way to specify information from build

examples/bindgen/BUILD.bazel

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,15 @@
1-
load("@rules_cc//cc:defs.bzl", "cc_library")
21
load("@rules_rust//bindgen:bindgen.bzl", "rust_bindgen_library")
32
load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_test")
43

5-
cc_library(
6-
name = "simple",
7-
srcs = ["simple.h"],
8-
)
9-
104
rust_bindgen_library(
115
name = "simple_bindgen",
126
bindgen_flags = [
7+
"--allowlist-function=simple_.*",
138
"--allowlist-var=SIMPLE_.*",
149
],
15-
cc_lib = ":simple",
16-
header = "simple.h",
10+
cc_lib = "//bindgen/simple",
11+
header = "//bindgen/simple:simple.h",
12+
leak_symbols = False,
1713
)
1814

1915
rust_binary(
@@ -26,3 +22,25 @@ rust_test(
2622
name = "simple_test",
2723
crate = ":simple_example",
2824
)
25+
26+
rust_bindgen_library(
27+
name = "simple_leaked_bindgen",
28+
bindgen_flags = [
29+
"--allowlist-function=simple_.*",
30+
"--allowlist-var=SIMPLE_.*",
31+
],
32+
cc_lib = "//bindgen/simple",
33+
header = "//bindgen/simple:simple.h",
34+
leak_symbols = True,
35+
)
36+
37+
rust_binary(
38+
name = "simple_leaked_example",
39+
srcs = ["main_leaked.rs"],
40+
deps = [":simple_leaked_bindgen"],
41+
)
42+
43+
rust_test(
44+
name = "simple_leaked_test",
45+
crate = ":simple_leaked_example",
46+
)

examples/bindgen/main.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,22 @@
1+
use simple_bindgen;
2+
3+
fn simple_function() -> i64 {
4+
unsafe { return simple_bindgen::simple_function() }
5+
}
6+
17
fn main() {
2-
println!("The value is {}!", simple_bindgen::SIMPLE_VALUE);
8+
println!(
9+
"The values are {} and {}!",
10+
simple_bindgen::SIMPLE_VALUE,
11+
simple_function()
12+
);
313
}
414

515
#[cfg(test)]
616
mod test {
717
#[test]
818
fn do_the_test() {
919
assert_eq!(42, simple_bindgen::SIMPLE_VALUE);
20+
assert_eq!(1337, super::simple_function());
1021
}
1122
}

examples/bindgen/main_leaked.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
use simple_leaked_bindgen;
2+
3+
fn simple_function() -> i64 {
4+
unsafe { return simple_leaked_bindgen::simple_function() }
5+
}
6+
7+
fn main() {
8+
println!(
9+
"The values are {} and {}!",
10+
simple_leaked_bindgen::SIMPLE_VALUE,
11+
simple_function()
12+
);
13+
}
14+
15+
#[cfg(test)]
16+
mod test {
17+
#[test]
18+
fn do_the_test() {
19+
assert_eq!(42, simple_leaked_bindgen::SIMPLE_VALUE);
20+
assert_eq!(1337, super::simple_function());
21+
}
22+
}

examples/bindgen/simple.h

Lines changed: 0 additions & 5 deletions
This file was deleted.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
load("@rules_cc//cc:defs.bzl", "cc_library")
2+
3+
exports_files(
4+
[
5+
"simple.h",
6+
],
7+
visibility = ["//bindgen:__pkg__"],
8+
)
9+
10+
cc_library(
11+
name = "simple",
12+
srcs = ["simple.cc"],
13+
hdrs = ["simple.h"],
14+
visibility = ["//bindgen:__pkg__"],
15+
)

examples/bindgen/simple/simple.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#include "simple.h"
2+
3+
EXTERN_C const int64_t simple_function() { return 1337; }

examples/bindgen/simple/simple.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#ifndef __SIMPLE_H_INCLUDE__
2+
#define __SIMPLE_H_INCLUDE__
3+
4+
#ifdef __cplusplus
5+
#define EXTERN_C extern "C"
6+
#else
7+
#define EXTERN_C
8+
#endif
9+
10+
#include <stdint.h>
11+
12+
EXTERN_C const int64_t SIMPLE_VALUE = 42;
13+
14+
EXTERN_C const int64_t simple_function();
15+
16+
#endif

rust/private/providers.bzl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,12 @@ CrateGroupInfo = provider(
7272
BuildInfo = provider(
7373
doc = "A provider containing `rustc` build settings for a given Crate.",
7474
fields = {
75+
"compile_data": "Depset[File]: Compile data provided by the build script that was not copied into `out_dir`.",
7576
"dep_env": "File: extra build script environment varibles to be set to direct dependencies.",
7677
"flags": "File: file containing additional flags to pass to rustc",
7778
"link_flags": "File: file containing flags to pass to the linker",
7879
"link_search_paths": "File: file containing search paths to pass to the linker",
79-
"out_dir": "File: directory containing the result of a build script",
80+
"out_dir": "Optional[File]: directory containing the result of a build script",
8081
"rustc_env": "File: file containing additional environment variables to set for rustc.",
8182
},
8283
)

0 commit comments

Comments
 (0)