Skip to content

"unresolved extern crate" when importing rustc crates from a locally built toolchain #12926

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
RalfJung opened this issue Aug 2, 2022 · 15 comments · Fixed by rust-lang/rust#103347

Comments

@RalfJung
Copy link
Member

RalfJung commented Aug 2, 2022

To reproduce, first locally build a rustc (./x.py build compiler --stage 2), then check out Miri, configure it for RA as shown below, and open it in vscode. Now open the src/lib.rs file. There are errors for extern crate rustc_middle; and all the other rustc crate imports: "unresolved extern crate".

A ./miri check works fine, so the crates do exist, but RA somehow fails to find them.

rust-analyzer version: rust-analyzer version: 0.3.1148-standalone (2b472f6 2022-07-31)

rustc version: locally built rustc master

relevant settings:

// Place your settings in this file to overwrite default and user settings.
{
    "rust-analyzer.rustc.source": "discover",
    "rust-analyzer.linkedProjects": [
        "./Cargo.toml",
        "./cargo-miri/Cargo.toml"
    ],
    "rust-analyzer.checkOnSave.overrideCommand": [
        "./miri",
        "check",
        "--message-format=json"
    ],
    "rust-analyzer.buildScripts.overrideCommand": [
        "./miri",
        "check",
        "--message-format=json",
    ],
    "rust-analyzer.rustfmt.extraArgs": [
        "+nightly"
    ],
}
@bjorn3
Copy link
Member

bjorn3 commented Aug 2, 2022

"rust-analyzer.rustc.source": "discover" doesn't work for linked toolchains as the rust-src component is absent. You need to manually point it to the root Cargo.toml of your rust checkout.

@RalfJung
Copy link
Member Author

RalfJung commented Aug 2, 2022

I switch between linked toolchains and downloaded toolchains all the time, so that is not a solution.

Why can't RA auto-discover linked toolchains? Miri for example auto-discovers the rust-src location for both linked and installed toolchains just fine.

@Yvan-xy
Copy link

Yvan-xy commented Oct 17, 2022

I have the same issue.

@Veykril
Copy link
Member

Veykril commented Oct 17, 2022

I'm not sure how this all works, so I'm just gonna lay out what r-a does right now for discovering. First it checks if RUST_SRC_PATH is set, and uses that if it is. Otherwise r-a invokes rustc --print sysroot with the containing directory of the workspace toml as the working directory, then checks whether {sysroot}/lib/rustlib/src/rust/library exists to use that as the path. What is miri doing differently here, what should we maybe do differently here?

@RalfJung
Copy link
Member Author

Yeah {sysroot}/lib/rustlib/src/rust/library works for normal toolchains but not for linked toolchains. I can't find where Miri even has that logic, but for a linked sysroot, the folder is $(rustc --print sysroot)/../../../library.

@RalfJung
Copy link
Member Author

RalfJung commented Oct 19, 2022

Oh, Miri doesn't have that logic any more since $(rustc --print sysroot)/lib/rustlib/src is a symlink so these things work even without doing something special on the Miri side.

Could R-A be confused by the symlink?

@Veykril
Copy link
Member

Veykril commented Oct 19, 2022

Ah wait, the rustc that is being invoked there is not the installed toolchain one right? (well in your case miri but whatever). I imagine that might be the problem then? I'll add some logging for the sysroot stuff that way you should be able to tell what might be going on here (I don't feel like building rustc myself tbh)

Edit: Actually setting RA_LOG=project_model::sysroot=debug should already log the commands that are invoked at least, maybe that shows some helpful info?

@RalfJung
Copy link
Member Author

The override in the Miri folder is set to the linked toolchain. So rustc --print sysroot in the Miri folder should print the right folder.

The rustc build will take a bit before I can provide logs.

@Veykril
Copy link
Member

Veykril commented Oct 19, 2022

How is the override specified? It might not work for r-a here depending on how you set the override and where

Edit: Looks like a directory override if I see this right? That should work fine then hmm
fwiw this is how we fetch the executable path for rustc and the like

