Following symlinks when computing default sysroot

I had a problem with std crate not being found. I opened a request for help in the users list and headed over to IRC as well.

For context I installed rust 1.12 from the tarball (and tried using rustup as well) into /usr/local/ I just found with the help of some of the guys in the #rust-beginners channel that the reason std could not be found was because my sysroot as output by rustc --print sysroot was /usr/local/stow/yabar/. I also noticed that if I set the sysroot manually in the rustc command line all was fine and the std crate would have been found. With this I started scratching my head and went to dig for an answer in the rustc source code.

It turns out that if no sysroot is defined, rustc will try to find a default sysroot.

This is the function that does the job (in src/librustc/session/filesearch.rs):

pub fn get_or_default_sysroot() -> PathBuf {
    // Follow symlinks.  If the resolved path is relative, make it absolute.
    fn canonicalize(path: Option<PathBuf>) -> Option<PathBuf> {
        path.and_then(|path| {
            match fs::canonicalize(&path) {
                // See comments on this target function, but the gist is that
                // gcc chokes on verbatim paths which fs::canonicalize generates
                // so we try to avoid those kinds of paths.
                Ok(canon) => Some(rustcfs::fix_windows_verbatim_for_gcc(&canon)),
                Err(e) => bug!("failed to get realpath: {}", e),
            }
        })
    }

    match canonicalize(env::current_exe().ok()) {
        Some(mut p) => { p.pop(); p.pop(); p }
        None => bug!("can't determine value for sysroot")
    }
}

As soon as I saw the function it hit me what the problem was. I installed in my new machine firstly yabar using GNU stow. Since /usr/local/bin didn’t exist, stow installed yabar to /usr/local/stow/yabar and symlinked /usr/local/bin to /usr/local/stow/yabar/bin. When I installed rust, the executables were installed to /usr/local/bin. When this function computes sysroot, it follows the symlinks and determines that rustc resides in /usr/local/stow/yabar/bin/rustc. And then returns as sysroot /usr/local/stow/yabar. This is obviously wrong since sysroot should be /usr/local/. Now, if the function hadn’t followed symlinks I would have had no error at all.

So, my question is, what is the reason for following symlinks when determining the sysroot?

I use stow as well, it’s awesome. I think rust was right here, when the executables were instaleld in /usr/local/bin, they effectively landed in /usr/local/stow/yabar/bin, so rust was right to determine that as the location of rustc, and therefore the sysroot. Following symlinks probably wasn’t involved…

What you should do is make stow not symlink /usr/local/bin to /usr/local/stow/yabar/bin, but have it make symlinks in /usr/local/bin that point to targets that live in /usr/local/stow/yabar/bin. That would result in rustc being installed in to /usr/local/bin, and therefore a correct path.

While I understand with stow I still don’t agree it has nothing to do with symlinks. which rustc reported it at /usr/local/bin so env::current_exe() would have been /usr/local/bin/rustc however the symlink following would have then transformed this into /usr/local/stow/yabar/bin/rustc.

I am in no way saying this is incorrect. In the end, it’s my fault due to my usage of stow but I am still intrigued why we are following symlinks here. What’s the use case?

Ok, yeah, I see. Your PATH says that the rustc to use is the one at /usr/local/bin/rustc, nevermind that it is a symlink to /usr/local/stow/yabar/bin/rustc, and the first env args passed to rustc should actually read /usr/local/bin/rustc, not that-other-thing. So I revise my opinion and think that in this case the sysroot should have been /usr/local/bin.

Whatever resolution rule rustc uses needs to work for downloaded rust snapshot tarballs, too.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.