Skip to content

Commit ae0232e

Browse files
committed
improve filesearch::get_or_default_sysroot r=ozkanonur
Signed-off-by: Onur Özkan <work@onurozkan.dev>
1 parent cdd7afe commit ae0232e

File tree

10 files changed

+151
-263
lines changed

10 files changed

+151
-263
lines changed

Cargo.lock

+3-2
Original file line numberDiff line numberDiff line change
@@ -3646,7 +3646,6 @@ dependencies = [
36463646
name = "rustc_interface"
36473647
version = "0.0.0"
36483648
dependencies = [
3649-
"libc",
36503649
"libloading",
36513650
"rustc-rayon",
36523651
"rustc-rayon-core",
@@ -3689,7 +3688,6 @@ dependencies = [
36893688
"rustc_ty_utils",
36903689
"smallvec",
36913690
"tracing",
3692-
"winapi",
36933691
]
36943692

36953693
[[package]]
@@ -4109,6 +4107,7 @@ name = "rustc_session"
41094107
version = "0.0.0"
41104108
dependencies = [
41114109
"getopts",
4110+
"libc",
41124111
"rustc_ast",
41134112
"rustc_data_structures",
41144113
"rustc_errors",
@@ -4120,7 +4119,9 @@ dependencies = [
41204119
"rustc_serialize",
41214120
"rustc_span",
41224121
"rustc_target",
4122+
"smallvec",
41234123
"tracing",
4124+
"winapi",
41244125
]
41254126

41264127
[[package]]

compiler/rustc_codegen_ssa/src/back/link.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1153,7 +1153,8 @@ fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) {
11531153
if path.exists() {
11541154
return session_tlib;
11551155
} else {
1156-
let default_sysroot = filesearch::get_or_default_sysroot();
1156+
let default_sysroot =
1157+
filesearch::get_or_default_sysroot().expect("Failed finding sysroot");
11571158
let default_tlib = filesearch::make_target_lib_path(
11581159
&default_sysroot,
11591160
sess.opts.target_triple.triple(),

compiler/rustc_interface/Cargo.toml

-6
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,6 @@ rustc_resolve = { path = "../rustc_resolve" }
4848
rustc_trait_selection = { path = "../rustc_trait_selection" }
4949
rustc_ty_utils = { path = "../rustc_ty_utils" }
5050

51-
[target.'cfg(unix)'.dependencies]
52-
libc = "0.2"
53-
54-
[target.'cfg(windows)'.dependencies]
55-
winapi = { version = "0.3", features = ["libloaderapi"] }
56-
5751
[dev-dependencies]
5852
rustc_target = { path = "../rustc_target" }
5953

compiler/rustc_interface/src/util.rs

+2-95
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use rustc_session as session;
99
use rustc_session::config::CheckCfg;
1010
use rustc_session::config::{self, CrateType};
1111
use rustc_session::config::{ErrorOutputType, Input, OutputFilenames};
12+
use rustc_session::filesearch::sysroot_candidates;
1213
use rustc_session::lint::{self, BuiltinLintDiagnostics, LintBuffer};
1314
use rustc_session::parse::CrateConfig;
1415
use rustc_session::{early_error, filesearch, output, Session};
@@ -78,7 +79,7 @@ pub fn create_session(
7879

7980
let bundle = match rustc_errors::fluent_bundle(
8081
sopts.maybe_sysroot.clone(),
81-
sysroot_candidates(),
82+
sysroot_candidates().to_vec(),
8283
sopts.unstable_opts.translate_lang.clone(),
8384
sopts.unstable_opts.translate_additional_ftl.as_deref(),
8485
sopts.unstable_opts.translate_directionality_markers,
@@ -273,100 +274,6 @@ fn get_rustc_path_inner(bin_path: &str) -> Option<PathBuf> {
273274
})
274275
}
275276

276-
fn sysroot_candidates() -> Vec<PathBuf> {
277-
let target = session::config::host_triple();
278-
let mut sysroot_candidates = vec![filesearch::get_or_default_sysroot()];
279-
let path = current_dll_path().and_then(|s| s.canonicalize().ok());
280-
if let Some(dll) = path {
281-
// use `parent` twice to chop off the file name and then also the
282-
// directory containing the dll which should be either `lib` or `bin`.
283-
if let Some(path) = dll.parent().and_then(|p| p.parent()) {
284-
// The original `path` pointed at the `rustc_driver` crate's dll.
285-
// Now that dll should only be in one of two locations. The first is
286-
// in the compiler's libdir, for example `$sysroot/lib/*.dll`. The
287-
// other is the target's libdir, for example
288-
// `$sysroot/lib/rustlib/$target/lib/*.dll`.
289-
//
290-
// We don't know which, so let's assume that if our `path` above
291-
// ends in `$target` we *could* be in the target libdir, and always
292-
// assume that we may be in the main libdir.
293-
sysroot_candidates.push(path.to_owned());
294-
295-
if path.ends_with(target) {
296-
sysroot_candidates.extend(
297-
path.parent() // chop off `$target`
298-
.and_then(|p| p.parent()) // chop off `rustlib`
299-
.and_then(|p| p.parent()) // chop off `lib`
300-
.map(|s| s.to_owned()),
301-
);
302-
}
303-
}
304-
}
305-
306-
return sysroot_candidates;
307-
308-
#[cfg(unix)]
309-
fn current_dll_path() -> Option<PathBuf> {
310-
use std::ffi::{CStr, OsStr};
311-
use std::os::unix::prelude::*;
312-
313-
unsafe {
314-
let addr = current_dll_path as usize as *mut _;
315-
let mut info = mem::zeroed();
316-
if libc::dladdr(addr, &mut info) == 0 {
317-
info!("dladdr failed");
318-
return None;
319-
}
320-
if info.dli_fname.is_null() {
321-
info!("dladdr returned null pointer");
322-
return None;
323-
}
324-
let bytes = CStr::from_ptr(info.dli_fname).to_bytes();
325-
let os = OsStr::from_bytes(bytes);
326-
Some(PathBuf::from(os))
327-
}
328-
}
329-
330-
#[cfg(windows)]
331-
fn current_dll_path() -> Option<PathBuf> {
332-
use std::ffi::OsString;
333-
use std::io;
334-
use std::os::windows::prelude::*;
335-
use std::ptr;
336-
337-
use winapi::um::libloaderapi::{
338-
GetModuleFileNameW, GetModuleHandleExW, GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
339-
};
340-
341-
unsafe {
342-
let mut module = ptr::null_mut();
343-
let r = GetModuleHandleExW(
344-
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
345-
current_dll_path as usize as *mut _,
346-
&mut module,
347-
);
348-
if r == 0 {
349-
info!("GetModuleHandleExW failed: {}", io::Error::last_os_error());
350-
return None;
351-
}
352-
let mut space = Vec::with_capacity(1024);
353-
let r = GetModuleFileNameW(module, space.as_mut_ptr(), space.capacity() as u32);
354-
if r == 0 {
355-
info!("GetModuleFileNameW failed: {}", io::Error::last_os_error());
356-
return None;
357-
}
358-
let r = r as usize;
359-
if r >= space.capacity() {
360-
info!("our buffer was too small? {}", io::Error::last_os_error());
361-
return None;
362-
}
363-
space.set_len(r);
364-
let os = OsString::from_wide(&space);
365-
Some(PathBuf::from(os))
366-
}
367-
}
368-
}
369-
370277
fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> MakeBackendFn {
371278
// For now we only allow this function to be called once as it'll dlopen a
372279
// few things, which seems to work best if we only do that once. In

compiler/rustc_session/Cargo.toml

+7
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,10 @@ rustc_span = { path = "../rustc_span" }
1717
rustc_fs_util = { path = "../rustc_fs_util" }
1818
rustc_ast = { path = "../rustc_ast" }
1919
rustc_lint_defs = { path = "../rustc_lint_defs" }
20+
smallvec = "1.8.1"
21+
22+
[target.'cfg(unix)'.dependencies]
23+
libc = "0.2"
24+
25+
[target.'cfg(windows)'.dependencies]
26+
winapi = { version = "0.3", features = ["libloaderapi"] }

compiler/rustc_session/src/config.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2431,7 +2431,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
24312431
let sysroot = match &sysroot_opt {
24322432
Some(s) => s,
24332433
None => {
2434-
tmp_buf = crate::filesearch::get_or_default_sysroot();
2434+
tmp_buf = crate::filesearch::get_or_default_sysroot().expect("Failed finding sysroot");
24352435
&tmp_buf
24362436
}
24372437
};

compiler/rustc_session/src/filesearch.rs

+119-24
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
//! A module for searching for libraries
22
3+
use smallvec::{smallvec, SmallVec};
34
use std::env;
45
use std::fs;
56
use std::iter::FromIterator;
67
use std::path::{Path, PathBuf};
78

89
use crate::search_paths::{PathKind, SearchPath};
9-
use rustc_fs_util::fix_windows_verbatim_for_gcc;
1010

1111
#[derive(Copy, Clone)]
1212
pub enum FileMatch {
@@ -62,29 +62,126 @@ pub fn make_target_lib_path(sysroot: &Path, target_triple: &str) -> PathBuf {
6262
PathBuf::from_iter([sysroot, Path::new(&rustlib_path), Path::new("lib")])
6363
}
6464

65-
/// This function checks if sysroot is found using env::args().next(), and if it
66-
/// is not found, uses env::current_exe() to imply sysroot.
67-
pub fn get_or_default_sysroot() -> PathBuf {
68-
// Follow symlinks. If the resolved path is relative, make it absolute.
69-
fn canonicalize(path: PathBuf) -> PathBuf {
70-
let path = fs::canonicalize(&path).unwrap_or(path);
71-
// See comments on this target function, but the gist is that
72-
// gcc chokes on verbatim paths which fs::canonicalize generates
73-
// so we try to avoid those kinds of paths.
74-
fix_windows_verbatim_for_gcc(&path)
65+
#[cfg(unix)]
66+
fn current_dll_path() -> Result<PathBuf, String> {
67+
use std::ffi::{CStr, OsStr};
68+
use std::os::unix::prelude::*;
69+
70+
unsafe {
71+
let addr = current_dll_path as usize as *mut _;
72+
let mut info = std::mem::zeroed();
73+
if libc::dladdr(addr, &mut info) == 0 {
74+
return Err("dladdr failed".into());
75+
}
76+
if info.dli_fname.is_null() {
77+
return Err("dladdr returned null pointer".into());
78+
}
79+
let bytes = CStr::from_ptr(info.dli_fname).to_bytes();
80+
let os = OsStr::from_bytes(bytes);
81+
Ok(PathBuf::from(os))
7582
}
83+
}
7684

77-
// Use env::current_exe() to get the path of the executable following
78-
// symlinks/canonicalizing components.
79-
fn from_current_exe() -> PathBuf {
80-
match env::current_exe() {
81-
Ok(exe) => {
82-
let mut p = canonicalize(exe);
83-
p.pop();
84-
p.pop();
85-
p
85+
#[cfg(windows)]
86+
fn current_dll_path() -> Result<PathBuf, String> {
87+
use std::ffi::OsString;
88+
use std::io;
89+
use std::os::windows::prelude::*;
90+
use std::ptr;
91+
92+
use winapi::um::libloaderapi::{
93+
GetModuleFileNameW, GetModuleHandleExW, GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
94+
};
95+
96+
unsafe {
97+
let mut module = ptr::null_mut();
98+
let r = GetModuleHandleExW(
99+
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
100+
current_dll_path as usize as *mut _,
101+
&mut module,
102+
);
103+
if r == 0 {
104+
return Err(format!("GetModuleHandleExW failed: {}", io::Error::last_os_error()));
105+
}
106+
let mut space = Vec::with_capacity(1024);
107+
let r = GetModuleFileNameW(module, space.as_mut_ptr(), space.capacity() as u32);
108+
if r == 0 {
109+
return Err(format!("GetModuleFileNameW failed: {}", io::Error::last_os_error()));
110+
}
111+
let r = r as usize;
112+
if r >= space.capacity() {
113+
return Err(format!("our buffer was too small? {}", io::Error::last_os_error()));
114+
}
115+
space.set_len(r);
116+
let os = OsString::from_wide(&space);
117+
Ok(PathBuf::from(os))
118+
}
119+
}
120+
121+
pub fn sysroot_candidates() -> SmallVec<[PathBuf; 2]> {
122+
let target = crate::config::host_triple();
123+
let mut sysroot_candidates: SmallVec<[PathBuf; 2]> =
124+
smallvec![get_or_default_sysroot().expect("Failed finding sysroot")];
125+
let path = current_dll_path().and_then(|s| Ok(s.canonicalize().map_err(|e| e.to_string())?));
126+
if let Ok(dll) = path {
127+
// use `parent` twice to chop off the file name and then also the
128+
// directory containing the dll which should be either `lib` or `bin`.
129+
if let Some(path) = dll.parent().and_then(|p| p.parent()) {
130+
// The original `path` pointed at the `rustc_driver` crate's dll.
131+
// Now that dll should only be in one of two locations. The first is
132+
// in the compiler's libdir, for example `$sysroot/lib/*.dll`. The
133+
// other is the target's libdir, for example
134+
// `$sysroot/lib/rustlib/$target/lib/*.dll`.
135+
//
136+
// We don't know which, so let's assume that if our `path` above
137+
// ends in `$target` we *could* be in the target libdir, and always
138+
// assume that we may be in the main libdir.
139+
sysroot_candidates.push(path.to_owned());
140+
141+
if path.ends_with(target) {
142+
sysroot_candidates.extend(
143+
path.parent() // chop off `$target`
144+
.and_then(|p| p.parent()) // chop off `rustlib`
145+
.and_then(|p| p.parent()) // chop off `lib`
146+
.map(|s| s.to_owned()),
147+
);
86148
}
87-
Err(e) => panic!("failed to get current_exe: {e}"),
149+
}
150+
}
151+
152+
return sysroot_candidates;
153+
}
154+
155+
/// This function checks if sysroot is found using env::args().next(), and if it
156+
/// is not found, finds sysroot from current rustc_driver dll.
157+
pub fn get_or_default_sysroot() -> Result<PathBuf, String> {
158+
fn default_from_rustc_driver_dll() -> Result<PathBuf, String> {
159+
let dll =
160+
current_dll_path().and_then(|s| Ok(s.canonicalize().map_err(|e| e.to_string())?))?;
161+
162+
// `dll` will be in one of the following two:
163+
// - compiler's libdir: $sysroot/lib/*.dll
164+
// - target's libdir: $sysroot/lib/rustlib/$target/lib/*.dll
165+
//
166+
// use `parent` twice to chop off the file name and then also the
167+
// directory containing the dll
168+
let dir = dll.parent().and_then(|p| p.parent()).ok_or(format!(
169+
"Could not move 2 levels upper using `parent()` on {}",
170+
dll.display()
171+
))?;
172+
173+
// if `dir` points target's dir, move up to the sysroot
174+
if dir.ends_with(crate::config::host_triple()) {
175+
dir.parent() // chop off `$target`
176+
.and_then(|p| p.parent()) // chop off `rustlib`
177+
.and_then(|p| p.parent()) // chop off `lib`
178+
.map(|s| s.to_owned())
179+
.ok_or(format!(
180+
"Could not move 3 levels upper using `parent()` on {}",
181+
dir.display()
182+
))
183+
} else {
184+
Ok(dir.to_owned())
88185
}
89186
}
90187

@@ -118,7 +215,5 @@ pub fn get_or_default_sysroot() -> PathBuf {
118215
}
119216
}
120217

121-
// Check if sysroot is found using env::args().next(), and if is not found,
122-
// use env::current_exe() to imply sysroot.
123-
from_env_args_next().unwrap_or_else(from_current_exe)
218+
Ok(from_env_args_next().unwrap_or(default_from_rustc_driver_dll()?))
124219
}

compiler/rustc_session/src/session.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1280,7 +1280,7 @@ pub fn build_session(
12801280

12811281
let sysroot = match &sopts.maybe_sysroot {
12821282
Some(sysroot) => sysroot.clone(),
1283-
None => filesearch::get_or_default_sysroot(),
1283+
None => filesearch::get_or_default_sysroot().expect("Failed finding sysroot"),
12841284
};
12851285

12861286
let target_cfg = config::build_target_config(&sopts, target_override, &sysroot);

0 commit comments

Comments
 (0)