Skip to content

Commit

Permalink
Allow usage of $(location ...) in rustc_env as well, to include_str!(…
Browse files Browse the repository at this point in the history
…) generated files. (#503)

The ${pwd} resolution in build_script_env is necessary during the compilation stage as well, as otherwise we can't use things like include_str!() on generated files. Starting with a test that demonstrates the issue; will follow up with a fix.
  • Loading branch information
dae committed Dec 8, 2020
1 parent 75d72ae commit 5448421
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 61 deletions.
40 changes: 2 additions & 38 deletions cargo/cargo_build_script.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,9 @@
load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "C_COMPILE_ACTION_NAME")
load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain")
load("@io_bazel_rules_rust//rust:private/rustc.bzl", "BuildInfo", "DepInfo", "get_cc_toolchain", "get_compilation_mode_opts", "get_linker_and_args")
load("@io_bazel_rules_rust//rust:private/utils.bzl", "find_toolchain")
load("@io_bazel_rules_rust//rust:private/utils.bzl", "expand_locations", "find_toolchain")
load("@io_bazel_rules_rust//rust:rust.bzl", "rust_binary")

def _expand_location(ctx, env, data):
"""A trivial helper for `_expand_locations`
Args:
ctx (ctx): The rule's context object
env (str): The value possibly containing location macros to expand.
data (sequence of Targets): see `_expand_locations`
Returns:
string: The location-macro expanded version of the string.
"""
for directive in ("$(execpath ", "$(location "):
if directive in env:
# build script runner will expand pwd to execroot for us
env = env.replace(directive, "${pwd}/" + directive)
return ctx.expand_location(env, data)

def _expand_locations(ctx, env, data):
"""Performs location-macro expansion on string values.
Note that exec-root relative locations will be exposed to the build script
as absolute paths, rather than the ordinary exec-root relative paths,
because cargo build scripts do not run in the exec root.
Args:
ctx (ctx): The rule's context object
env (dict): A dict whose values 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:
dict: A dict of environment variables with expanded location macros
"""
return dict([(k, _expand_location(ctx, v, data)) for (k, v) in env.items()])

def get_cc_compile_env(cc_toolchain, feature_configuration):
"""Gather cc environment variables from the given `cc_toolchain`
Expand Down Expand Up @@ -145,7 +109,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_locations(
ctx,
ctx.attr.build_script_env,
getattr(ctx.attr, "data", []),
Expand Down
3 changes: 2 additions & 1 deletion examples/env_locations/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ rust_test(
edition = "2018",
rustc_env = {
"SOURCE_FILE": "$(rootpath source.file)",
"GENERATED_DATA": "$(rootpath generated.data)",
"GENERATED_DATA_ROOT": "$(rootpath generated.data)",
"GENERATED_DATA_ABS": "$(execpath generated.data)",
"SOME_TOOL": "$(rootpath @com_google_protobuf//:protoc)",
},
deps = [
Expand Down
7 changes: 4 additions & 3 deletions examples/env_locations/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ fn test() {
// our source file should be readable
let source_file = std::fs::read_to_string(env!("SOURCE_FILE")).unwrap();
assert_eq!(source_file, "source\n");
// our generated data file should be readable
let generated_data = std::fs::read_to_string(env!("GENERATED_DATA")).unwrap();
assert_eq!(generated_data, "hello\n");
// our generated data file should be readable at run time and build time
let generated_data = std::fs::read_to_string(env!("GENERATED_DATA_ROOT")).unwrap();
let generated_data2 = include_str!(env!("GENERATED_DATA_ABS"));
assert_eq!(generated_data, generated_data2);
// and we should be able to read (and thus execute) our tool
assert_eq!(std::fs::read(env!("SOME_TOOL")).unwrap().is_empty(), false);
}
21 changes: 2 additions & 19 deletions rust/private/rustc.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ load(
load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain")
load(
"@io_bazel_rules_rust//rust:private/utils.bzl",
"expand_locations",
"get_lib_name",
"get_libs_for_static_executable",
"relativize",
Expand Down Expand Up @@ -293,24 +294,6 @@ def get_linker_and_args(ctx, cc_toolchain, feature_configuration, rpaths):

return ld, link_args, link_env

def _expand_locations(ctx, env, data):
"""Performs location-macro expansion on string values.
Note: Only `$(rootpath ...)` is recommended as `$(execpath ...)` will fail
in the case of generated sources.
Args:
ctx (ctx): The rule's context object
env (str): The value possibly containing location macros to expand.
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:
dict: A dict of environment variables with expanded location macros
"""
return dict([(k, ctx.expand_location(v, data)) for (k, v) in env.items()])

def _process_build_scripts(
ctx,
file,
Expand Down Expand Up @@ -545,7 +528,7 @@ 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_locations(
ctx,
crate_info.rustc_env,
getattr(rule_attrs(ctx, aspect), "data", []),
Expand Down
44 changes: 44 additions & 0 deletions rust/private/utils.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -141,3 +141,47 @@ def rule_attrs(ctx, aspect):
object.
"""
return ctx.rule.attr if aspect else ctx.attr

def _expand_location(ctx, env, data):
"""A trivial helper for `_expand_locations`
Args:
ctx (ctx): The rule's context object
env (str): The value possibly containing location macros to expand.
data (sequence of Targets): see `_expand_locations`
Returns:
string: The location-macro expanded version of the string.
"""
for directive in ("$(execpath ", "$(location "):
if directive in env:
# build script runner will expand pwd to execroot for us
env = env.replace(directive, "${pwd}/" + directive)
return ctx.expand_location(env, data)

def expand_locations(ctx, env, data):
"""Performs location-macro expansion on 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. This is necessary because include_str!() is relative
to the currently compiled file, and build scripts run relative to the
manifest dir, so we can not use execroot-relative paths.
$(rootpath ...) is unmodified, and is useful for passing in paths via
rustc_env that are encoded in the binary with env!(), but utilized at
runtime, such as in tests. The absolute paths are not usable in this case,
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.
Args:
ctx (ctx): The rule's context object
env (dict): A dict whose values 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:
dict: A dict of environment variables with expanded location macros
"""
return dict([(k, _expand_location(ctx, v, data)) for (k, v) in env.items()])

0 comments on commit 5448421

Please sign in to comment.