2020)
2121load ("@rules_cc//cc:defs.bzl" , "CcInfo" )
2222load ("//rust:defs.bzl" , "rust_library" )
23+ load ("//rust:rust_common.bzl" , "BuildInfo" )
2324
2425# buildifier: disable=bzl-visibility
2526load ("//rust/private:rustc.bzl" , "get_linker_and_args" )
@@ -64,27 +65,109 @@ 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 "linkstatic" in kwargs :
76+ bindgen_kwargs .update ({"linkstatic" : kwargs .pop ("linkstatic" )})
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
86+ )
87+
88+ compile_data = kwargs .pop ("compile_data" , []) + [name + "__bindgen.compile_data" ]
89+ native .filegroup (
90+ name = name + "__bindgen.compile_data" ,
91+ srcs = [name + "__bindgen" ],
92+ output_group = "bindgen_compile_data" ,
93+ tags = sub_tags ,
7894 )
7995
96+ for custom_tag in ["__bindgen" , "no-clippy" , "no-rustfmt" ]:
97+ tags = tags + ([] if custom_tag in tags else [custom_tag ])
98+
8099 rust_library (
81100 name = name ,
82101 srcs = [name + "__bindgen.rs" ],
83- tags = tags + ["__bindgen" , "noclippy" ],
84- deps = deps + [cc_lib ],
102+ deps = deps + [name + "__bindgen" ],
103+ compile_data = compile_data ,
104+ tags = tags ,
85105 ** kwargs
86106 )
87107
108+ def _generate_cc_link_build_info (ctx , cc_lib ):
109+ """Produce the eqivilant cargo_build_script providers for use in linking the library.
110+
111+ Args:
112+ ctx (ctx): The rule's context object
113+ cc_lib (Target): The `rust_bindgen.cc_lib` target.
114+
115+ Returns:
116+ The `BuildInfo` provider.
117+ """
118+ compile_data = []
119+ linker_flags = []
120+ linker_search_paths = []
121+
122+ for linker_input in cc_lib [CcInfo ].linking_context .linker_inputs .to_list ():
123+ for lib in linker_input .libraries :
124+ if lib .static_library :
125+ linker_flags .append ("-lstatic={}" .format (lib .static_library .owner .name ))
126+ linker_search_paths .append (lib .static_library .dirname )
127+ compile_data .append (lib .static_library )
128+ elif lib .pic_static_library :
129+ linker_flags .append ("-lstatic={}" .format (lib .pic_static_library .owner .name ))
130+ linker_search_paths .append (lib .pic_static_library .dirname )
131+ compile_data .append (lib .pic_static_library )
132+
133+ linker_flags .extend (linker_input .user_link_flags )
134+
135+ if not compile_data :
136+ fail ("No static libraries found in {}" .format (
137+ cc_lib .label ,
138+ ))
139+
140+ empty_file = ctx .actions .declare_file ("{}.empty" .format (ctx .label .name ))
141+ ctx .actions .write (
142+ output = empty_file ,
143+ content = "" ,
144+ )
145+
146+ link_flags = ctx .actions .declare_file ("{}.link_flags" .format (ctx .label .name ))
147+ ctx .actions .write (
148+ output = link_flags ,
149+ content = "\n " .join (linker_flags ),
150+ )
151+
152+ link_search_paths = ctx .actions .declare_file ("{}.link_search_paths" .format (ctx .label .name ))
153+ ctx .actions .write (
154+ output = link_search_paths ,
155+ content = "\n " .join ([
156+ "-Lnative=${{pwd}}/{}" .format (path )
157+ for path in depset (linker_search_paths ).to_list ()
158+ ]),
159+ )
160+
161+ return BuildInfo (
162+ out_dir = ctx .file ._bindgen_out_dir ,
163+ rustc_env = empty_file ,
164+ dep_env = empty_file ,
165+ flags = empty_file ,
166+ link_flags = link_flags ,
167+ link_search_paths = link_search_paths ,
168+ compile_data = depset (compile_data ),
169+ )
170+
88171def _rust_bindgen_impl (ctx ):
89172 # nb. We can't grab the cc_library`s direct headers, so a header must be provided.
90173 cc_lib = ctx .attr .cc_lib
@@ -200,6 +283,19 @@ def _rust_bindgen_impl(ctx):
200283 tools = tools ,
201284 )
202285
286+ if ctx .attr .linkstatic :
287+ providers = [_generate_cc_link_build_info (ctx , cc_lib )]
288+ else :
289+ providers = [cc_common .merge_cc_infos (
290+ direct_cc_infos = [cc_lib [CcInfo ]],
291+ )]
292+
293+ return providers + [
294+ OutputGroupInfo (
295+ bindgen_bindings = depset ([output ]),
296+ ),
297+ ]
298+
203299rust_bindgen = rule (
204300 doc = "Generates a rust source file from a cc_library and a header." ,
205301 implementation = _rust_bindgen_impl ,
@@ -220,6 +316,17 @@ rust_bindgen = rule(
220316 allow_single_file = True ,
221317 mandatory = True ,
222318 ),
319+ "linkstatic" : attr .bool (
320+ doc = (
321+ "If True, `cc_lib` will be statically linked directly into `rust_library that consumes it. " +
322+ "This will stop the propagation of the `CcInfo` provider from `cc_lib` into downstream targets. "
323+ ),
324+ default = False ,
325+ ),
326+ "_bindgen_out_dir" : attr .label (
327+ default = Label ("//bindgen/private:out_dir" ),
328+ allow_single_file = True ,
329+ ),
223330 "_cc_toolchain" : attr .label (
224331 default = Label ("@bazel_tools//tools/cpp:current_cc_toolchain" ),
225332 ),
0 commit comments