Skip to content
Merged
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
58 changes: 6 additions & 52 deletions rust/private/rustdoc_test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,7 @@ load("//rust/private:providers.bzl", "CrateInfo")
load("//rust/private:rustdoc.bzl", "rustdoc_compile_action")
load("//rust/private:utils.bzl", "dedent", "find_toolchain", "transform_deps")

def _collect_library_roots(roots, deps):
for dep in deps.to_list():
for lib in dep.libraries:
for artifact in [lib.static_library, lib.pic_static_library]:
if artifact:
roots.append(artifact.root.path)
for input in dep.additional_inputs:
roots.append(input.root.path)

def _construct_writer_arguments(ctx, test_runner, opt_test_params, action, crate_info):
def _construct_writer_arguments(ctx, test_runner, opt_test_params, action):
"""Construct arguments and environment variables specific to `rustdoc_test_writer`.

This is largely solving for the fact that tests run from a runfiles directory
Expand All @@ -41,7 +32,6 @@ def _construct_writer_arguments(ctx, test_runner, opt_test_params, action, crate
test_runner (File): The test_runner output file declared by `rustdoc_test`.
opt_test_params (File): An output file we can optionally use to store params for `rustdoc`.
action (struct): Action arguments generated by `rustdoc_compile_action`.
crate_info (CrateInfo): The provider of the crate who's docs are being tested.

Returns:
tuple: A tuple of `rustdoc_test_writer` specific inputs
Expand All @@ -65,46 +55,11 @@ def _construct_writer_arguments(ctx, test_runner, opt_test_params, action, crate
for var in action.env.keys():
writer_args.add("--action_env={}".format(var))

# Since the test runner will be running from a runfiles directory, the
# paths originally generated for the build action will not map to any
# files. To ensure rustdoc can find the appropriate dependencies, the
# file roots are identified and tracked for each dependency so it can be
# stripped from the test runner.

# Collect and dedupe all of the file roots in a list before appending
# them to args to prevent generating a large amount of identical args
roots = [crate_info.output.root.path]
for dep in crate_info.deps.to_list() + crate_info.proc_macro_deps.to_list():
dep_crate_info = getattr(dep, "crate_info", None)
dep_dep_info = getattr(dep, "dep_info", None)
dep_cc_info = getattr(dep, "cc_info", None)
if dep_crate_info:
roots.append(dep_crate_info.output.root.path)
if dep_dep_info:
for direct_dep in dep_dep_info.direct_crates.to_list():
roots.append(direct_dep.dep.output.root.path)
for transitive_dep in dep_dep_info.transitive_crates.to_list():
roots.append(transitive_dep.output.root.path)
_collect_library_roots(roots, dep_dep_info.transitive_noncrates)
if dep_cc_info:
_collect_library_roots(roots, dep_cc_info.linking_context.linker_inputs)

# The cc_toolchain runtime libs (see rustdoc.bzl) are built in their own
# configuration, so their root differs from every crate root collected
# above. Without stripping it too, the `-Lnative=` search path rustc emits
# for them stays an execroot path that does not exist under runfiles, and
# the linker reports "unable to find library".
#
# Source files have an empty root, and they need no stripping: their
# `-Lnative=` path is already workspace-relative. Skip them -- an empty
# root would add `--strip_substring=/`, and the writer applies these as
# plain string replacements, so that would delete every `/` in every
# argument.
for lib in action.static_runtime_libs:
if lib.root.path:
roots.append(lib.root.path)

writer_args.add_all(roots, format_each = "--strip_substring=%s/", uniquify = True)
# Every declared input is staged in runfiles. Strip each generated root,
# including compiler tools built in an execution configuration. Empty roots
# are source files: stripping "/" would corrupt every path in the command.
roots = {file.root.path: True for file in action.inputs.to_list() if file.root.path}
writer_args.add_all(roots.keys(), format_each = "--strip_substring=%s/")

# Indicate that the rustdoc_test args are over.
writer_args.add("--")
Expand Down Expand Up @@ -287,7 +242,6 @@ def _legacy_rust_doc_test_impl(ctx, toolchain, crate_info):
test_runner = test_runner,
opt_test_params = opt_test_params,
action = action,
crate_info = crate_info,
)

# Allow writer environment variables to override those from the action.
Expand Down
31 changes: 31 additions & 0 deletions test/rustdoc_generated_inputs/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
load("@bazel_skylib//rules:write_file.bzl", "write_file")
load("//rust:defs.bzl", "rust_doc_test", "rust_library")
load(":input.bzl", "exec_file")

rust_doc_test(
name = "generated_environment_test",
crate = ":lib",
# Legacy doctests require directory runfiles on Windows (#1156).
target_compatible_with = select({
"@platforms//os:windows": ["@platforms//:incompatible"],
"//conditions:default": [],
}),
)

rust_library(
name = "lib",
srcs = ["lib.rs"],
edition = "2021",
rustc_env_files = [":exec_environment"],
)

exec_file(
name = "exec_environment",
src = ":environment",
)

write_file(
name = "environment",
out = "environment.txt",
content = ["GENERATED_VALUE=from the execution configuration"],
)
11 changes: 11 additions & 0 deletions test/rustdoc_generated_inputs/input.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"""Expose an environment file built in an execution configuration."""

def _exec_file_impl(ctx):
return [DefaultInfo(files = ctx.attr.src[DefaultInfo].files)]

exec_file = rule(
implementation = _exec_file_impl,
attrs = {
"src": attr.label(mandatory = True, cfg = "exec"),
},
)
10 changes: 10 additions & 0 deletions test/rustdoc_generated_inputs/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//! The wrapper must find generated environment files after moving into runfiles.
//!
//! Unlike the runtime libraries covered by #4220, this file has no crate or
//! C++ dependency provider from which the legacy launcher could infer its root.
//!
//! ```
//! assert_eq!(env!("GENERATED_VALUE"), "from the execution configuration");
//! ```

#![warn(rust_2018_idioms)]
Loading