]>
Commit | Line | Data |
---|---|---|
1a4d82fc | 1 | // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT |
223e47cc LB |
2 | // file at the top-level directory of this distribution and at |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
1a4d82fc | 11 | #![allow(non_camel_case_types)] |
223e47cc | 12 | |
1a4d82fc JJ |
13 | pub use self::FileMatch::*; |
14 | ||
15 | use std::collections::HashSet; | |
16 | use std::io::fs::PathExtensions; | |
17 | use std::io::fs; | |
970d7e83 | 18 | use std::os; |
1a4d82fc JJ |
19 | |
20 | use util::fs as myfs; | |
21 | use session::search_paths::{SearchPaths, PathKind}; | |
22 | ||
23 | #[derive(Copy)] | |
24 | pub enum FileMatch { | |
25 | FileMatches, | |
26 | FileDoesntMatch, | |
27 | } | |
970d7e83 | 28 | |
223e47cc LB |
29 | // A module for searching for libraries |
30 | // FIXME (#2658): I'm not happy how this module turned out. Should | |
31 | // probably just be folded into cstore. | |
32 | ||
1a4d82fc JJ |
33 | pub struct FileSearch<'a> { |
34 | pub sysroot: &'a Path, | |
35 | pub search_paths: &'a SearchPaths, | |
36 | pub triple: &'a str, | |
37 | pub kind: PathKind, | |
223e47cc LB |
38 | } |
39 | ||
1a4d82fc JJ |
40 | impl<'a> FileSearch<'a> { |
41 | pub fn for_each_lib_search_path<F>(&self, mut f: F) where | |
42 | F: FnMut(&Path) -> FileMatch, | |
43 | { | |
44 | let mut visited_dirs = HashSet::new(); | |
45 | let mut found = false; | |
223e47cc | 46 | |
1a4d82fc JJ |
47 | for path in self.search_paths.iter(self.kind) { |
48 | match f(path) { | |
49 | FileMatches => found = true, | |
50 | FileDoesntMatch => () | |
223e47cc | 51 | } |
1a4d82fc | 52 | visited_dirs.insert(path.as_vec().to_vec()); |
223e47cc | 53 | } |
1a4d82fc JJ |
54 | |
55 | debug!("filesearch: searching lib path"); | |
56 | let tlib_path = make_target_lib_path(self.sysroot, | |
57 | self.triple); | |
58 | if !visited_dirs.contains(tlib_path.as_vec()) { | |
59 | match f(&tlib_path) { | |
60 | FileMatches => found = true, | |
61 | FileDoesntMatch => () | |
62 | } | |
223e47cc | 63 | } |
1a4d82fc JJ |
64 | |
65 | visited_dirs.insert(tlib_path.as_vec().to_vec()); | |
66 | // Try RUST_PATH | |
67 | if !found { | |
68 | let rustpath = rust_path(); | |
69 | for path in rustpath.iter() { | |
70 | let tlib_path = make_rustpkg_lib_path( | |
71 | self.sysroot, path, self.triple); | |
72 | debug!("is {} in visited_dirs? {}", tlib_path.display(), | |
73 | visited_dirs.contains(&tlib_path.as_vec().to_vec())); | |
74 | ||
75 | if !visited_dirs.contains(tlib_path.as_vec()) { | |
76 | visited_dirs.insert(tlib_path.as_vec().to_vec()); | |
77 | // Don't keep searching the RUST_PATH if one match turns up -- | |
78 | // if we did, we'd get a "multiple matching crates" error | |
79 | match f(&tlib_path) { | |
80 | FileMatches => { | |
81 | break; | |
82 | } | |
83 | FileDoesntMatch => () | |
84 | } | |
85 | } | |
86 | } | |
223e47cc LB |
87 | } |
88 | } | |
89 | ||
1a4d82fc JJ |
90 | pub fn get_lib_path(&self) -> Path { |
91 | make_target_lib_path(self.sysroot, self.triple) | |
92 | } | |
223e47cc | 93 | |
1a4d82fc JJ |
94 | pub fn search<F>(&self, mut pick: F) where F: FnMut(&Path) -> FileMatch { |
95 | self.for_each_lib_search_path(|lib_search_path| { | |
96 | debug!("searching {}", lib_search_path.display()); | |
97 | match fs::readdir(lib_search_path) { | |
98 | Ok(files) => { | |
99 | let mut rslt = FileDoesntMatch; | |
100 | fn is_rlib(p: & &Path) -> bool { | |
101 | p.extension_str() == Some("rlib") | |
102 | } | |
103 | // Reading metadata out of rlibs is faster, and if we find both | |
104 | // an rlib and a dylib we only read one of the files of | |
105 | // metadata, so in the name of speed, bring all rlib files to | |
106 | // the front of the search list. | |
107 | let files1 = files.iter().filter(|p| is_rlib(p)); | |
108 | let files2 = files.iter().filter(|p| !is_rlib(p)); | |
109 | for path in files1.chain(files2) { | |
110 | debug!("testing {}", path.display()); | |
111 | let maybe_picked = pick(path); | |
112 | match maybe_picked { | |
113 | FileMatches => { | |
114 | debug!("picked {}", path.display()); | |
115 | rslt = FileMatches; | |
116 | } | |
117 | FileDoesntMatch => { | |
118 | debug!("rejected {}", path.display()); | |
119 | } | |
120 | } | |
121 | } | |
122 | rslt | |
123 | } | |
124 | Err(..) => FileDoesntMatch, | |
223e47cc | 125 | } |
1a4d82fc JJ |
126 | }); |
127 | } | |
128 | ||
129 | pub fn new(sysroot: &'a Path, | |
130 | triple: &'a str, | |
131 | search_paths: &'a SearchPaths, | |
132 | kind: PathKind) -> FileSearch<'a> { | |
133 | debug!("using sysroot = {}, triple = {}", sysroot.display(), triple); | |
134 | FileSearch { | |
135 | sysroot: sysroot, | |
136 | search_paths: search_paths, | |
137 | triple: triple, | |
138 | kind: kind, | |
223e47cc | 139 | } |
223e47cc | 140 | } |
1a4d82fc JJ |
141 | |
142 | // Returns a list of directories where target-specific dylibs might be located. | |
143 | pub fn get_dylib_search_paths(&self) -> Vec<Path> { | |
144 | let mut paths = Vec::new(); | |
145 | self.for_each_lib_search_path(|lib_search_path| { | |
146 | paths.push(lib_search_path.clone()); | |
147 | FileDoesntMatch | |
148 | }); | |
149 | paths | |
150 | } | |
151 | ||
152 | // Returns a list of directories where target-specific tool binaries are located. | |
153 | pub fn get_tools_search_paths(&self) -> Vec<Path> { | |
154 | let mut p = Path::new(self.sysroot); | |
155 | p.push(find_libdir(self.sysroot)); | |
156 | p.push(rustlibdir()); | |
157 | p.push(self.triple); | |
158 | p.push("bin"); | |
159 | vec![p] | |
160 | } | |
223e47cc LB |
161 | } |
162 | ||
1a4d82fc JJ |
163 | pub fn relative_target_lib_path(sysroot: &Path, target_triple: &str) -> Path { |
164 | let mut p = Path::new(find_libdir(sysroot)); | |
165 | assert!(p.is_relative()); | |
166 | p.push(rustlibdir()); | |
167 | p.push(target_triple); | |
168 | p.push("lib"); | |
169 | p | |
223e47cc LB |
170 | } |
171 | ||
172 | fn make_target_lib_path(sysroot: &Path, | |
173 | target_triple: &str) -> Path { | |
1a4d82fc | 174 | sysroot.join(&relative_target_lib_path(sysroot, target_triple)) |
223e47cc LB |
175 | } |
176 | ||
1a4d82fc JJ |
177 | fn make_rustpkg_lib_path(sysroot: &Path, |
178 | dir: &Path, | |
179 | triple: &str) -> Path { | |
180 | let mut p = dir.join(find_libdir(sysroot)); | |
181 | p.push(triple); | |
182 | p | |
223e47cc LB |
183 | } |
184 | ||
1a4d82fc JJ |
185 | pub fn get_or_default_sysroot() -> Path { |
186 | // Follow symlinks. If the resolved path is relative, make it absolute. | |
187 | fn canonicalize(path: Option<Path>) -> Option<Path> { | |
188 | path.and_then(|path| | |
189 | match myfs::realpath(&path) { | |
190 | Ok(canon) => Some(canon), | |
191 | Err(e) => panic!("failed to get realpath: {}", e), | |
192 | }) | |
193 | } | |
194 | ||
195 | match canonicalize(os::self_exe_name()) { | |
196 | Some(mut p) => { p.pop(); p.pop(); p } | |
197 | None => panic!("can't determine value for sysroot") | |
223e47cc LB |
198 | } |
199 | } | |
200 | ||
1a4d82fc JJ |
201 | #[cfg(windows)] |
202 | static PATH_ENTRY_SEPARATOR: &'static str = ";"; | |
203 | #[cfg(not(windows))] | |
204 | static PATH_ENTRY_SEPARATOR: &'static str = ":"; | |
205 | ||
206 | /// Returns RUST_PATH as a string, without default paths added | |
207 | pub fn get_rust_path() -> Option<String> { | |
208 | os::getenv("RUST_PATH").map(|x| x.to_string()) | |
223e47cc LB |
209 | } |
210 | ||
1a4d82fc JJ |
211 | /// Returns the value of RUST_PATH, as a list |
212 | /// of Paths. Includes default entries for, if they exist: | |
213 | /// $HOME/.rust | |
214 | /// DIR/.rust for any DIR that's the current working directory | |
215 | /// or an ancestor of it | |
216 | pub fn rust_path() -> Vec<Path> { | |
217 | let mut env_rust_path: Vec<Path> = match get_rust_path() { | |
218 | Some(env_path) => { | |
219 | let env_path_components = | |
220 | env_path.split_str(PATH_ENTRY_SEPARATOR); | |
221 | env_path_components.map(|s| Path::new(s)).collect() | |
222 | } | |
223 | None => Vec::new() | |
224 | }; | |
225 | let mut cwd = os::getcwd().unwrap(); | |
226 | // now add in default entries | |
227 | let cwd_dot_rust = cwd.join(".rust"); | |
228 | if !env_rust_path.contains(&cwd_dot_rust) { | |
229 | env_rust_path.push(cwd_dot_rust); | |
230 | } | |
231 | if !env_rust_path.contains(&cwd) { | |
232 | env_rust_path.push(cwd.clone()); | |
233 | } | |
234 | loop { | |
235 | if { let f = cwd.filename(); f.is_none() || f.unwrap() == b".." } { | |
236 | break | |
237 | } | |
238 | cwd.set_filename(".rust"); | |
239 | if !env_rust_path.contains(&cwd) && cwd.exists() { | |
240 | env_rust_path.push(cwd.clone()); | |
241 | } | |
242 | cwd.pop(); | |
243 | } | |
244 | let h = os::homedir(); | |
245 | for h in h.iter() { | |
246 | let p = h.join(".rust"); | |
247 | if !env_rust_path.contains(&p) && p.exists() { | |
248 | env_rust_path.push(p); | |
223e47cc LB |
249 | } |
250 | } | |
1a4d82fc | 251 | env_rust_path |
223e47cc LB |
252 | } |
253 | ||
1a4d82fc JJ |
254 | // The name of the directory rustc expects libraries to be located. |
255 | // On Unix should be "lib", on windows "bin" | |
256 | #[cfg(unix)] | |
257 | fn find_libdir(sysroot: &Path) -> String { | |
258 | // FIXME: This is a quick hack to make the rustc binary able to locate | |
259 | // Rust libraries in Linux environments where libraries might be installed | |
260 | // to lib64/lib32. This would be more foolproof by basing the sysroot off | |
261 | // of the directory where librustc is located, rather than where the rustc | |
262 | // binary is. | |
263 | //If --libdir is set during configuration to the value other than | |
264 | // "lib" (i.e. non-default), this value is used (see issue #16552). | |
265 | ||
266 | match option_env!("CFG_LIBDIR_RELATIVE") { | |
267 | Some(libdir) if libdir != "lib" => return libdir.to_string(), | |
268 | _ => if sysroot.join(primary_libdir_name()).join(rustlibdir()).exists() { | |
269 | return primary_libdir_name(); | |
270 | } else { | |
271 | return secondary_libdir_name(); | |
223e47cc | 272 | } |
223e47cc | 273 | } |
223e47cc | 274 | |
1a4d82fc JJ |
275 | #[cfg(any(all(stage0, target_word_size = "64"), all(not(stage0), target_pointer_width = "64")))] |
276 | fn primary_libdir_name() -> String { | |
277 | "lib64".to_string() | |
223e47cc | 278 | } |
223e47cc | 279 | |
1a4d82fc JJ |
280 | #[cfg(any(all(stage0, target_word_size = "32"), all(not(stage0), target_pointer_width = "32")))] |
281 | fn primary_libdir_name() -> String { | |
282 | "lib32".to_string() | |
283 | } | |
284 | ||
285 | fn secondary_libdir_name() -> String { | |
286 | "lib".to_string() | |
223e47cc LB |
287 | } |
288 | } | |
289 | ||
1a4d82fc JJ |
290 | #[cfg(windows)] |
291 | fn find_libdir(_sysroot: &Path) -> String { | |
292 | "bin".to_string() | |
293 | } | |
294 | ||
295 | // The name of rustc's own place to organize libraries. | |
296 | // Used to be "rustc", now the default is "rustlib" | |
297 | pub fn rustlibdir() -> String { | |
298 | "rustlib".to_string() | |
223e47cc | 299 | } |