Skip to content

Commit 4bf51b3

Browse files
authored
Expand arg location in rustc_flags attribute (#809)
Expand locations in rustc_flags. Fixes #801.
1 parent a862cde commit 4bf51b3

File tree

12 files changed

+155
-27
lines changed

12 files changed

+155
-27
lines changed

cargo/cargo_build_script.bzl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ load("//rust:rust.bzl", "rust_binary")
88
load("//rust/private:rustc.bzl", "BuildInfo", "get_compilation_mode_opts", "get_linker_and_args")
99

1010
# buildifier: disable=bzl-visibility
11-
load("//rust/private:utils.bzl", "expand_locations", "find_cc_toolchain", "find_toolchain", "name_to_crate_name")
11+
load("//rust/private:utils.bzl", "expand_dict_value_locations", "find_cc_toolchain", "find_toolchain", "name_to_crate_name")
1212

1313
def get_cc_compile_env(cc_toolchain, feature_configuration):
1414
"""Gather cc environment variables from the given `cc_toolchain`
@@ -117,7 +117,7 @@ def _build_script_impl(ctx):
117117
for f in ctx.attr.crate_features:
118118
env["CARGO_FEATURE_" + f.upper().replace("-", "_")] = "1"
119119

120-
env.update(expand_locations(
120+
env.update(expand_dict_value_locations(
121121
ctx,
122122
ctx.attr.build_script_env,
123123
getattr(ctx.attr, "data", []) +

docs/defs.md

Lines changed: 7 additions & 7 deletions
Large diffs are not rendered by default.

docs/flatten.md

Lines changed: 7 additions & 7 deletions
Large diffs are not rendered by default.

examples/flag_locations/BUILD.bazel

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
load(
2+
"@rules_rust//rust:rust.bzl",
3+
"rust_test",
4+
)
5+
6+
# generate a file containing cfg flags
7+
genrule(
8+
name = "flag_generator",
9+
outs = ["generated_flag.data"],
10+
cmd = "echo --cfg=test_flag > $@",
11+
)
12+
13+
rust_test(
14+
name = "test",
15+
srcs = [
16+
"main.rs",
17+
],
18+
data = [":flag_generator"],
19+
edition = "2018",
20+
rustc_flags = [
21+
"@$(location :flag_generator)",
22+
],
23+
)

examples/flag_locations/main.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#[test]
2+
fn test() {
3+
// we should be able to read rustc args from a generated file
4+
if cfg!(test_flag) {
5+
return;
6+
}
7+
8+
unreachable!();
9+
}

rust/private/rust.bzl

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ load(
2020
"crate_name_from_attr",
2121
"dedent",
2222
"determine_output_hash",
23-
"expand_locations",
23+
"expand_dict_value_locations",
2424
"find_toolchain",
2525
)
2626

@@ -340,7 +340,7 @@ def _create_test_launcher(ctx, toolchain, output, providers):
340340

341341
# Expand the environment variables and write them to a file
342342
environ_file = ctx.actions.declare_file(launcher_filename + ".launchfiles/env")
343-
environ = expand_locations(
343+
environ = expand_dict_value_locations(
344344
ctx,
345345
getattr(ctx.attr, "env", {}),
346346
data,
@@ -620,7 +620,14 @@ _common_attrs = {
620620
"""),
621621
),
622622
"rustc_flags": attr.string_list(
623-
doc = "List of compiler flags passed to `rustc`.",
623+
doc = dedent("""\
624+
List of compiler flags passed to `rustc`.
625+
626+
These strings are subject to Make variable expansion for predefined
627+
source/output path variables like `$location`, `$execpath`, and `$rootpath`.
628+
This expansion is useful if you wish to pass a generated file of
629+
arguments to rustc: `@$(location //package:target)`.
630+
"""),
624631
),
625632
# TODO(stardoc): How do we provide additional documentation to an inherited attribute?
626633
# "name": attr.string(