fn get_path_for_executable(executable_name: &'static str) -> PathBuf {
// The current implementation checks three places for an executable to use:
// 1) Appropriate environment variable (erroring if this is set but not a usable executable)
// example: for cargo, this checks $CARGO environment variable; for rustc, $RUSTC; etc
// 2) `<executable_name>`
// example: for cargo, this tries just `cargo`, which will succeed if `cargo` is on the $PATH
// 3) `~/.cargo/bin/<executable_name>`
// example: for cargo, this tries ~/.cargo/bin/cargo
// It seems that this is a reasonable place to try for cargo, rustc, and rustup
let env_var = executable_name.to_ascii_uppercase();
if let Some(path) = env::var_os(&env_var) {
return path.into();
}
if lookup_in_path(executable_name) {
return executable_name.into();
}
if let Some(mut path) = home::home_dir() {
path.push(".cargo");
path.push("bin");
path.push(executable_name);
if let Some(path) = probe(path) {
return path;
}
}
executable_name.into()
}

@RalfJung
Copy link
Member Author

How is the override specified? It might not work for r-a here depending on how you set the override and where

rustup override set

@Veykril
Copy link
Member

Veykril commented Oct 19, 2022

Added some logging to emit the sysroot and rustc paths being used #13441

@RalfJung
Copy link
Member Author

The RA_LOG you suggested prints this several times

[DEBUG project_model::sysroot] Discovering sysroot for /home/r/src/rust/miri
[DEBUG project_model::sysroot] Discovering sysroot by "rustc" "--print" "sysroot"
[DEBUG project_model::sysroot] Checking sysroot: /home/r/src/rust/rustc/build/x86_64-unknown-linux-gnu/stage2/lib/rustlib/src/rust/library
[DEBUG project_model::sysroot] Discovering rustc source for /home/r/src/rust/miri/./Cargo.toml
[DEBUG project_model::sysroot] Discovering sysroot by "rustc" "--print" "sysroot"
[DEBUG project_model::sysroot] Checking for rustc source code: /home/r/src/rust/rustc/build/x86_64-unknown-linux-gnu/stage2/lib/rustlib/rustc-src/rust/compiler/rustc/Cargo.toml
[DEBUG project_model::sysroot] Discovering sysroot for /home/r/src/rust/miri/./cargo-miri
[DEBUG project_model::sysroot] Discovering sysroot by "rustc" "--print" "sysroot"
[DEBUG project_model::sysroot] Checking sysroot: /home/r/src/rust/rustc/build/x86_64-unknown-linux-gnu/stage2/lib/rustlib/src/rust/library
[DEBUG project_model::sysroot] Discovering rustc source for /home/r/src/rust/miri/./cargo-miri/Cargo.toml
[DEBUG project_model::sysroot] Discovering sysroot by "rustc" "--print" "sysroot"
[DEBUG project_model::sysroot] Checking for rustc source code: /home/r/src/rust/rustc/build/x86_64-unknown-linux-gnu/stage2/lib/rustlib/rustc-src/rust/compiler/rustc/Cargo.toml

Some of the paths it mentions indeed exist (/home/r/src/rust/rustc/build/x86_64-unknown-linux-gnu/stage2/lib/rustlib/src/rust/library) but others do not (/home/r/src/rust/rustc/build/x86_64-unknown-linux-gnu/stage2/lib/rustlib/rustc-src/rust/compiler/rustc/Cargo.toml).

@RalfJung
Copy link
Member Author

So looks like we have to extend whatever code sets up the symlink in lib/rustlib/src/rust to also set up the same symlink at lib/rustlib/rustc-src/rust?

@Veykril
Copy link
Member

Veykril commented Oct 19, 2022

Ye I would guess so? This is what r-a is doing fwiw

fn get_rustc_src(sysroot_path: &AbsPath) -> Option<ManifestPath> {
let rustc_src = sysroot_path.join("lib/rustlib/rustc-src/rust/compiler/rustc/Cargo.toml");
let rustc_src = ManifestPath::try_from(rustc_src).ok()?;
tracing::debug!("checking for rustc source code: {}", rustc_src.display());
if fs::metadata(&rustc_src).is_ok() {
Some(rustc_src)
} else {
None
}
}
fn get_rust_src(sysroot_path: &AbsPath) -> Option<AbsPathBuf> {
let rust_src = sysroot_path.join("lib/rustlib/src/rust/library");
tracing::debug!("checking sysroot library: {}", rust_src.display());
if fs::metadata(&rust_src).is_ok() {
Some(rust_src)
} else {
None
}
}

Just simply append the path to the sysroot, and I don't think there is much more we can do from our side? Though it's odd, how does rust do this then ...

@RalfJung
Copy link
Member Author

Indeed I can confirm that rust-lang/rust#103347 fixes this problem. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants