Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 35 additions & 6 deletions rust/private/rustc.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -965,12 +965,16 @@ def has_location_expansion(values):
return False

def _args_map_bin_dir(file):
"""Extract `bazel-out/<config>/bin` from a File whose path lives in the configuration's bin directory.
"""Return a generated File's output root in its consuming action's layout.

Evaluated at action-execution time so that Bazel's path mapping (`--experimental_output_paths=strip`) can
rewrite the `<config>` segment to `cfg` before we slice it off.
`File.root.path` provides the root depth, including sibling repositories;
`File.path` carries the configuration selected by the action's path mapper.
"""
return "/".join(file.path.split("/", 3)[:3])
return "/".join(file.path.split("/")[:len(file.root.path.split("/"))])

def _args_map_output_configuration(file):
"""Return the output configuration in the consuming action's path layout."""
return _args_map_bin_dir(file).split("/")[-2]

def construct_arguments(
*,
Expand Down Expand Up @@ -1105,6 +1109,16 @@ def construct_arguments(
for build_env_file in build_env_files:
process_wrapper_flags.add("--env-file", build_env_file)

# Source env files have no output configuration to substitute.
if not build_env_file.is_source:
process_wrapper_flags.add_all(
[build_env_file],
before_each = "--subst",
format_each = "rustc_env_file:" + build_env_file.short_path.replace("%", "%25").replace("=", "%3D") + "=%s",
map_each = _args_map_output_configuration,
expand_directories = False,
)

process_wrapper_flags.add_all(build_flags_files, before_each = "--arg-file")

all_allowed_unstable_features = []
Expand Down Expand Up @@ -1362,8 +1376,14 @@ def construct_arguments(
# If linker_type is not explicitly set, infer from which linker is actually being used
ld_is_direct_driver = False

# Metadata does not link, so avoid expanding string-valued linker flags.
adds_linker_args = not build_metadata and (
("link" in emit and crate_info.type not in ["rlib", "lib"]) or
add_flags_for_binary
)

# Link!
if ("link" in emit and crate_info.type not in ["rlib", "lib"]) or add_flags_for_binary:
if adds_linker_args:
# Rust's built-in linker can handle linking wasm files. We don't want to attempt to use the cc
# linker since it won't understand.
compilation_mode = ctx.var["COMPILATION_MODE"]
Expand Down Expand Up @@ -1645,7 +1665,16 @@ def construct_arguments(
rustc_path = rustc_path,
rustc_flags = rustc_flags,
extra_rustc_flags = rust_flags_args,
supports_path_mapping = not target_has_location_expansion,
# Native linker selection and C/C++ feature expansion flatten generated
# paths into strings that Bazel cannot remap. Pure Wasm remains mappable.
supports_path_mapping = not target_has_location_expansion and not (
adds_linker_args and
(include_link_flags or force_depend_on_objects) and
Comment thread
tamird marked this conversation as resolved.
(
toolchain.target_arch not in ("wasm32", "wasm64") or
bool(dep_info.transitive_noncrates)
Comment thread
tamird marked this conversation as resolved.
)
),
all = all_args,
)

Expand Down
3 changes: 2 additions & 1 deletion rust/private/rustdoc.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,8 @@ def rustdoc_compile_action(
build_flags_files = build_flags_files,
emit = [],
remap_path_prefix = None,
add_flags_for_binary = True,
# Documentation does not link; doctest compilation does.
add_flags_for_binary = is_test,
include_link_flags = is_test,
force_depend_on_objects = is_test,
skip_expanding_rustc_env = True,
Expand Down
7 changes: 7 additions & 0 deletions test/unit/metadata_output_groups/metadata_output_groups.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ def _metadata_output_groups_present_test_impl(ctx):
"Expected %s to end with .rustc-output" % rustc_rmeta_output[0],
)

metadata_action = [action for action in tut.actions if action.mnemonic == "RustcMetadata"][0]
asserts.equals(env, [], [
arg
for arg in metadata_action.argv
if arg.startswith("--codegen=linker=") or arg.startswith("--codegen=link-arg=")
])

return analysistest.end(env)

def _metadata_output_groups_missing_test_impl(ctx):
Expand Down
4 changes: 4 additions & 0 deletions test/unit/native_deps/native_deps_test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,10 @@ def _bin_has_native_dep_and_alwayslink_test_impl(ctx, use_cc_linker):
link_args = _extract_linker_args(action.argv)
bin_dir = get_bin_dir_from_action(action)

# Native linking must retain the same output root as its declared output.
output_bin_dir = action.outputs.to_list()[0].path.split("/bin/", 1)[0] + "/bin"
asserts.equals(env, output_bin_dir, bin_dir)

# Validate bin_dir structure (ignoring ST-{hash} suffix from config transitions)
_assert_bin_dir_structure(env, ctx, bin_dir, toolchain)

Expand Down
1 change: 1 addition & 0 deletions test/unit/rustdoc/rustdoc_unit_test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ def _common_rustdoc_checks(env, tut):
# `Rustdoc` actions
assert_argv_contains_prefix_not(env, action, "--remap-path-prefix")
assert_argv_contains_prefix_not(env, action, "--emit")
assert_argv_contains_prefix_not(env, action, "--codegen=linker=")

def _rustdoc_for_lib_test_impl(ctx):
env = analysistest.begin(ctx)
Expand Down
52 changes: 23 additions & 29 deletions tools/rust_analyzer/env_file.bzl
Original file line number Diff line number Diff line change
@@ -1,32 +1,27 @@
"""A `rustc_env_files`-format rule whose VALUE is a path-mapping-aware file path."""

load("@bazel_features//:features.bzl", "bazel_features")

def _arg_map_pair(value):
key, file = value
return "{}=${{pwd}}/{}".format(key, file.path)
"""A `rustc_env_files`-format rule whose file paths follow the consuming action."""

def _env_file_impl(ctx):
out = ctx.actions.declare_file(ctx.label.name + ".rustc_env")
content = ctx.actions.args()
content.set_param_file_format("multiline")
content.add_all(
[(ctx.attr.key, ctx.file.src)],
map_each = _arg_map_pair,
expand_directories = False,
)

if bazel_features.rules.write_action_has_execution_requirements:
ctx.actions.write(
output = out,
content = content,
execution_requirements = {"supports-path-mapping": ""},
)
else:
ctx.actions.write(
output = out,
content = content,
# ':' reserves this namespace; escape '%' first to keep keys injective.
substitution = "rustc_env_file:" + out.short_path.replace("%", "%25").replace("=", "%3D")
source_root = ctx.file.src.root.path
root_components = source_root.split("/")

# Generated inputs share this rule's configuration; defer that component to
# the consuming action while preserving their repository and output root.
source_path = (
ctx.file.src.path if ctx.file.src.is_source else "{}/${{{}}}/{}/{}".format(
"/".join(root_components[:-2]),
substitution,
root_components[-1],
Comment thread
tamird marked this conversation as resolved.
ctx.file.src.path[len(source_root) + 1:],
)
)
ctx.actions.write(
output = out,
content = "{}=${{pwd}}/{}\n".format(ctx.attr.key, source_path),
)
return [DefaultInfo(files = depset([out]))]

env_file = rule(
Expand All @@ -43,11 +38,10 @@ env_file = rule(
),
},
doc = """\
Emit a one-line `KEY=${pwd}/<src.path>\\n` file suitable for `rust_library`'s
`rustc_env_files` attribute. The path is generated through `Args.add_all`'s
`format_each` so Bazel's path mapping (`--experimental_output_paths=strip`)
rewrites it before the action runs, and the `${pwd}` prefix is later resolved
to the exec_root by `process_wrapper`'s env-block substitution.
Emit a `KEY=${pwd}/<source-path>\\n` file suitable for `rustc_env_files`.
Generated inputs share this rule's configuration. A File-backed substitution
selects the consuming action's mapped or unmapped configuration while preserving
the input's repository and output root.

Pair with a matching `compile_data = [src]` on the consumer crate and use
`include_str!(env!("KEY"))` in Rust to embed the file's content at compile
Expand Down
Loading