rust/private/rustc.bzl

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ load("//rust/private:common.bzl", "rust_common")
2121
load(
2222
"//rust/private:utils.bzl",
2323
"crate_name_from_attr",
24-
"expand_locations",
24+
"expand_dict_value_locations",
25+
"expand_list_element_locations",
2526
"find_cc_toolchain",
2627
"get_lib_name",
2728
"get_preferred_artifact",
@@ -438,9 +439,16 @@ def construct_arguments(
438439

439440
# Tell Rustc where to find the standard library
440441
args.add_all(rust_lib_paths, before_each = "-L", format_each = "%s")
441-
442442
args.add_all(rust_flags)
443-
args.add_all(getattr(attr, "rustc_flags", []))
443+
444+
data_paths = getattr(attr, "data", []) + getattr(attr, "compile_data", [])
445+
args.add_all(
446+
expand_list_element_locations(
447+
ctx,
448+
getattr(attr, "rustc_flags", []),
449+
data_paths,
450+
),
451+
)
444452
add_edition_flags(args, crate_info)
445453

446454
# Link!
@@ -471,11 +479,10 @@ def construct_arguments(
471479
env["CARGO_BIN_EXE_" + dep_crate_info.output.basename] = dep_crate_info.output.short_path
472480

473481
# Update environment with user provided variables.
474-
env.update(expand_locations(
482+
env.update(expand_dict_value_locations(
475483
ctx,
476484
crate_info.rustc_env,
477-
getattr(attr, "data", []) +
478-
getattr(attr, "compile_data", []),
485+
data_paths,
479486
))
480487

481488
# This empty value satisfies Clippy, which otherwise complains about the

rust/private/utils.bzl

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ def _expand_location(ctx, env, data):
152152
env = env.replace(directive, "${pwd}/" + directive)
153153
return ctx.expand_location(env, data)
154154

155-
def expand_locations(ctx, env, data):
155+
def expand_dict_value_locations(ctx, env, data):
156156
"""Performs location-macro expansion on string values.
157157
158158
$(execroot ...) and $(location ...) are prefixed with ${pwd},
@@ -167,6 +167,8 @@ def expand_locations(ctx, env, data):
167167
as compilation happens in a separate sandbox folder, so when it comes time
168168
to read the file at runtime, the path is no longer valid.
169169
170+
See [`expand_location`](https://docs.bazel.build/versions/main/skylark/lib/ctx.html#expand_location) for detailed documentation.
171+
170172
Args:
171173
ctx (ctx): The rule's context object
172174
env (dict): A dict whose values we iterate over
@@ -179,6 +181,27 @@ def expand_locations(ctx, env, data):
179181
"""
180182
return dict([(k, _expand_location(ctx, v, data)) for (k, v) in env.items()])
181183

184+
def expand_list_element_locations(ctx, args, data):
185+
"""Performs location-macro expansion on a list of string values.
186+
187+
$(execroot ...) and $(location ...) are prefixed with ${pwd},
188+
which process_wrapper and build_script_runner will expand at run time
189+
to the absolute path.
190+
191+
See [`expand_location`](https://docs.bazel.build/versions/main/skylark/lib/ctx.html#expand_location) for detailed documentation.
192+
193+
Args:
194+
ctx (ctx): The rule's context object
195+
args (list): A list we iterate over
196+
data (sequence of Targets): The targets which may be referenced by
197+
location macros. This is expected to be the `data` attribute of
198+
the target, though may have other targets or attributes mixed in.
199+
200+
Returns:
201+
list: A list of arguments with expanded location macros
202+
"""
203+
return [_expand_location(ctx, arg, data) for arg in args]
204+
182205
def name_to_crate_name(name):
183206
"""Converts a build target's name into the name of its associated crate.
184207
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
load(":location_expansion_test.bzl", "location_expansion_test_suite")
2+
3+
############################ UNIT TESTS #############################
4+
location_expansion_test_suite(name = "location_expansion_test_suite")
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
"""Unittest to verify location expansion in rustc flags"""
2+
3+
load("@bazel_skylib//lib:unittest.bzl", "analysistest")
4+
load("//rust:defs.bzl", "rust_library")
5+
load("//test/unit:common.bzl", "assert_action_mnemonic", "assert_argv_contains")
6+
7+
def _location_expansion_rustc_flags_test(ctx):
8+
env = analysistest.begin(ctx)
9+
tut = analysistest.target_under_test(env)
10+
action = tut.actions[0]
11+
argv = action.argv
12+
assert_action_mnemonic(env, action, "Rustc")
13+
assert_argv_contains(env, action, "test/unit/location_expansion/mylibrary.rs")
14+
expected = "@${pwd}/" + ctx.bin_dir.path + "/test/unit/location_expansion/generated_flag.data"
15+
assert_argv_contains(env, action, expected)
16+
return analysistest.end(env)
17+
18+
location_expansion_rustc_flags_test = analysistest.make(_location_expansion_rustc_flags_test)
19+
20+
def _location_expansion_test():
21+
native.genrule(
22+
name = "flag_generator",
23+
outs = ["generated_flag.data"],
24+
cmd = "echo --cfg=test_flag > $@",
25+
)
26+
27+
rust_library(
28+
name = "mylibrary",
29+
srcs = ["mylibrary.rs"],
30+
rustc_flags = [
31+
"@$(location :flag_generator)",
32+
],
33+
compile_data = [":flag_generator"],
34+
)
35+
36+
location_expansion_rustc_flags_test(
37+
name = "location_expansion_rustc_flags_test",
38+
target_under_test = ":mylibrary",
39+
)
40+
41+
def location_expansion_test_suite(name):
42+
"""Entry-point macro called from the BUILD file.
43+
44+
Args:
45+
name: Name of the macro.
46+
"""
47+
_location_expansion_test()
48+
49+
native.test_suite(
50+
name = name,
51+
tests = [
52+
":location_expansion_rustc_flags_test",
53+
],
54+
)

0 commit comments

Comments
 (0)