Skip to content

Commit a6f4d69

Browse files
krasimirgghlopko
andauthored
Support native dependencies with linkstamps (#961)
Co-authored-by: Marcel Hlopko <marcel@hlopko.com>
1 parent 238b998 commit a6f4d69

File tree

9 files changed

+223
-9
lines changed

9 files changed

+223
-9
lines changed

docs/defs.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ Add additional rustc_flags from the command line with `--@rules_rust//:extra_rus
7373
<pre>
7474
rust_binary(<a href="#rust_binary-name">name</a>, <a href="#rust_binary-aliases">aliases</a>, <a href="#rust_binary-compile_data">compile_data</a>, <a href="#rust_binary-crate_features">crate_features</a>, <a href="#rust_binary-crate_name">crate_name</a>, <a href="#rust_binary-crate_root">crate_root</a>, <a href="#rust_binary-crate_type">crate_type</a>, <a href="#rust_binary-data">data</a>,
7575
<a href="#rust_binary-deps">deps</a>, <a href="#rust_binary-edition">edition</a>, <a href="#rust_binary-linker_script">linker_script</a>, <a href="#rust_binary-out_binary">out_binary</a>, <a href="#rust_binary-proc_macro_deps">proc_macro_deps</a>, <a href="#rust_binary-rustc_env">rustc_env</a>, <a href="#rust_binary-rustc_env_files">rustc_env_files</a>,
76-
<a href="#rust_binary-rustc_flags">rustc_flags</a>, <a href="#rust_binary-srcs">srcs</a>, <a href="#rust_binary-version">version</a>)
76+
<a href="#rust_binary-rustc_flags">rustc_flags</a>, <a href="#rust_binary-srcs">srcs</a>, <a href="#rust_binary-stamp">stamp</a>, <a href="#rust_binary-version">version</a>)
7777
</pre>
7878

7979
Builds a Rust binary crate.
@@ -181,6 +181,7 @@ Hello world
181181
| <a id="rust_binary-rustc_env_files"></a>rustc_env_files | Files containing additional environment variables to set for rustc.<br><br>These files should contain a single variable per line, of format <code>NAME=value</code>, and newlines may be included in a value by ending a line with a trailing back-slash (<code>\</code>).<br><br>The order that these files will be processed is unspecified, so multiple definitions of a particular variable are discouraged. | <a href="https://bazel.build/docs/build-ref.html#labels">List of labels</a> | optional | [] |
182182
| <a id="rust_binary-rustc_flags"></a>rustc_flags | List of compiler flags passed to <code>rustc</code>.<br><br>These strings are subject to Make variable expansion for predefined source/output path variables like <code>$location</code>, <code>$execpath</code>, and <code>$rootpath</code>. This expansion is useful if you wish to pass a generated file of arguments to rustc: <code>@$(location //package:target)</code>. | List of strings | optional | [] |
183183
| <a id="rust_binary-srcs"></a>srcs | List of Rust <code>.rs</code> source files used to build the library.<br><br>If <code>srcs</code> contains more than one file, then there must be a file either named <code>lib.rs</code>. Otherwise, <code>crate_root</code> must be set to the source file that is the root of the crate to be passed to rustc to build this crate. | <a href="https://bazel.build/docs/build-ref.html#labels">List of labels</a> | optional | [] |
184+
| <a id="rust_binary-stamp"></a>stamp | Embed additional information into the binaries.<br><br>By default stamping is controlled by the --stamp flag. See https://docs.bazel.build/versions/main/user-manual.html#workspace_status and https://docs.bazel.build/versions/main/user-manual.html#flag--stamp. | Integer | optional | -1 |
184185
| <a id="rust_binary-version"></a>version | A version to inject in the cargo environment variable. | String | optional | "0.0.0" |
185186

186187

docs/flatten.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ Produces a rust-project.json for the given targets. Configure rust-analyzer to l
241241
<pre>
242242
rust_binary(<a href="#rust_binary-name">name</a>, <a href="#rust_binary-aliases">aliases</a>, <a href="#rust_binary-compile_data">compile_data</a>, <a href="#rust_binary-crate_features">crate_features</a>, <a href="#rust_binary-crate_name">crate_name</a>, <a href="#rust_binary-crate_root">crate_root</a>, <a href="#rust_binary-crate_type">crate_type</a>, <a href="#rust_binary-data">data</a>,
243243
<a href="#rust_binary-deps">deps</a>, <a href="#rust_binary-edition">edition</a>, <a href="#rust_binary-linker_script">linker_script</a>, <a href="#rust_binary-out_binary">out_binary</a>, <a href="#rust_binary-proc_macro_deps">proc_macro_deps</a>, <a href="#rust_binary-rustc_env">rustc_env</a>, <a href="#rust_binary-rustc_env_files">rustc_env_files</a>,
244-
<a href="#rust_binary-rustc_flags">rustc_flags</a>, <a href="#rust_binary-srcs">srcs</a>, <a href="#rust_binary-version">version</a>)
244+
<a href="#rust_binary-rustc_flags">rustc_flags</a>, <a href="#rust_binary-srcs">srcs</a>, <a href="#rust_binary-stamp">stamp</a>, <a href="#rust_binary-version">version</a>)
245245
</pre>
246246

247247
Builds a Rust binary crate.
@@ -349,6 +349,7 @@ Hello world
349349
| <a id="rust_binary-rustc_env_files"></a>rustc_env_files | Files containing additional environment variables to set for rustc.<br><br>These files should contain a single variable per line, of format <code>NAME=value</code>, and newlines may be included in a value by ending a line with a trailing back-slash (<code>\</code>).<br><br>The order that these files will be processed is unspecified, so multiple definitions of a particular variable are discouraged. | <a href="https://bazel.build/docs/build-ref.html#labels">List of labels</a> | optional | [] |
350350
| <a id="rust_binary-rustc_flags"></a>rustc_flags | List of compiler flags passed to <code>rustc</code>.<br><br>These strings are subject to Make variable expansion for predefined source/output path variables like <code>$location</code>, <code>$execpath</code>, and <code>$rootpath</code>. This expansion is useful if you wish to pass a generated file of arguments to rustc: <code>@$(location //package:target)</code>. | List of strings | optional | [] |
351351
| <a id="rust_binary-srcs"></a>srcs | List of Rust <code>.rs</code> source files used to build the library.<br><br>If <code>srcs</code> contains more than one file, then there must be a file either named <code>lib.rs</code>. Otherwise, <code>crate_root</code> must be set to the source file that is the root of the crate to be passed to rustc to build this crate. | <a href="https://bazel.build/docs/build-ref.html#labels">List of labels</a> | optional | [] |
352+
| <a id="rust_binary-stamp"></a>stamp | Embed additional information into the binaries.<br><br>By default stamping is controlled by the --stamp flag. See https://docs.bazel.build/versions/main/user-manual.html#workspace_status and https://docs.bazel.build/versions/main/user-manual.html#flag--stamp. | Integer | optional | -1 |
352353
| <a id="rust_binary-version"></a>version | A version to inject in the cargo environment variable. | String | optional | "0.0.0" |
353354

354355

rust/private/clippy.bzl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,13 @@ def _clippy_aspect_impl(target, ctx):
6565
aliases = crate_info.aliases,
6666
)
6767

68-
compile_inputs, out_dir, build_env_files, build_flags_files = collect_inputs(
68+
compile_inputs, out_dir, build_env_files, build_flags_files, linkstamp_outs = collect_inputs(
6969
ctx,
7070
ctx.rule.file,
7171
ctx.rule.files,
7272
toolchain,
7373
cc_toolchain,
74+
feature_configuration,
7475
crate_info,
7576
dep_info,
7677
build_info,
@@ -86,6 +87,7 @@ def _clippy_aspect_impl(target, ctx):
8687
feature_configuration = feature_configuration,
8788
crate_info = crate_info,
8889
dep_info = dep_info,
90+
linkstamp_outs = linkstamp_outs,
8991
output_hash = determine_output_hash(crate_info.root),
9092
rust_flags = [],
9193
out_dir = out_dir,

rust/private/rust.bzl

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,12 @@ _rust_test_attrs = {
651651
Whether to use libtest.
652652
"""),
653653
),
654+
"_grep_includes": attr.label(
655+
allow_single_file = True,
656+
cfg = "host",
657+
default = Label("@bazel_tools//tools/cpp:grep-includes"),
658+
executable = True,
659+
),
654660
"_launcher": attr.label(
655661
executable = True,
656662
default = Label("//util/launcher:launcher"),
@@ -834,6 +840,22 @@ _rust_binary_attrs = {
834840
),
835841
default = False,
836842
),
843+
"stamp": attr.int(
844+
doc = dedent("""\
845+
Embed additional information into the binaries.
846+
847+
By default stamping is controlled by the --stamp flag.
848+
See https://docs.bazel.build/versions/main/user-manual.html#workspace_status
849+
and https://docs.bazel.build/versions/main/user-manual.html#flag--stamp.
850+
"""),
851+
default = -1,
852+
),
853+
"_grep_includes": attr.label(
854+
allow_single_file = True,
855+
cfg = "host",
856+
default = Label("@bazel_tools//tools/cpp:grep-includes"),
857+
executable = True,
858+
),
837859
}
838860

839861
rust_binary = rule(

rust/private/rustc.bzl

Lines changed: 66 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@ def collect_inputs(
276276
files,
277277
toolchain,
278278
cc_toolchain,
279+
feature_configuration,
279280
crate_info,
280281
dep_info,
281282
build_info):
@@ -287,12 +288,18 @@ def collect_inputs(
287288
files (list): A list of all inputs (`ctx.files`).
288289
toolchain (rust_toolchain): The current `rust_toolchain`.
289290
cc_toolchain (CcToolchainInfo): The current `cc_toolchain`.
291+
feature_configuration (FeatureConfiguration): Feature configuration to be queried.
290292
crate_info (CrateInfo): The Crate information of the crate to process build scripts for.
291293
dep_info (DepInfo): The target Crate's dependency information.
292294
build_info (BuildInfo): The target Crate's build settings.
293295
294296
Returns:
295-
tuple: See `_process_build_scripts`
297+
tuple: A tuple: A tuple of the following items:
298+
- (list): A list of all build info `OUT_DIR` File objects
299+
- (str): The `OUT_DIR` of the current build info
300+
- (File): An optional path to a generated environment file from a `cargo_build_script` target
301+
- (list): All direct and transitive build flags from the current build info
302+
- (list[File]): Linkstamp outputs.
296303
"""
297304
linker_script = getattr(file, "linker_script") if hasattr(file, "linker_script") else None
298305

@@ -310,7 +317,12 @@ def collect_inputs(
310317
for additional_input in linker_input.additional_inputs
311318
]
312319

313-
compile_inputs = depset(
320+
# Compute linkstamps. Use the inputs of the binary as inputs to the
321+
# linkstamp action to ensure linkstamps are rebuilt whenever binary inputs
322+
# change.
323+
linkstamp_outs = []
324+
325+
nolinkstamp_compile_inputs = depset(
314326
getattr(files, "data", []) +
315327
[toolchain.rustc] +
316328
toolchain.crosstool_files +
@@ -327,12 +339,52 @@ def collect_inputs(
327339
crate_info.compile_data,
328340
],
329341
)
342+
343+
if (crate_info.type in ("bin", "cdylib") and
344+
# Are linkstamps supported by the C++ toolchain?
345+
cc_common.is_enabled(feature_configuration = feature_configuration, feature_name = "linkstamps") and
346+
# Is Bazel recent enough to support Starlark linkstamps?
347+
hasattr(cc_common, "register_linkstamp_compile_action") and
348+
# The current rule doesn't define _grep_includes attribute; this
349+
# attribute is required for compiling linkstamps.
350+
hasattr(ctx.attr, "_grep_includes")):
351+
for dep in ctx.attr.deps:
352+
if CcInfo in dep and dep[CcInfo].linking_context:
353+
linking_context = dep[CcInfo].linking_context
354+
for linkstamp in linking_context.linkstamps().to_list():
355+
# The linkstamp output path is based on the binary crate
356+
# name and the input linkstamp path. This is to disambiguate
357+
# the linkstamp outputs produced by multiple binary crates
358+
# that depend on the same linkstamp. We use the same pattern
359+
# for the output name as the one used by native cc rules.
360+
out_name = "_objs/" + crate_info.output.basename + "/" + linkstamp.file().path[:-len(linkstamp.file().extension)] + "o"
361+
linkstamp_out = ctx.actions.declare_file(out_name)
362+
linkstamp_outs.append(linkstamp_out)
363+
cc_common.register_linkstamp_compile_action(
364+
actions = ctx.actions,
365+
cc_toolchain = cc_toolchain,
366+
feature_configuration = feature_configuration,
367+
grep_includes = ctx.file._grep_includes,
368+
source_file = linkstamp.file(),
369+
output_file = linkstamp_out,
370+
compilation_inputs = linkstamp.hdrs(),
371+
inputs_for_validation = nolinkstamp_compile_inputs,
372+
label_replacement = str(ctx.label),
373+
output_replacement = crate_info.output.path,
374+
)
375+
376+
compile_inputs = depset(
377+
linkstamp_outs,
378+
transitive = [
379+
nolinkstamp_compile_inputs,
380+
],
381+
)
330382
build_env_files = getattr(files, "rustc_env_files", [])
331383
compile_inputs, out_dir, build_env_file, build_flags_files = _process_build_scripts(ctx, file, crate_info, build_info, dep_info, compile_inputs)
332384
if build_env_file:
333385
build_env_files = [f for f in build_env_files] + [build_env_file]
334386
compile_inputs = depset(build_env_files, transitive = [compile_inputs])
335-
return compile_inputs, out_dir, build_env_files, build_flags_files
387+
return compile_inputs, out_dir, build_env_files, build_flags_files, linkstamp_outs
336388

337389
def construct_arguments(
338390
ctx,
@@ -344,6 +396,7 @@ def construct_arguments(
344396
feature_configuration,
345397
crate_info,
346398
dep_info,
399+
linkstamp_outs,
347400
output_hash,
348401
rust_flags,
349402
out_dir,
@@ -362,6 +415,7 @@ def construct_arguments(
362415
feature_configuration (FeatureConfiguration): Class used to construct command lines from CROSSTOOL features.
363416
crate_info (CrateInfo): The CrateInfo provider of the target crate
364417
dep_info (DepInfo): The DepInfo provider of the target crate
418+
linkstamp_outs (list): Linkstamp outputs of native dependencies
365419
output_hash (str): The hashed path of the crate root
366420
rust_flags (list): Additional flags to pass to rustc
367421
out_dir (str): The path to the output directory for the target Crate.
@@ -495,7 +549,7 @@ def construct_arguments(
495549
rustc_flags.add("--codegen=linker=" + ld)
496550
rustc_flags.add_joined("--codegen", link_args, join_with = " ", format_joined = "link-args=%s")
497551

498-
_add_native_link_flags(rustc_flags, dep_info, crate_info.type, toolchain, cc_toolchain, feature_configuration)
552+
_add_native_link_flags(rustc_flags, dep_info, linkstamp_outs, crate_info.type, toolchain, cc_toolchain, feature_configuration)
499553

500554
# These always need to be added, even if not linking this crate.
501555
add_crate_link_flags(rustc_flags, dep_info)
@@ -574,12 +628,13 @@ def rustc_compile_action(
574628
aliases = crate_info.aliases,
575629
)
576630

577-
compile_inputs, out_dir, build_env_files, build_flags_files = collect_inputs(
631+
compile_inputs, out_dir, build_env_files, build_flags_files, linkstamp_outs = collect_inputs(
578632
ctx = ctx,
579633
file = ctx.file,
580634
files = ctx.files,
581635
toolchain = toolchain,
582636
cc_toolchain = cc_toolchain,
637+
feature_configuration = feature_configuration,
583638
crate_info = crate_info,
584639
dep_info = dep_info,
585640
build_info = build_info,
@@ -595,6 +650,7 @@ def rustc_compile_action(
595650
feature_configuration = feature_configuration,
596651
crate_info = crate_info,
597652
dep_info = dep_info,
653+
linkstamp_outs = linkstamp_outs,
598654
output_hash = output_hash,
599655
rust_flags = rust_flags,
600656
out_dir = out_dir,
@@ -943,12 +999,13 @@ def _make_link_flags_default(linker_input):
943999
def _libraries_dirnames(linker_input):
9441000
return [get_preferred_artifact(lib).dirname for lib in linker_input.libraries]
9451001

946-
def _add_native_link_flags(args, dep_info, crate_type, toolchain, cc_toolchain, feature_configuration):
1002+
def _add_native_link_flags(args, dep_info, linkstamp_outs, crate_type, toolchain, cc_toolchain, feature_configuration):
9471003
"""Adds linker flags for all dependencies of the current target.
9481004
9491005
Args:
9501006
args (Args): The Args struct for a ctx.action
9511007
dep_info (DepInfo): Dependency Info provider
1008+
linkstamp_outs (list): Linkstamp outputs of native dependencies
9521009
crate_type: Crate type of the current target
9531010
toolchain (rust_toolchain): The current `rust_toolchain`
9541011
cc_toolchain (CcToolchainInfo): The current `cc_toolchain`
@@ -967,6 +1024,9 @@ def _add_native_link_flags(args, dep_info, crate_type, toolchain, cc_toolchain,
9671024

9681025
args.add_all(dep_info.transitive_noncrates, map_each = make_link_flags)
9691026

1027+
for linkstamp_out in linkstamp_outs:
1028+
args.add_all(["-C", "link-arg=%s" % linkstamp_out.path])
1029+
9701030
if crate_type in ["dylib", "cdylib"]:
9711031
# For shared libraries we want to link C++ runtime library dynamically
9721032
# (for example libstdc++.so or libc++.so).

test/unit/linkstamps/BUILD.bazel

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
load(":linkstamps_test.bzl", "linkstamps_test_suite")
2+
3+
############################ UNIT TESTS #############################
4+
linkstamps_test_suite(name = "linkstamps_test_suite")

test/unit/linkstamps/foo.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub fn main() {}

test/unit/linkstamps/linkstamp.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
// linkstamp.cc

0 commit comments

Comments
 (0)