Skip to content

Commit 8cb9059

Browse files
authored
mix in label in crate hash computation (#1083)
Consider the situation where we have two variants of the same crate: ``` rust_library( name = "foo", srcs = ["foo.rs"], ) rust_library( name = "foo2", crate_name = "foo", srcs = ["foo.rs"], ) ``` A use case for this is for example when we want to define different variants of a crate using different feature sets, e.g., define a rustc_private non-std variant of a vendored crate of the standard library together with a more standard version of the vendored crate that requires the standard library. Currently, this is a fragile definition since the output rlib filename of both of these is the same, e.g., `libfoo-$HASH.rlib`, where `$HASH` is derived from the crate root source filename, in this case `foo.rs`. So whenever we have a Bazel query that includes both of these, the build may fail with errors like: ``` ERROR: file 'test/unit/crate_variants/libfoo-717083168.rlib' is generated by these conflicting actions: Label: //test/unit/crate_variants:foo2, //test/unit/crate_variants:foo ``` This patch reduces the risk of such output filename collisions by mixing in the rule label in the output hash calculation.
1 parent 6630fd5 commit 8cb9059

File tree

10 files changed

+68
-8
lines changed

10 files changed

+68
-8
lines changed

proto/proto.bzl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ def _rust_proto_compile(protos, descriptor_sets, imports, crate_name, ctx, is_gr
205205
srcs.append(lib_rs)
206206

207207
# And simulate rust_library behavior
208-
output_hash = determine_output_hash(lib_rs)
208+
output_hash = determine_output_hash(lib_rs, ctx.label)
209209
rust_lib = ctx.actions.declare_file("%s/lib%s-%s.rlib" % (
210210
output_dir,
211211
crate_name,

rust/private/clippy.bzl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ def _clippy_aspect_impl(target, ctx):
9797
crate_info = crate_info,
9898
dep_info = dep_info,
9999
linkstamp_outs = linkstamp_outs,
100-
output_hash = determine_output_hash(crate_info.root),
100+
output_hash = determine_output_hash(crate_info.root, ctx.label),
101101
rust_flags = [],
102102
out_dir = out_dir,
103103
build_env_files = build_env_files,

rust/private/rust.bzl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ def _rust_library_common(ctx, crate_type):
249249
# to include the library with a specific filename into a larger application.
250250
# (see https://github.com/bazelbuild/rules_rust/issues/405#issuecomment-993089889 for more details)
251251
if crate_type != "cdylib":
252-
output_hash = determine_output_hash(crate_root)
252+
output_hash = determine_output_hash(crate_root, ctx.label)
253253
else:
254254
output_hash = None
255255

rust/private/utils.bzl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,18 +123,19 @@ def get_lib_name(lib):
123123
else:
124124
return libname
125125

126-
def determine_output_hash(crate_root):
126+
def determine_output_hash(crate_root, label):
127127
"""Generates a hash of the crate root file's path.
128128
129129
Args:
130130
crate_root (File): The crate's root file (typically `lib.rs`).
131+
label (Label): The label of the target.
131132
132133
Returns:
133134
str: A string representation of the hash.
134135
"""
135136

136137
# Take the absolute value of hash() since it could be negative.
137-
h = hash(crate_root.path)
138+
h = hash(crate_root.path) + hash(repr(label))
138139
if h < 0:
139140
h = -h
140141
return repr(h)

test/BUILD.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ load(
55

66
rule_test(
77
name = "hello_lib_rule_test",
8-
generates = ["libhello_lib-145651613.rlib"],
8+
generates = ["libhello_lib-683707109.rlib"],
99
rule = "//test/rust:hello_lib",
1010
)
1111

test/unit/crate_name/crate_name_test.bzl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,14 @@ def _slib_library_name_test_impl(ctx):
6161
6262
Checks that the extra hash value appended to the library filename only
6363
contains one dash. Previously, the hash for `slib` was negative,
64-
resulting in an extra dash in the filename (--codegen_extra_filename=--517943325).
64+
resulting in an extra dash in the filename (--codegen_extra_filename=--NUM).
6565
6666
Args:
6767
ctx: rule context.
6868
"""
6969
env = analysistest.begin(ctx)
7070
tut = analysistest.target_under_test(env)
71-
assert_argv_contains(env, tut.actions[0], "--codegen=extra-filename=-517943325")
71+
assert_argv_contains(env, tut.actions[0], "--codegen=extra-filename=-2102077805")
7272
return analysistest.end(env)
7373

7474
default_crate_name_library_test = analysistest.make(

test/unit/crate_variants/BUILD.bazel

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

test/unit/crate_variants/bar.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
"""Unittests for rust rules."""
2+
3+
load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts")
4+
load("//rust:defs.bzl", "rust_common", "rust_library")
5+
6+
def _crate_variants_test_impl(ctx):
7+
env = analysistest.begin(ctx)
8+
tut = analysistest.target_under_test(env)
9+
transitive_crate_outputs = tut[rust_common.dep_info].transitive_crate_outputs.to_list()
10+
11+
# Both variants of "foo" occur as dependencies.
12+
asserts.equals(env, len(transitive_crate_outputs), 2)
13+
return analysistest.end(env)
14+
15+
crate_variants_test = analysistest.make(_crate_variants_test_impl)
16+
17+
def _crate_variants_test():
18+
rust_library(
19+
name = "foo",
20+
srcs = ["foo.rs"],
21+
)
22+
23+
rust_library(
24+
name = "foo2",
25+
crate_name = "foo",
26+
srcs = ["foo.rs"],
27+
)
28+
29+
rust_library(
30+
name = "bar",
31+
srcs = ["bar.rs"],
32+
deps = [":foo", ":foo2"],
33+
)
34+
35+
crate_variants_test(
36+
name = "crate_variants_test",
37+
target_under_test = ":bar",
38+
)
39+
40+
def crate_variants_test_suite(name):
41+
"""Entry-point macro called from the BUILD file.
42+
43+
Args:
44+
name: Name of the macro.
45+
"""
46+
_crate_variants_test()
47+
48+
native.test_suite(
49+
name = name,
50+
tests = [
51+
":crate_variants_test",
52+
],
53+
)

test/unit/crate_variants/foo.rs

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

0 commit comments

Comments
 (0)