summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_session/src/filesearch.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:32 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:32 +0000
commit4547b622d8d29df964fa2914213088b148c498fc (patch)
tree9fc6b25f3c3add6b745be9a2400a6e96140046e9 /compiler/rustc_session/src/filesearch.rs
parentReleasing progress-linux version 1.66.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-4547b622d8d29df964fa2914213088b148c498fc.tar.xz
rustc-4547b622d8d29df964fa2914213088b148c498fc.zip
Merging upstream version 1.67.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_session/src/filesearch.rs')
-rw-r--r--compiler/rustc_session/src/filesearch.rs136
1 files changed, 120 insertions, 16 deletions
diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs
index e8edb38f5..1b66773be 100644
--- a/compiler/rustc_session/src/filesearch.rs
+++ b/compiler/rustc_session/src/filesearch.rs
@@ -1,5 +1,6 @@
//! A module for searching for libraries
+use smallvec::{smallvec, SmallVec};
use std::env;
use std::fs;
use std::iter::FromIterator;
@@ -62,9 +63,99 @@ pub fn make_target_lib_path(sysroot: &Path, target_triple: &str) -> PathBuf {
PathBuf::from_iter([sysroot, Path::new(&rustlib_path), Path::new("lib")])
}
+#[cfg(unix)]
+fn current_dll_path() -> Result<PathBuf, String> {
+ use std::ffi::{CStr, OsStr};
+ use std::os::unix::prelude::*;
+
+ unsafe {
+ let addr = current_dll_path as usize as *mut _;
+ let mut info = std::mem::zeroed();
+ if libc::dladdr(addr, &mut info) == 0 {
+ return Err("dladdr failed".into());
+ }
+ if info.dli_fname.is_null() {
+ return Err("dladdr returned null pointer".into());
+ }
+ let bytes = CStr::from_ptr(info.dli_fname).to_bytes();
+ let os = OsStr::from_bytes(bytes);
+ Ok(PathBuf::from(os))
+ }
+}
+
+#[cfg(windows)]
+fn current_dll_path() -> Result<PathBuf, String> {
+ use std::ffi::OsString;
+ use std::io;
+ use std::os::windows::prelude::*;
+ use std::ptr;
+
+ use winapi::um::libloaderapi::{
+ GetModuleFileNameW, GetModuleHandleExW, GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
+ };
+
+ unsafe {
+ let mut module = ptr::null_mut();
+ let r = GetModuleHandleExW(
+ GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
+ current_dll_path as usize as *mut _,
+ &mut module,
+ );
+ if r == 0 {
+ return Err(format!("GetModuleHandleExW failed: {}", io::Error::last_os_error()));
+ }
+ let mut space = Vec::with_capacity(1024);
+ let r = GetModuleFileNameW(module, space.as_mut_ptr(), space.capacity() as u32);
+ if r == 0 {
+ return Err(format!("GetModuleFileNameW failed: {}", io::Error::last_os_error()));
+ }
+ let r = r as usize;
+ if r >= space.capacity() {
+ return Err(format!("our buffer was too small? {}", io::Error::last_os_error()));
+ }
+ space.set_len(r);
+ let os = OsString::from_wide(&space);
+ Ok(PathBuf::from(os))
+ }
+}
+
+pub fn sysroot_candidates() -> SmallVec<[PathBuf; 2]> {
+ let target = crate::config::host_triple();
+ let mut sysroot_candidates: SmallVec<[PathBuf; 2]> =
+ smallvec![get_or_default_sysroot().expect("Failed finding sysroot")];
+ let path = current_dll_path().and_then(|s| Ok(s.canonicalize().map_err(|e| e.to_string())?));
+ if let Ok(dll) = path {
+ // use `parent` twice to chop off the file name and then also the
+ // directory containing the dll which should be either `lib` or `bin`.
+ if let Some(path) = dll.parent().and_then(|p| p.parent()) {
+ // The original `path` pointed at the `rustc_driver` crate's dll.
+ // Now that dll should only be in one of two locations. The first is
+ // in the compiler's libdir, for example `$sysroot/lib/*.dll`. The
+ // other is the target's libdir, for example
+ // `$sysroot/lib/rustlib/$target/lib/*.dll`.
+ //
+ // We don't know which, so let's assume that if our `path` above
+ // ends in `$target` we *could* be in the target libdir, and always
+ // assume that we may be in the main libdir.
+ sysroot_candidates.push(path.to_owned());
+
+ if path.ends_with(target) {
+ sysroot_candidates.extend(
+ path.parent() // chop off `$target`
+ .and_then(|p| p.parent()) // chop off `rustlib`
+ .and_then(|p| p.parent()) // chop off `lib`
+ .map(|s| s.to_owned()),
+ );
+ }
+ }
+ }
+
+ return sysroot_candidates;
+}
+
/// This function checks if sysroot is found using env::args().next(), and if it
-/// is not found, uses env::current_exe() to imply sysroot.
-pub fn get_or_default_sysroot() -> PathBuf {
+/// is not found, finds sysroot from current rustc_driver dll.
+pub fn get_or_default_sysroot() -> Result<PathBuf, String> {
// Follow symlinks. If the resolved path is relative, make it absolute.
fn canonicalize(path: PathBuf) -> PathBuf {
let path = fs::canonicalize(&path).unwrap_or(path);
@@ -74,17 +165,32 @@ pub fn get_or_default_sysroot() -> PathBuf {
fix_windows_verbatim_for_gcc(&path)
}
- // Use env::current_exe() to get the path of the executable following
- // symlinks/canonicalizing components.
- fn from_current_exe() -> PathBuf {
- match env::current_exe() {
- Ok(exe) => {
- let mut p = canonicalize(exe);
- p.pop();
- p.pop();
- p
- }
- Err(e) => panic!("failed to get current_exe: {e}"),
+ fn default_from_rustc_driver_dll() -> Result<PathBuf, String> {
+ let dll = current_dll_path().and_then(|s| Ok(canonicalize(s)))?;
+
+ // `dll` will be in one of the following two:
+ // - compiler's libdir: $sysroot/lib/*.dll
+ // - target's libdir: $sysroot/lib/rustlib/$target/lib/*.dll
+ //
+ // use `parent` twice to chop off the file name and then also the
+ // directory containing the dll
+ let dir = dll.parent().and_then(|p| p.parent()).ok_or(format!(
+ "Could not move 2 levels upper using `parent()` on {}",
+ dll.display()
+ ))?;
+
+ // if `dir` points target's dir, move up to the sysroot
+ if dir.ends_with(crate::config::host_triple()) {
+ dir.parent() // chop off `$target`
+ .and_then(|p| p.parent()) // chop off `rustlib`
+ .and_then(|p| p.parent()) // chop off `lib`
+ .map(|s| s.to_owned())
+ .ok_or(format!(
+ "Could not move 3 levels upper using `parent()` on {}",
+ dir.display()
+ ))
+ } else {
+ Ok(dir.to_owned())
}
}
@@ -118,7 +224,5 @@ pub fn get_or_default_sysroot() -> PathBuf {
}
}
- // Check if sysroot is found using env::args().next(), and if is not found,
- // use env::current_exe() to imply sysroot.
- from_env_args_next().unwrap_or_else(from_current_exe)
+ Ok(from_env_args_next().unwrap_or(default_from_rustc_driver_dll()?))
}