rustc_session/
filesearch.rs1use std::path::{Path, PathBuf};
4use std::{env, fs};
5
6use rustc_fs_util::try_canonicalize;
7use rustc_target::spec::Target;
8
9use crate::search_paths::{PathKind, SearchPath};
10
11#[derive(Clone)]
12pub struct FileSearch {
13 cli_search_paths: Vec<SearchPath>,
14 tlib_path: SearchPath,
15}
16
17impl FileSearch {
18 pub fn cli_search_paths<'b>(&'b self, kind: PathKind) -> impl Iterator<Item = &'b SearchPath> {
19 self.cli_search_paths.iter().filter(move |sp| sp.kind.matches(kind))
20 }
21
22 pub fn search_paths<'b>(&'b self, kind: PathKind) -> impl Iterator<Item = &'b SearchPath> {
23 self.cli_search_paths
24 .iter()
25 .filter(move |sp| sp.kind.matches(kind))
26 .chain(std::iter::once(&self.tlib_path))
27 }
28
29 pub fn new(cli_search_paths: &[SearchPath], tlib_path: &SearchPath, target: &Target) -> Self {
30 let this = FileSearch {
31 cli_search_paths: cli_search_paths.to_owned(),
32 tlib_path: tlib_path.clone(),
33 };
34 this.refine(&["lib", &target.staticlib_prefix, &target.dll_prefix])
35 }
36 fn refine(mut self, allowed_prefixes: &[&str]) -> FileSearch {
38 self.cli_search_paths
39 .iter_mut()
40 .for_each(|search_paths| search_paths.files.retain(allowed_prefixes));
41 self.tlib_path.files.retain(allowed_prefixes);
42
43 self
44 }
45}
46
47pub fn make_target_lib_path(sysroot: &Path, target_triple: &str) -> PathBuf {
48 let rustlib_path = rustc_target::relative_target_rustlib_path(sysroot, target_triple);
49 sysroot.join(rustlib_path).join("lib")
50}
51
52pub fn make_target_bin_path(sysroot: &Path, target_triple: &str) -> PathBuf {
56 let rustlib_path = rustc_target::relative_target_rustlib_path(sysroot, target_triple);
57 sysroot.join(rustlib_path).join("bin")
58}
59
60#[cfg(unix)]
61fn current_dll_path() -> Result<PathBuf, String> {
62 use std::sync::OnceLock;
63
64 static CURRENT_DLL_PATH: OnceLock<Result<PathBuf, String>> = OnceLock::new();
68 CURRENT_DLL_PATH
69 .get_or_init(|| {
70 use std::ffi::{CStr, OsStr};
71 use std::os::unix::prelude::*;
72
73 #[cfg(not(target_os = "aix"))]
74 unsafe {
75 let addr = current_dll_path as usize as *mut _;
76 let mut info = std::mem::zeroed();
77 if libc::dladdr(addr, &mut info) == 0 {
78 return Err("dladdr failed".into());
79 }
80 #[cfg(target_os = "cygwin")]
81 let fname_ptr = info.dli_fname.as_ptr();
82 #[cfg(not(target_os = "cygwin"))]
83 let fname_ptr = {
84 assert!(!info.dli_fname.is_null(), "dli_fname cannot be null");
85 info.dli_fname
86 };
87 let bytes = CStr::from_ptr(fname_ptr).to_bytes();
88 let os = OsStr::from_bytes(bytes);
89 try_canonicalize(Path::new(os)).map_err(|e| e.to_string())
90 }
91
92 #[cfg(target_os = "aix")]
93 unsafe {
94 let addr = current_dll_path as u64;
101 let mut buffer = vec![std::mem::zeroed::<libc::ld_info>(); 64];
102 loop {
103 if libc::loadquery(
104 libc::L_GETINFO,
105 buffer.as_mut_ptr() as *mut u8,
106 (size_of::<libc::ld_info>() * buffer.len()) as u32,
107 ) >= 0
108 {
109 break;
110 } else {
111 if std::io::Error::last_os_error().raw_os_error().unwrap() != libc::ENOMEM {
112 return Err("loadquery failed".into());
113 }
114 buffer.resize(buffer.len() * 2, std::mem::zeroed::<libc::ld_info>());
115 }
116 }
117 let mut current = buffer.as_mut_ptr() as *mut libc::ld_info;
118 loop {
119 let data_base = (*current).ldinfo_dataorg as u64;
120 let data_end = data_base + (*current).ldinfo_datasize;
121 if (data_base..data_end).contains(&addr) {
122 let bytes = CStr::from_ptr(&(*current).ldinfo_filename[0]).to_bytes();
123 let os = OsStr::from_bytes(bytes);
124 return try_canonicalize(Path::new(os)).map_err(|e| e.to_string());
125 }
126 if (*current).ldinfo_next == 0 {
127 break;
128 }
129 current = (current as *mut i8).offset((*current).ldinfo_next as isize)
130 as *mut libc::ld_info;
131 }
132 return Err(format!("current dll's address {} is not in the load map", addr));
133 }
134 })
135 .clone()
136}
137
138#[cfg(windows)]
139fn current_dll_path() -> Result<PathBuf, String> {
140 use std::ffi::OsString;
141 use std::io;
142 use std::os::windows::prelude::*;
143
144 use windows::Win32::Foundation::HMODULE;
145 use windows::Win32::System::LibraryLoader::{
146 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, GetModuleFileNameW, GetModuleHandleExW,
147 };
148 use windows::core::PCWSTR;
149
150 let mut module = HMODULE::default();
151 unsafe {
152 GetModuleHandleExW(
153 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
154 PCWSTR(current_dll_path as *mut u16),
155 &mut module,
156 )
157 }
158 .map_err(|e| e.to_string())?;
159
160 let mut filename = vec![0; 1024];
161 let n = unsafe { GetModuleFileNameW(Some(module), &mut filename) } as usize;
162 if n == 0 {
163 return Err(format!("GetModuleFileNameW failed: {}", io::Error::last_os_error()));
164 }
165 if n >= filename.capacity() {
166 return Err(format!("our buffer was too small? {}", io::Error::last_os_error()));
167 }
168
169 filename.truncate(n);
170
171 let path = try_canonicalize(OsString::from_wide(&filename)).map_err(|e| e.to_string())?;
172
173 Ok(rustc_fs_util::fix_windows_verbatim_for_gcc(&path))
177}
178
179#[cfg(target_os = "wasi")]
180fn current_dll_path() -> Result<PathBuf, String> {
181 Err("current_dll_path is not supported on WASI".to_string())
182}
183
184pub(crate) fn default_sysroot() -> PathBuf {
187 fn default_from_rustc_driver_dll() -> Result<PathBuf, String> {
188 let dll = current_dll_path()?;
189
190 let dir = dll.parent().and_then(|p| p.parent()).ok_or_else(|| {
197 format!("Could not move 2 levels upper using `parent()` on {}", dll.display())
198 })?;
199
200 let mut sysroot_dir = if dir.ends_with(crate::config::host_tuple()) {
202 dir.parent() .and_then(|p| p.parent()) .and_then(|p| p.parent()) .map(|s| s.to_owned())
206 .ok_or_else(|| {
207 format!("Could not move 3 levels upper using `parent()` on {}", dir.display())
208 })?
209 } else {
210 dir.to_owned()
211 };
212
213 if sysroot_dir.ends_with("lib") {
217 sysroot_dir =
218 sysroot_dir.parent().map(|real_sysroot| real_sysroot.to_owned()).ok_or_else(
219 || format!("Could not move to parent path of {}", sysroot_dir.display()),
220 )?
221 }
222
223 Ok(sysroot_dir)
224 }
225
226 fn from_env_args_next() -> Option<PathBuf> {
231 let mut p = PathBuf::from(env::args_os().next()?);
232
233 if fs::read_link(&p).is_err() {
238 return None;
240 }
241
242 p.pop();
244 p.pop();
245 let mut rustlib_path = rustc_target::relative_target_rustlib_path(&p, "dummy");
247 rustlib_path.pop(); rustlib_path.exists().then_some(p)
249 }
250
251 from_env_args_next()
252 .unwrap_or_else(|| default_from_rustc_driver_dll().expect("Failed finding sysroot"))
253}