Skip to content

Commit 9b7f1f5

Browse files
authored
Rollup merge of rust-lang#93608 - nnethercote:speed-up-find_library_crate, r=petrochenkov
Clean up `find_library_crate` Some clean-ups. r? `@petrochenkov`
2 parents 3edec80 + 2826586 commit 9b7f1f5

File tree

3 files changed

+67
-90
lines changed

3 files changed

+67
-90
lines changed

compiler/rustc_metadata/src/locator.rs

+53-44
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ use rustc_data_structures::sync::MetadataRef;
223223
use rustc_errors::{struct_span_err, FatalError};
224224
use rustc_session::config::{self, CrateType};
225225
use rustc_session::cstore::{CrateSource, MetadataLoader};
226-
use rustc_session::filesearch::{FileDoesntMatch, FileMatches, FileSearch};
226+
use rustc_session::filesearch::FileSearch;
227227
use rustc_session::search_paths::PathKind;
228228
use rustc_session::utils::CanonicalizedPath;
229229
use rustc_session::Session;
@@ -371,15 +371,20 @@ impl<'a> CrateLocator<'a> {
371371
extra_prefix: &str,
372372
seen_paths: &mut FxHashSet<PathBuf>,
373373
) -> Result<Option<Library>, CrateError> {
374-
// want: crate_name.dir_part() + prefix + crate_name.file_part + "-"
375-
let dylib_prefix = format!("{}{}{}", self.target.dll_prefix, self.crate_name, extra_prefix);
376-
let rlib_prefix = format!("lib{}{}", self.crate_name, extra_prefix);
374+
let rmeta_prefix = &format!("lib{}{}", self.crate_name, extra_prefix);
375+
let rlib_prefix = rmeta_prefix;
376+
let dylib_prefix =
377+
&format!("{}{}{}", self.target.dll_prefix, self.crate_name, extra_prefix);
377378
let staticlib_prefix =
378-
format!("{}{}{}", self.target.staticlib_prefix, self.crate_name, extra_prefix);
379+
&format!("{}{}{}", self.target.staticlib_prefix, self.crate_name, extra_prefix);
380+
381+
let rmeta_suffix = ".rmeta";
382+
let rlib_suffix = ".rlib";
383+
let dylib_suffix = &self.target.dll_suffix;
384+
let staticlib_suffix = &self.target.staticlib_suffix;
379385

380386
let mut candidates: FxHashMap<_, (FxHashMap<_, _>, FxHashMap<_, _>, FxHashMap<_, _>)> =
381387
Default::default();
382-
let mut staticlibs = vec![];
383388

384389
// First, find all possible candidate rlibs and dylibs purely based on
385390
// the name of the files themselves. We're trying to match against an
@@ -394,46 +399,50 @@ impl<'a> CrateLocator<'a> {
394399
// of the crate id (path/name/id).
395400
//
396401
// The goal of this step is to look at as little metadata as possible.
397-
self.filesearch.search(|spf, kind| {
398-
let file = match &spf.file_name_str {
399-
None => return FileDoesntMatch,
400-
Some(file) => file,
401-
};
402-
let (hash, found_kind) = if file.starts_with(&rlib_prefix) && file.ends_with(".rlib") {
403-
(&file[(rlib_prefix.len())..(file.len() - ".rlib".len())], CrateFlavor::Rlib)
404-
} else if file.starts_with(&rlib_prefix) && file.ends_with(".rmeta") {
405-
(&file[(rlib_prefix.len())..(file.len() - ".rmeta".len())], CrateFlavor::Rmeta)
406-
} else if file.starts_with(&dylib_prefix) && file.ends_with(&self.target.dll_suffix) {
407-
(
408-
&file[(dylib_prefix.len())..(file.len() - self.target.dll_suffix.len())],
409-
CrateFlavor::Dylib,
410-
)
411-
} else {
412-
if file.starts_with(&staticlib_prefix)
413-
&& file.ends_with(&self.target.staticlib_suffix)
414-
{
415-
staticlibs
416-
.push(CrateMismatch { path: spf.path.clone(), got: "static".to_string() });
417-
}
418-
return FileDoesntMatch;
419-
};
402+
// Unfortunately, the prefix-based matching sometimes is over-eager.
403+
// E.g. if `rlib_suffix` is `libstd` it'll match the file
404+
// `libstd_detect-8d6701fb958915ad.rlib` (incorrect) as well as
405+
// `libstd-f3ab5b1dea981f17.rlib` (correct). But this is hard to avoid
406+
// given that `extra_filename` comes from the `-C extra-filename`
407+
// option and thus can be anything, and the incorrect match will be
408+
// handled safely in `extract_one`.
409+
for search_path in self.filesearch.search_paths() {
410+
debug!("searching {}", search_path.dir.display());
411+
for spf in search_path.files.iter() {
412+
debug!("testing {}", spf.path.display());
413+
414+
let f = &spf.file_name_str;
415+
let (hash, kind) = if f.starts_with(rlib_prefix) && f.ends_with(rlib_suffix) {
416+
(&f[rlib_prefix.len()..(f.len() - rlib_suffix.len())], CrateFlavor::Rlib)
417+
} else if f.starts_with(rmeta_prefix) && f.ends_with(rmeta_suffix) {
418+
(&f[rmeta_prefix.len()..(f.len() - rmeta_suffix.len())], CrateFlavor::Rmeta)
419+
} else if f.starts_with(dylib_prefix) && f.ends_with(dylib_suffix) {
420+
(&f[dylib_prefix.len()..(f.len() - dylib_suffix.len())], CrateFlavor::Dylib)
421+
} else {
422+
if f.starts_with(staticlib_prefix) && f.ends_with(staticlib_suffix) {
423+
self.crate_rejections.via_kind.push(CrateMismatch {
424+
path: spf.path.clone(),
425+
got: "static".to_string(),
426+
});
427+
}
428+
continue;
429+
};
420430

421-
info!("lib candidate: {}", spf.path.display());
431+
info!("lib candidate: {}", spf.path.display());
422432

423-
let (rlibs, rmetas, dylibs) = candidates.entry(hash.to_string()).or_default();
424-
let path = fs::canonicalize(&spf.path).unwrap_or_else(|_| spf.path.clone());
425-
if seen_paths.contains(&path) {
426-
return FileDoesntMatch;
427-
};
428-
seen_paths.insert(path.clone());
429-
match found_kind {
430-
CrateFlavor::Rlib => rlibs.insert(path, kind),
431-
CrateFlavor::Rmeta => rmetas.insert(path, kind),
432-
CrateFlavor::Dylib => dylibs.insert(path, kind),
433-
};
434-
FileMatches
435-
});
436-
self.crate_rejections.via_kind.extend(staticlibs);
433+
let (rlibs, rmetas, dylibs) = candidates.entry(hash.to_string()).or_default();
434+
let path = fs::canonicalize(&spf.path).unwrap_or_else(|_| spf.path.clone());
435+
if seen_paths.contains(&path) {
436+
continue;
437+
};
438+
seen_paths.insert(path.clone());
439+
match kind {
440+
CrateFlavor::Rlib => rlibs.insert(path, search_path.kind),
441+
CrateFlavor::Rmeta => rmetas.insert(path, search_path.kind),
442+
CrateFlavor::Dylib => dylibs.insert(path, search_path.kind),
443+
};
444+
}
445+
}
437446

438447
// We have now collected all known libraries into a set of candidates
439448
// keyed of the filename hash listed. For each filename, we also have a

compiler/rustc_session/src/filesearch.rs

+1-33
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
//! A module for searching for libraries
22
3-
pub use self::FileMatch::*;
4-
53
use std::env;
64
use std::fs;
75
use std::iter::FromIterator;
86
use std::path::{Path, PathBuf};
97

10-
use crate::search_paths::{PathKind, SearchPath, SearchPathFile};
8+
use crate::search_paths::{PathKind, SearchPath};
119
use rustc_fs_util::fix_windows_verbatim_for_gcc;
1210
use tracing::debug;
1311

@@ -43,36 +41,6 @@ impl<'a> FileSearch<'a> {
4341
self.get_lib_path().join("self-contained")
4442
}
4543

46-
pub fn search<F>(&self, mut pick: F)
47-
where
48-
F: FnMut(&SearchPathFile, PathKind) -> FileMatch,
49-
{
50-
for search_path in self.search_paths() {
51-
debug!("searching {}", search_path.dir.display());
52-
fn is_rlib(spf: &SearchPathFile) -> bool {
53-
if let Some(f) = &spf.file_name_str { f.ends_with(".rlib") } else { false }
54-
}
55-
// Reading metadata out of rlibs is faster, and if we find both
56-
// an rlib and a dylib we only read one of the files of
57-
// metadata, so in the name of speed, bring all rlib files to
58-
// the front of the search list.
59-
let files1 = search_path.files.iter().filter(|spf| is_rlib(&spf));
60-
let files2 = search_path.files.iter().filter(|spf| !is_rlib(&spf));
61-
for spf in files1.chain(files2) {
62-
debug!("testing {}", spf.path.display());
63-
let maybe_picked = pick(spf, search_path.kind);
64-
match maybe_picked {
65-
FileMatches => {
66-
debug!("picked {}", spf.path.display());
67-
}
68-
FileDoesntMatch => {
69-
debug!("rejected {}", spf.path.display());
70-
}
71-
}
72-
}
73-
}
74-
}
75-
7644
pub fn new(
7745
sysroot: &'a Path,
7846
triple: &'a str,

compiler/rustc_session/src/search_paths.rs

+13-13
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,15 @@ pub struct SearchPath {
1515
/// doable, but very slow, because it involves calls to `file_name` and
1616
/// `extension` that are themselves slow.
1717
///
18-
/// This type augments the `PathBuf` with an `Option<String>` containing the
18+
/// This type augments the `PathBuf` with an `String` containing the
1919
/// `PathBuf`'s filename. The prefix and suffix checking is much faster on the
20-
/// `Option<String>` than the `PathBuf`. (It's an `Option` because
21-
/// `Path::file_name` can fail; if that happens then all subsequent checking
22-
/// will also fail, which is fine.)
20+
/// `String` than the `PathBuf`. (The filename must be valid UTF-8. If it's
21+
/// not, the entry should be skipped, because all Rust output files are valid
22+
/// UTF-8, and so a non-UTF-8 filename couldn't be one we're looking for.)
2323
#[derive(Clone, Debug)]
2424
pub struct SearchPathFile {
2525
pub path: PathBuf,
26-
pub file_name_str: Option<String>,
27-
}
28-
29-
impl SearchPathFile {
30-
fn new(path: PathBuf) -> SearchPathFile {
31-
let file_name_str = path.file_name().and_then(|f| f.to_str()).map(|s| s.to_string());
32-
SearchPathFile { path, file_name_str }
33-
}
26+
pub file_name_str: String,
3427
}
3528

3629
#[derive(PartialEq, Clone, Copy, Debug, Hash, Eq, Encodable, Decodable)]
@@ -85,7 +78,14 @@ impl SearchPath {
8578
// Get the files within the directory.
8679
let files = match std::fs::read_dir(&dir) {
8780
Ok(files) => files
88-
.filter_map(|e| e.ok().map(|e| SearchPathFile::new(e.path())))
81+
.filter_map(|e| {
82+
e.ok().and_then(|e| {
83+
e.file_name().to_str().map(|s| SearchPathFile {
84+
path: e.path(),
85+
file_name_str: s.to_string(),
86+
})
87+
})
88+
})
8989
.collect::<Vec<_>>(),
9090
Err(..) => vec![],
9191
};

0 commit comments

Comments
 (0)