Skip to content

Commit

Permalink
Expand arg location in rustc_flags attribute (#809)
Browse files Browse the repository at this point in the history
Expand locations in rustc_flags.
Fixes #801.
  • Loading branch information
sayrer committed Jul 1, 2021
1 parent a862cde commit 4bf51b3
Show file tree
Hide file tree
Showing 12 changed files with 155 additions and 27 deletions.
4 changes: 2 additions & 2 deletions cargo/cargo_build_script.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ load("//rust:rust.bzl", "rust_binary")
load("//rust/private:rustc.bzl", "BuildInfo", "get_compilation_mode_opts", "get_linker_and_args")

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

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

env.update(expand_locations(
env.update(expand_dict_value_locations(
ctx,
ctx.attr.build_script_env,
getattr(ctx.attr, "data", []) +
Expand Down
14 changes: 7 additions & 7 deletions docs/defs.md

Large diffs are not rendered by default.

14 changes: 7 additions & 7 deletions docs/flatten.md

Large diffs are not rendered by default.

23 changes: 23 additions & 0 deletions examples/flag_locations/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
load(
"@rules_rust//rust:rust.bzl",
"rust_test",
)

# generate a file containing cfg flags
genrule(
name = "flag_generator",
outs = ["generated_flag.data"],
cmd = "echo --cfg=test_flag > $@",
)

rust_test(
name = "test",
srcs = [
"main.rs",
],
data = [":flag_generator"],
edition = "2018",
rustc_flags = [
"@$(location :flag_generator)",
],
)
9 changes: 9 additions & 0 deletions examples/flag_locations/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#[test]
fn test() {
// we should be able to read rustc args from a generated file
if cfg!(test_flag) {
return;
}

unreachable!();
}
13 changes: 10 additions & 3 deletions rust/private/rust.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ load(
"crate_name_from_attr",
"dedent",
"determine_output_hash",
"expand_locations",
"expand_dict_value_locations",
"find_toolchain",
)

Expand Down Expand Up @@ -340,7 +340,7 @@ def _create_test_launcher(ctx, toolchain, output, providers):

# Expand the environment variables and write them to a file
environ_file = ctx.actions.declare_file(launcher_filename + ".launchfiles/env")
environ = expand_locations(
environ = expand_dict_value_locations(
ctx,
getattr(ctx.attr, "env", {}),
data,
Expand Down Expand Up @@ -620,7 +620,14 @@ _common_attrs = {
"""),
),
"rustc_flags": attr.string_list(
doc = "List of compiler flags passed to `rustc`.",
doc = dedent("""\
List of compiler flags passed to `rustc`.
These strings are subject to Make variable expansion for predefined
source/output path variables like `$location`, `$execpath`, and `$rootpath`.
This expansion is useful if you wish to pass a generated file of
arguments to rustc: `@$(location //package:target)`.
"""),
),
# TODO(stardoc): How do we provide additional documentation to an inherited attribute?
# "name": attr.string(
Expand Down
19 changes: 13 additions & 6 deletions rust/private/rustc.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ load("//rust/private:common.bzl", "rust_common")
load(
"//rust/private:utils.bzl",
"crate_name_from_attr",
"expand_locations",
"expand_dict_value_locations",
"expand_list_element_locations",
"find_cc_toolchain",
"get_lib_name",
"get_preferred_artifact",
Expand Down Expand Up @@ -438,9 +439,16 @@ def construct_arguments(

# Tell Rustc where to find the standard library
args.add_all(rust_lib_paths, before_each = "-L", format_each = "%s")

args.add_all(rust_flags)
args.add_all(getattr(attr, "rustc_flags", []))

data_paths = getattr(attr, "data", []) + getattr(attr, "compile_data", [])
args.add_all(
expand_list_element_locations(
ctx,
getattr(attr, "rustc_flags", []),
data_paths,
),
)
add_edition_flags(args, crate_info)

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

# Update environment with user provided variables.
env.update(expand_locations(
env.update(expand_dict_value_locations(
ctx,
crate_info.rustc_env,
getattr(attr, "data", []) +
getattr(attr, "compile_data", []),
data_paths,
))

# This empty value satisfies Clippy, which otherwise complains about the
Expand Down
25 changes: 24 additions & 1 deletion rust/private/utils.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ def _expand_location(ctx, env, data):
env = env.replace(directive, "${pwd}/" + directive)
return ctx.expand_location(env, data)

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

def expand_list_element_locations(ctx, args, data):
"""Performs location-macro expansion on a list of string values.
$(execroot ...) and $(location ...) are prefixed with ${pwd},
which process_wrapper and build_script_runner will expand at run time
to the absolute path.
See [`expand_location`](https://docs.bazel.build/versions/main/skylark/lib/ctx.html#expand_location) for detailed documentation.
Args:
ctx (ctx): The rule's context object
args (list): A list we iterate over
data (sequence of Targets): The targets which may be referenced by
location macros. This is expected to be the `data` attribute of
the target, though may have other targets or attributes mixed in.
Returns:
list: A list of arguments with expanded location macros
"""
return [_expand_location(ctx, arg, data) for arg in args]

def name_to_crate_name(name):
"""Converts a build target's name into the name of its associated crate.
Expand Down
4 changes: 4 additions & 0 deletions test/unit/location_expansion/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
load(":location_expansion_test.bzl", "location_expansion_test_suite")

############################ UNIT TESTS #############################
location_expansion_test_suite(name = "location_expansion_test_suite")
54 changes: 54 additions & 0 deletions test/unit/location_expansion/location_expansion_test.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
"""Unittest to verify location expansion in rustc flags"""

load("@bazel_skylib//lib:unittest.bzl", "analysistest")
load("//rust:defs.bzl", "rust_library")
load("//test/unit:common.bzl", "assert_action_mnemonic", "assert_argv_contains")

def _location_expansion_rustc_flags_test(ctx):
env = analysistest.begin(ctx)
tut = analysistest.target_under_test(env)
action = tut.actions[0]
argv = action.argv
assert_action_mnemonic(env, action, "Rustc")
assert_argv_contains(env, action, "test/unit/location_expansion/mylibrary.rs")
expected = "@${pwd}/" + ctx.bin_dir.path + "/test/unit/location_expansion/generated_flag.data"
assert_argv_contains(env, action, expected)
return analysistest.end(env)

location_expansion_rustc_flags_test = analysistest.make(_location_expansion_rustc_flags_test)

def _location_expansion_test():
native.genrule(
name = "flag_generator",
outs = ["generated_flag.data"],
cmd = "echo --cfg=test_flag > $@",
)

rust_library(
name = "mylibrary",
srcs = ["mylibrary.rs"],
rustc_flags = [
"@$(location :flag_generator)",
],
compile_data = [":flag_generator"],
)

location_expansion_rustc_flags_test(
name = "location_expansion_rustc_flags_test",
target_under_test = ":mylibrary",
)

def location_expansion_test_suite(name):
"""Entry-point macro called from the BUILD file.
Args:
name: Name of the macro.
"""
_location_expansion_test()

native.test_suite(
name = name,
tests = [
":location_expansion_rustc_flags_test",
],
)
1 change: 1 addition & 0 deletions test/unit/location_expansion/mylibrary.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

2 changes: 1 addition & 1 deletion util/launcher/launcher_main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ fn environ() -> BTreeMap<String, String> {
let file = File::open(env_path).expect("Failed to load the environment file");

// Variables will have the `${pwd}` variable replaced which is rendered by
// `@rules_rust//rust/private:util.bzl::expand_locations`
// `@rules_rust//rust/private:util.bzl::expand_dict_value_locations`
let pwd = std::env::current_dir().expect("Failed to get current working directory");
let pwd_str = pwd.to_string_lossy();

Expand Down

0 comments on commit 4bf51b3

Please sign in to comment.