]> git.lizzy.rs Git - rust.git/blob - src/librustc_session/filesearch.rs
Auto merge of #66911 - eddyb:nicer-rustc_regions, r=matthewjasper
[rust.git] / src / librustc_session / filesearch.rs
1 #![allow(non_camel_case_types)]
2
3 pub use self::FileMatch::*;
4
5 use std::borrow::Cow;
6 use std::env;
7 use std::fs;
8 use std::path::{Path, PathBuf};
9
10 use crate::search_paths::{SearchPath, PathKind};
11 use rustc_fs_util::fix_windows_verbatim_for_gcc;
12 use log::debug;
13
14 #[derive(Copy, Clone)]
15 pub enum FileMatch {
16     FileMatches,
17     FileDoesntMatch,
18 }
19
20 // A module for searching for libraries
21
22 #[derive(Clone)]
23 pub struct FileSearch<'a> {
24     sysroot: &'a Path,
25     triple: &'a str,
26     search_paths: &'a [SearchPath],
27     tlib_path: &'a SearchPath,
28     kind: PathKind,
29 }
30
31 impl<'a> FileSearch<'a> {
32     pub fn search_paths(&self) -> impl Iterator<Item = &'a SearchPath> {
33         let kind = self.kind;
34         self.search_paths.iter()
35             .filter(move |sp| sp.kind.matches(kind))
36             .chain(std::iter::once(self.tlib_path))
37     }
38
39     pub fn get_lib_path(&self) -> PathBuf {
40         make_target_lib_path(self.sysroot, self.triple)
41     }
42
43     pub fn search<F>(&self, mut pick: F)
44         where F: FnMut(&Path, PathKind) -> FileMatch
45     {
46         for search_path in self.search_paths() {
47             debug!("searching {}", search_path.dir.display());
48             fn is_rlib(p: &Path) -> bool {
49                 p.extension() == Some("rlib".as_ref())
50             }
51             // Reading metadata out of rlibs is faster, and if we find both
52             // an rlib and a dylib we only read one of the files of
53             // metadata, so in the name of speed, bring all rlib files to
54             // the front of the search list.
55             let files1 = search_path.files.iter().filter(|p| is_rlib(p));
56             let files2 = search_path.files.iter().filter(|p| !is_rlib(p));
57             for path in files1.chain(files2) {
58                 debug!("testing {}", path.display());
59                 let maybe_picked = pick(path, search_path.kind);
60                 match maybe_picked {
61                     FileMatches => {
62                         debug!("picked {}", path.display());
63                     }
64                     FileDoesntMatch => {
65                         debug!("rejected {}", path.display());
66                     }
67                 }
68             }
69         }
70     }
71
72     pub fn new(sysroot: &'a Path,
73                triple: &'a str,
74                search_paths: &'a Vec<SearchPath>,
75                tlib_path: &'a SearchPath,
76                kind: PathKind)
77                -> FileSearch<'a> {
78         debug!("using sysroot = {}, triple = {}", sysroot.display(), triple);
79         FileSearch {
80             sysroot,
81             triple,
82             search_paths,
83             tlib_path,
84             kind,
85         }
86     }
87
88     // Returns just the directories within the search paths.
89     pub fn search_path_dirs(&self) -> Vec<PathBuf> {
90         self.search_paths()
91             .map(|sp| sp.dir.to_path_buf())
92             .collect()
93     }
94
95     // Returns a list of directories where target-specific tool binaries are located.
96     pub fn get_tools_search_paths(&self) -> Vec<PathBuf> {
97         let mut p = PathBuf::from(self.sysroot);
98         p.push(find_libdir(self.sysroot).as_ref());
99         p.push(RUST_LIB_DIR);
100         p.push(&self.triple);
101         p.push("bin");
102         vec![p]
103     }
104 }
105
106 pub fn relative_target_lib_path(sysroot: &Path, target_triple: &str) -> PathBuf {
107     let mut p = PathBuf::from(find_libdir(sysroot).as_ref());
108     assert!(p.is_relative());
109     p.push(RUST_LIB_DIR);
110     p.push(target_triple);
111     p.push("lib");
112     p
113 }
114
115 pub fn make_target_lib_path(sysroot: &Path, target_triple: &str) -> PathBuf {
116     sysroot.join(&relative_target_lib_path(sysroot, target_triple))
117 }
118
119 pub fn get_or_default_sysroot() -> PathBuf {
120     // Follow symlinks.  If the resolved path is relative, make it absolute.
121     fn canonicalize(path: Option<PathBuf>) -> Option<PathBuf> {
122         path.and_then(|path| {
123             match fs::canonicalize(&path) {
124                 // See comments on this target function, but the gist is that
125                 // gcc chokes on verbatim paths which fs::canonicalize generates
126                 // so we try to avoid those kinds of paths.
127                 Ok(canon) => Some(fix_windows_verbatim_for_gcc(&canon)),
128                 Err(e) => panic!("failed to get realpath: {}", e),
129             }
130         })
131     }
132
133     match env::current_exe() {
134         Ok(exe) => {
135             match canonicalize(Some(exe)) {
136                 Some(mut p) => { p.pop(); p.pop(); p },
137                 None => panic!("can't determine value for sysroot")
138             }
139         }
140         Err(ref e) => panic!(format!("failed to get current_exe: {}", e))
141     }
142 }
143
144 // The name of the directory rustc expects libraries to be located.
145 fn find_libdir(sysroot: &Path) -> Cow<'static, str> {
146     // FIXME: This is a quick hack to make the rustc binary able to locate
147     // Rust libraries in Linux environments where libraries might be installed
148     // to lib64/lib32. This would be more foolproof by basing the sysroot off
149     // of the directory where librustc is located, rather than where the rustc
150     // binary is.
151     // If --libdir is set during configuration to the value other than
152     // "lib" (i.e., non-default), this value is used (see issue #16552).
153
154     #[cfg(target_pointer_width = "64")]
155     const PRIMARY_LIB_DIR: &str = "lib64";
156
157     #[cfg(target_pointer_width = "32")]
158     const PRIMARY_LIB_DIR: &str = "lib32";
159
160     const SECONDARY_LIB_DIR: &str = "lib";
161
162     match option_env!("CFG_LIBDIR_RELATIVE") {
163         Some(libdir) if libdir != "lib" => libdir.into(),
164         _ => if sysroot.join(PRIMARY_LIB_DIR).join(RUST_LIB_DIR).exists() {
165             PRIMARY_LIB_DIR.into()
166         } else {
167             SECONDARY_LIB_DIR.into()
168         }
169     }
170 }
171
172 // The name of rustc's own place to organize libraries.
173 // Used to be "rustc", now the default is "rustlib"
174 const RUST_LIB_DIR: &str = "rustlib";