diff --git a/cargo/cargo_build_script.bzl b/cargo/cargo_build_script.bzl index 5b197a58b0..171faa2f11 100644 --- a/cargo/cargo_build_script.bzl +++ b/cargo/cargo_build_script.bzl @@ -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` @@ -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", []), diff --git a/examples/env_locations/BUILD b/examples/env_locations/BUILD index b82f60c69e..9da9854c65 100644 --- a/examples/env_locations/BUILD +++ b/examples/env_locations/BUILD @@ -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 = [ diff --git a/examples/env_locations/main.rs b/examples/env_locations/main.rs index 4905472f7e..ef84add6d2 100644 --- a/examples/env_locations/main.rs +++ b/examples/env_locations/main.rs @@ -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); } diff --git a/rust/private/rustc.bzl b/rust/private/rustc.bzl index 26da08fe49..bd917d03c7 100644 --- a/rust/private/rustc.bzl +++ b/rust/private/rustc.bzl @@ -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", @@ -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, @@ -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", []), diff --git a/rust/private/utils.bzl b/rust/private/utils.bzl index 8aaae9b5ad..154b7c6fb8 100644 --- a/rust/private/utils.bzl +++ b/rust/private/utils.bzl @@ -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()])