From 78bf242cd37016f1be153f9612d1c8cdbc557e1b Mon Sep 17 00:00:00 2001 From: jyn Date: Mon, 19 Jun 2023 15:13:01 -0500 Subject: [PATCH 1/2] bootstrap: Allow setting relative paths for build.rustc --- src/bootstrap/lib.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index d7e77aeb338f6..4602daf256e26 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -36,7 +36,7 @@ use once_cell::sync::OnceCell; use crate::builder::Kind; use crate::config::{LlvmLibunwind, TargetSelection}; use crate::util::{ - exe, libdir, mtime, output, run, run_suppressed, symlink_dir, try_run_suppressed, + absolute, exe, libdir, mtime, output, run, run_suppressed, symlink_dir, try_run_suppressed, }; mod bolt; @@ -426,8 +426,9 @@ impl Build { } let mut build = Build { - initial_rustc: config.initial_rustc.clone(), - initial_cargo: config.initial_cargo.clone(), + // Use absolute paths for these to allow setting them to e.g. build/host/stage1 + initial_rustc: absolute(&config.initial_rustc), + initial_cargo: absolute(&config.initial_cargo), initial_lld, initial_libdir, initial_sysroot: initial_sysroot.into(), From f698f3cbb3f41575b856f76791bc92c5d44b0249 Mon Sep 17 00:00:00 2001 From: jyn Date: Mon, 19 Jun 2023 15:16:58 -0500 Subject: [PATCH 2/2] bootstrap: Add and use `-Z absolute-file-paths` It's unfortunate that this hack is necessary. A short summary of the background here: - Rust-Analyzer uses `x check --json-output` to show red underlines in the editor. - There are several different Cargo workspaces in rust-lang/rust, including src/bootstrap and src/tools/miri. - Cargo runs each invocation of rustc relative to the *workspace*, not to the current working directory of cargo itself. - Rustc prints file paths relative to its current working directory. As a result, it would print things like `config.rs:43:14` instead of `src/bootstrap/config.rs`. This adds a new flag to rustc to print the files as an absolute path instead of a relative path. I went with this approach instead of one of the wrapping tools for the following reasons: 1. Cargo considers changing the working directory to be a breaking change: https://github.com/rust-lang/cargo/issues/11007#issuecomment-1290294388. They have open feature requests for adding a flag to print absolute paths, but none have been implemented. 2. Bootstrap would potentially be able to parse and rewrite the paths that cargo emits, but I don't want to hard-code Cargo's JSON output format in both bootstrap.py and rustbuild; unlike rustbuild, bootstrap.py can't use `cargo_metadata` as a library. 3. Rust-Analyzer could potentially rewrite this output, but that wouldn't fix ctrl+click on the relative path when someone runs `cargo check`. In addition to adding and using the new flag, this also adds `local_rebuild` detection to bootstrap.py, so that I could test the change. Before: ``` error[E0425]: cannot find value `MIRI_DEFAULT_ARGS` in crate `miri` --> src/bin/miri.rs:269:33 | 269 | args.splice(1..1, miri::MIRI_DEFAULT_ARGS.iter().map(ToString::to_string)); | ^^^^^^^^^^^^^^^^^ help: a constant with a similar name exists: `MIRI_DEFLT_ARGS` | ::: src/lib.rs:128:1 | 128 | pub const MIRI_DEFLT_ARGS: &[&str] = &[ | ---------------------------------- similarly named constant `MIRI_DEFLT_ARGS` defined here ``` After: ``` error[E0425]: cannot find value `MIRI_DEFAULT_ARGS` in crate `miri` --> /home/jyn/src/rust/src/tools/miri/src/bin/miri.rs:269:33 | 269 | args.splice(1..1, miri::MIRI_DEFAULT_ARGS.iter().map(ToString::to_string)); | ^^^^^^^^^^^^^^^^^ help: a constant with a similar name exists: `MIRI_DEFLT_ARGS` | ::: /home/jyn/src/rust/src/tools/miri/src/lib.rs:128:1 | 128 | pub const MIRI_DEFLT_ARGS: &[&str] = &[ | ---------------------------------- similarly named constant `MIRI_DEFLT_ARGS` defined here ``` --- compiler/rustc_driver_impl/src/lib.rs | 22 +++++++++++++++++-- compiler/rustc_interface/src/tests.rs | 1 + compiler/rustc_session/src/options.rs | 2 ++ src/bootstrap/bootstrap.py | 16 ++++++++++++++ src/bootstrap/builder.rs | 5 +++++ .../src/compiler-flags/absolute-file-paths.md | 9 ++++++++ 6 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 src/doc/unstable-book/src/compiler-flags/absolute-file-paths.md diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 2f1c78197275d..1d7971b8d5d9d 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -5,6 +5,7 @@ //! This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![feature(absolute_path)] #![feature(lazy_cell)] #![feature(decl_macro)] #![recursion_limit = "256"] @@ -303,7 +304,11 @@ fn run_compiler( registry: diagnostics_registry(), }; - match make_input(config.opts.error_format, &matches.free) { + match make_input( + config.opts.error_format, + &matches.free, + config.opts.unstable_opts.absolute_file_paths, + ) { Err(reported) => return Err(reported), Ok(Some(input)) => { config.input = input; @@ -476,6 +481,7 @@ fn make_output(matches: &getopts::Matches) -> (Option, Option Result, ErrorGuaranteed> { if free_matches.len() == 1 { let ifile = &free_matches[0]; @@ -503,7 +509,19 @@ fn make_input( Ok(Some(Input::Str { name: FileName::anon_source_code(&src), input: src })) } } else { - Ok(Some(Input::File(PathBuf::from(ifile)))) + let mut path = PathBuf::from(ifile); + if absolute_file_paths { + match std::path::absolute(path) { + Ok(p) => path = p, + Err(e) => { + return Err(early_error_no_abort( + error_format, + format!("failed to convert {ifile} to an absolute path: {e}"), + )); + } + } + } + Ok(Some(Input::File(path))) } } else { Ok(None) diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 9d0c9ec974231..748abe7ef0e5e 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -657,6 +657,7 @@ fn test_unstable_options_tracking_hash() { // Make sure that changing an [UNTRACKED] option leaves the hash unchanged. // tidy-alphabetical-start + untracked!(absolute_file_paths, true); untracked!(assert_incr_state, Some(String::from("loaded"))); untracked!(deduplicate_diagnostics, false); untracked!(dep_tasks, true); diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index edf95949d3234..175868cdc202c 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1352,6 +1352,8 @@ options! { // - src/doc/unstable-book/src/compiler-flags // tidy-alphabetical-start + absolute_file_paths: bool = (false, parse_bool, [UNTRACKED], + "use absolute file paths in diagnostics, not relative paths (default: no)"), allow_features: Option> = (None, parse_opt_comma_list, [TRACKED], "only allow the listed language features to be enabled in code (comma separated)"), always_encode_mir: bool = (false, parse_bool, [TRACKED], diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 473fdbe1edc27..95ecc3efdc656 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -474,6 +474,7 @@ def __init__(self): self.verbose = False self.git_version = None self.nix_deps_dir = None + self.local_rebuild = False self._should_fix_bins_and_dylibs = None def download_toolchain(self): @@ -894,6 +895,10 @@ def build_bootstrap(self, color, warnings, verbose_count): if target_linker is not None: env["RUSTFLAGS"] += " -C linker=" + target_linker env["RUSTFLAGS"] += " -Wrust_2018_idioms -Wunused_lifetimes" + # Make sure that rust-analyzer can map error diagnostics to the file. + # cfg(bootstrap) + if self.local_rebuild: + env["RUSTFLAGS"] += " -Zabsolute-file-paths" if warnings == "default": deny_warnings = self.get_toml("deny-warnings", "rust") != "false" else: @@ -1054,6 +1059,17 @@ def bootstrap(args): if not os.path.exists(build.build_dir): os.makedirs(build.build_dir) + build.local_rebuild = build.get_toml("local_rebuild", "build") + if build.local_rebuild is None and not build.rustc().startswith(build.bin_root()): + with open(os.path.join(build.rust_root, "src", "version")) as f: + expected_version = f.read().split(".")[:2] + output = require([build.rustc(), "--version"]).decode(sys.getdefaultencoding()) + actual_version = output.split(" ")[1].split(".")[:2] + if expected_version == actual_version: + if build.verbose: + print("auto-detected local-rebuild {}".format(actual_version)) + build.local_rebuild = True + # Fetch/build the bootstrap build.download_toolchain() sys.stdout.flush() diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 7c8e3536df588..913ab12ec4e9d 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -1392,6 +1392,11 @@ impl<'a> Builder<'a> { // cargo would implicitly add it, it was discover that sometimes bootstrap only use // `rustflags` without `cargo` making it required. rustflags.arg("-Zunstable-options"); + // Make ctrl+click, etc. work with workspaces other than the root workspace. + // cfg(bootstrap) + if stage > 0 { + rustflags.arg("-Zabsolute-file-paths"); + } for (restricted_mode, name, values) in EXTRA_CHECK_CFGS { if *restricted_mode == None || *restricted_mode == Some(mode) { // Creating a string of the values by concatenating each value: diff --git a/src/doc/unstable-book/src/compiler-flags/absolute-file-paths.md b/src/doc/unstable-book/src/compiler-flags/absolute-file-paths.md new file mode 100644 index 0000000000000..74e74f3662ca0 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/absolute-file-paths.md @@ -0,0 +1,9 @@ +# `absolute-file-paths` + +This features is currently perma-unstable, with no tracking issue. + +------------------------ + +This feature allows you to configure rustc to print diagnostics and other output using absolute file paths, not relative file paths. + +Set `-Zabsolute-file-paths` to enable this feature.