]>
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; | |
85aaf69f | 16 | use std::env; |
c34b1796 AL |
17 | use std::fs; |
18 | use std::io::prelude::*; | |
19 | use std::path::{Path, PathBuf}; | |
1a4d82fc | 20 | |
1a4d82fc | 21 | use session::search_paths::{SearchPaths, PathKind}; |
d9579d0f | 22 | use util::fs as rustcfs; |
1a4d82fc | 23 | |
c34b1796 | 24 | #[derive(Copy, Clone)] |
1a4d82fc JJ |
25 | pub enum FileMatch { |
26 | FileMatches, | |
27 | FileDoesntMatch, | |
28 | } | |
970d7e83 | 29 | |
223e47cc LB |
30 | // A module for searching for libraries |
31 | // FIXME (#2658): I'm not happy how this module turned out. Should | |
32 | // probably just be folded into cstore. | |
33 | ||
1a4d82fc JJ |
34 | pub struct FileSearch<'a> { |
35 | pub sysroot: &'a Path, | |
36 | pub search_paths: &'a SearchPaths, | |
37 | pub triple: &'a str, | |
38 | pub kind: PathKind, | |
223e47cc LB |
39 | } |
40 | ||
1a4d82fc JJ |
41 | impl<'a> FileSearch<'a> { |
42 | pub fn for_each_lib_search_path<F>(&self, mut f: F) where | |
92a42be0 | 43 | F: FnMut(&Path, PathKind) |
1a4d82fc JJ |
44 | { |
45 | let mut visited_dirs = HashSet::new(); | |
223e47cc | 46 | |
85aaf69f | 47 | for (path, kind) in self.search_paths.iter(self.kind) { |
92a42be0 | 48 | f(path, kind); |
c34b1796 | 49 | visited_dirs.insert(path.to_path_buf()); |
223e47cc | 50 | } |
1a4d82fc JJ |
51 | |
52 | debug!("filesearch: searching lib path"); | |
53 | let tlib_path = make_target_lib_path(self.sysroot, | |
85aaf69f | 54 | self.triple); |
c34b1796 | 55 | if !visited_dirs.contains(&tlib_path) { |
92a42be0 | 56 | f(&tlib_path, PathKind::All); |
223e47cc | 57 | } |
1a4d82fc | 58 | |
c34b1796 | 59 | visited_dirs.insert(tlib_path); |
223e47cc LB |
60 | } |
61 | ||
c34b1796 | 62 | pub fn get_lib_path(&self) -> PathBuf { |
1a4d82fc JJ |
63 | make_target_lib_path(self.sysroot, self.triple) |
64 | } | |
223e47cc | 65 | |
85aaf69f SL |
66 | pub fn search<F>(&self, mut pick: F) |
67 | where F: FnMut(&Path, PathKind) -> FileMatch | |
68 | { | |
69 | self.for_each_lib_search_path(|lib_search_path, kind| { | |
1a4d82fc | 70 | debug!("searching {}", lib_search_path.display()); |
c34b1796 | 71 | match fs::read_dir(lib_search_path) { |
1a4d82fc | 72 | Ok(files) => { |
c34b1796 AL |
73 | let files = files.filter_map(|p| p.ok().map(|s| s.path())) |
74 | .collect::<Vec<_>>(); | |
c34b1796 AL |
75 | fn is_rlib(p: &Path) -> bool { |
76 | p.extension().and_then(|s| s.to_str()) == Some("rlib") | |
1a4d82fc JJ |
77 | } |
78 | // Reading metadata out of rlibs is faster, and if we find both | |
79 | // an rlib and a dylib we only read one of the files of | |
80 | // metadata, so in the name of speed, bring all rlib files to | |
81 | // the front of the search list. | |
82 | let files1 = files.iter().filter(|p| is_rlib(p)); | |
83 | let files2 = files.iter().filter(|p| !is_rlib(p)); | |
84 | for path in files1.chain(files2) { | |
85 | debug!("testing {}", path.display()); | |
85aaf69f | 86 | let maybe_picked = pick(path, kind); |
1a4d82fc JJ |
87 | match maybe_picked { |
88 | FileMatches => { | |
89 | debug!("picked {}", path.display()); | |
1a4d82fc JJ |
90 | } |
91 | FileDoesntMatch => { | |
92 | debug!("rejected {}", path.display()); | |
93 | } | |
94 | } | |
95 | } | |
1a4d82fc | 96 | } |
92a42be0 | 97 | Err(..) => (), |
223e47cc | 98 | } |
1a4d82fc JJ |
99 | }); |
100 | } | |
101 | ||
102 | pub fn new(sysroot: &'a Path, | |
103 | triple: &'a str, | |
104 | search_paths: &'a SearchPaths, | |
105 | kind: PathKind) -> FileSearch<'a> { | |
106 | debug!("using sysroot = {}, triple = {}", sysroot.display(), triple); | |
107 | FileSearch { | |
108 | sysroot: sysroot, | |
109 | search_paths: search_paths, | |
110 | triple: triple, | |
111 | kind: kind, | |
223e47cc | 112 | } |
223e47cc | 113 | } |
1a4d82fc JJ |
114 | |
115 | // Returns a list of directories where target-specific dylibs might be located. | |
c34b1796 | 116 | pub fn get_dylib_search_paths(&self) -> Vec<PathBuf> { |
1a4d82fc | 117 | let mut paths = Vec::new(); |
85aaf69f | 118 | self.for_each_lib_search_path(|lib_search_path, _| { |
c34b1796 | 119 | paths.push(lib_search_path.to_path_buf()); |
1a4d82fc JJ |
120 | }); |
121 | paths | |
122 | } | |
123 | ||
124 | // Returns a list of directories where target-specific tool binaries are located. | |
c34b1796 AL |
125 | pub fn get_tools_search_paths(&self) -> Vec<PathBuf> { |
126 | let mut p = PathBuf::from(self.sysroot); | |
127 | p.push(&find_libdir(self.sysroot)); | |
128 | p.push(&rustlibdir()); | |
129 | p.push(&self.triple); | |
1a4d82fc JJ |
130 | p.push("bin"); |
131 | vec![p] | |
132 | } | |
223e47cc LB |
133 | } |
134 | ||
c34b1796 AL |
135 | pub fn relative_target_lib_path(sysroot: &Path, target_triple: &str) -> PathBuf { |
136 | let mut p = PathBuf::from(&find_libdir(sysroot)); | |
1a4d82fc | 137 | assert!(p.is_relative()); |
c34b1796 | 138 | p.push(&rustlibdir()); |
1a4d82fc JJ |
139 | p.push(target_triple); |
140 | p.push("lib"); | |
141 | p | |
223e47cc LB |
142 | } |
143 | ||
144 | fn make_target_lib_path(sysroot: &Path, | |
c34b1796 | 145 | target_triple: &str) -> PathBuf { |
1a4d82fc | 146 | sysroot.join(&relative_target_lib_path(sysroot, target_triple)) |
223e47cc LB |
147 | } |
148 | ||
c34b1796 | 149 | pub fn get_or_default_sysroot() -> PathBuf { |
1a4d82fc | 150 | // Follow symlinks. If the resolved path is relative, make it absolute. |
c34b1796 AL |
151 | fn canonicalize(path: Option<PathBuf>) -> Option<PathBuf> { |
152 | path.and_then(|path| { | |
d9579d0f AL |
153 | match fs::canonicalize(&path) { |
154 | // See comments on this target function, but the gist is that | |
155 | // gcc chokes on verbatim paths which fs::canonicalize generates | |
156 | // so we try to avoid those kinds of paths. | |
157 | Ok(canon) => Some(rustcfs::fix_windows_verbatim_for_gcc(&canon)), | |
54a0048b | 158 | Err(e) => bug!("failed to get realpath: {}", e), |
c34b1796 AL |
159 | } |
160 | }) | |
1a4d82fc JJ |
161 | } |
162 | ||
85aaf69f | 163 | match canonicalize(env::current_exe().ok()) { |
1a4d82fc | 164 | Some(mut p) => { p.pop(); p.pop(); p } |
54a0048b | 165 | None => bug!("can't determine value for sysroot") |
223e47cc LB |
166 | } |
167 | } | |
168 | ||
1a4d82fc | 169 | // The name of the directory rustc expects libraries to be located. |
1a4d82fc JJ |
170 | fn find_libdir(sysroot: &Path) -> String { |
171 | // FIXME: This is a quick hack to make the rustc binary able to locate | |
172 | // Rust libraries in Linux environments where libraries might be installed | |
173 | // to lib64/lib32. This would be more foolproof by basing the sysroot off | |
174 | // of the directory where librustc is located, rather than where the rustc | |
175 | // binary is. | |
176 | //If --libdir is set during configuration to the value other than | |
177 | // "lib" (i.e. non-default), this value is used (see issue #16552). | |
178 | ||
179 | match option_env!("CFG_LIBDIR_RELATIVE") { | |
180 | Some(libdir) if libdir != "lib" => return libdir.to_string(), | |
c34b1796 | 181 | _ => if sysroot.join(&primary_libdir_name()).join(&rustlibdir()).exists() { |
1a4d82fc JJ |
182 | return primary_libdir_name(); |
183 | } else { | |
184 | return secondary_libdir_name(); | |
223e47cc | 185 | } |
223e47cc | 186 | } |
223e47cc | 187 | |
85aaf69f | 188 | #[cfg(target_pointer_width = "64")] |
1a4d82fc JJ |
189 | fn primary_libdir_name() -> String { |
190 | "lib64".to_string() | |
223e47cc | 191 | } |
223e47cc | 192 | |
85aaf69f | 193 | #[cfg(target_pointer_width = "32")] |
1a4d82fc JJ |
194 | fn primary_libdir_name() -> String { |
195 | "lib32".to_string() | |
196 | } | |
197 | ||
198 | fn secondary_libdir_name() -> String { | |
199 | "lib".to_string() | |
223e47cc LB |
200 | } |
201 | } | |
202 | ||
1a4d82fc JJ |
203 | // The name of rustc's own place to organize libraries. |
204 | // Used to be "rustc", now the default is "rustlib" | |
205 | pub fn rustlibdir() -> String { | |
206 | "rustlib".to_string() | |
223e47cc | 207 | } |