diff --git a/rust/private/rustdoc_test.bzl b/rust/private/rustdoc_test.bzl index 9a6a0efac4..777def8e6e 100644 --- a/rust/private/rustdoc_test.bzl +++ b/rust/private/rustdoc_test.bzl @@ -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 @@ -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 @@ -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("--") @@ -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. diff --git a/test/rustdoc_generated_inputs/BUILD.bazel b/test/rustdoc_generated_inputs/BUILD.bazel new file mode 100644 index 0000000000..dfbf72bdfa --- /dev/null +++ b/test/rustdoc_generated_inputs/BUILD.bazel @@ -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"], +) diff --git a/test/rustdoc_generated_inputs/input.bzl b/test/rustdoc_generated_inputs/input.bzl new file mode 100644 index 0000000000..c5230320e8 --- /dev/null +++ b/test/rustdoc_generated_inputs/input.bzl @@ -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"), + }, +) diff --git a/test/rustdoc_generated_inputs/lib.rs b/test/rustdoc_generated_inputs/lib.rs new file mode 100644 index 0000000000..1f9c4b9a18 --- /dev/null +++ b/test/rustdoc_generated_inputs/lib.rs @@ -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)]