|
1 | 1 | use std::env; |
| 2 | +use std::fs::read_dir; |
2 | 3 | use std::path::{Path, PathBuf}; |
3 | 4 | use std::process::Command; |
4 | 5 |
|
5 | 6 | use failure::Error; |
6 | 7 |
|
7 | 8 | pub fn find_lib_path() -> Result<PathBuf, Error> { |
8 | | - let paths = collect_possible_paths()?; |
| 9 | + let directories = collect_possible_directories(); |
9 | 10 |
|
10 | | - if paths.is_empty() { |
| 11 | + if directories.is_empty() { |
11 | 12 | bail!("Unable to find possible LLVM shared lib locations."); |
12 | 13 | } |
13 | 14 |
|
14 | | - for path in &paths { |
15 | | - if path.join("librustc_codegen_llvm-llvm.so").exists() { |
16 | | - return Ok(path.join("librustc_codegen_llvm-llvm.so")); |
17 | | - } |
18 | | - |
19 | | - if path.join("librustc_codegen_llvm-llvm.dylib").exists() { |
20 | | - return Ok(path.join("librustc_codegen_llvm-llvm.dylib")); |
21 | | - } |
22 | | - |
23 | | - if path.join("rustc_codegen_llvm-llvm.dll").exists() { |
24 | | - return Ok(path.join("rustc_codegen_llvm-llvm.dll")); |
| 15 | + for directory in &directories { |
| 16 | + if let Some(library) = find_library_in_directory(&directory) { |
| 17 | + return Ok(library); |
25 | 18 | } |
26 | 19 | } |
27 | 20 |
|
28 | 21 | bail!( |
29 | 22 | "Unable to find LLVM shared lib in possible locations:\n- {}", |
30 | | - paths |
| 23 | + directories |
31 | 24 | .into_iter() |
32 | 25 | .map(|item| item.to_str().unwrap().to_owned()) |
33 | 26 | .collect::<Vec<_>>() |
34 | 27 | .join("\n- ") |
35 | 28 | ); |
36 | 29 | } |
37 | 30 |
|
38 | | -fn collect_possible_paths() -> Result<Vec<PathBuf>, Error> { |
| 31 | +fn collect_possible_directories() -> Vec<PathBuf> { |
39 | 32 | let mut paths = vec![]; |
40 | 33 |
|
41 | | - // Special case: find the location for Rust built from sources. |
42 | | - if let Ok(env_path) = env::var("PATH") { |
43 | | - for item in env_path.split(':') { |
44 | | - let mut rustc_path = PathBuf::from(item); |
45 | | - |
46 | | - rustc_path.pop(); |
47 | | - paths.push(rustc_path.join("codegen-backends")); |
48 | | - } |
49 | | - } |
50 | | - |
51 | | - if let Ok(rustup_home) = env::var("RUSTUP_HOME") { |
52 | | - let rustup_home = PathBuf::from(rustup_home); |
53 | | - let rustup_toolchain = env::var("RUSTUP_TOOLCHAIN")?; |
54 | | - let rustup_arch = extract_arch(&rustup_toolchain); |
55 | | - |
56 | | - paths.push( |
57 | | - rustup_home |
58 | | - .join("toolchains") |
59 | | - .join(&rustup_toolchain) |
60 | | - .join("lib") |
61 | | - .join("rustlib") |
62 | | - .join(rustup_arch) |
63 | | - .join("codegen-backends"), |
64 | | - ); |
65 | | - } |
66 | | - |
67 | 34 | if let Ok(lib_paths) = env::var("LD_LIBRARY_PATH") { |
68 | 35 | for item in lib_paths.split(':') { |
69 | | - let mut possible_path = PathBuf::from(item); |
70 | | - possible_path.pop(); |
71 | | - |
72 | | - if let Some(possible_toolchain) = possible_path.file_name() { |
73 | | - let possible_arch = extract_arch(possible_toolchain.to_str().unwrap()); |
74 | | - |
75 | | - paths.push( |
76 | | - possible_path |
77 | | - .join("lib") |
78 | | - .join("rustlib") |
79 | | - .join(possible_arch) |
80 | | - .join("codegen-backends"), |
81 | | - ); |
82 | | - } |
| 36 | + paths.push(PathBuf::from(item)); |
83 | 37 | } |
84 | 38 | } |
85 | 39 |
|
86 | | - if let Ok(cargo) = env::var("CARGO") { |
87 | | - let mut cargo_path = PathBuf::from(cargo); |
88 | | - cargo_path.pop(); |
89 | | - cargo_path.pop(); |
90 | | - |
91 | | - if let Some(toolchain) = cargo_path.file_name() { |
92 | | - let arch = env::var("HOST").unwrap_or_else(|_| extract_arch(toolchain.to_str().unwrap())); |
93 | | - |
94 | | - paths.push( |
95 | | - cargo_path |
96 | | - .join("lib") |
97 | | - .join("rustlib") |
98 | | - .join(arch) |
99 | | - .join("codegen-backends"), |
100 | | - ); |
101 | | - } |
102 | | - } |
103 | | - |
104 | | - if let Some(rustc) = find_rustc() { |
105 | | - if let Ok(output) = Command::new(&rustc).args(&["--print", "sysroot"]).output() { |
106 | | - let mut sysroot = PathBuf::from(String::from_utf8_lossy(&output.stdout).trim()); |
107 | | - if let Some(arch) = find_arch(&rustc, &sysroot) { |
108 | | - paths.push( |
109 | | - sysroot |
110 | | - .join("lib") |
111 | | - .join("rustlib") |
112 | | - .join(arch) |
113 | | - .join("codegen-backends"), |
114 | | - ); |
115 | | - } |
116 | | - } |
117 | | - } |
118 | | - |
119 | | - if let Ok(output) = Command::new("rustup").args(&["which", "rustc"]).output() { |
120 | | - let mut rustc_path = PathBuf::from(String::from_utf8_lossy(&output.stdout).trim()); |
121 | | - rustc_path.pop(); |
122 | | - rustc_path.pop(); |
123 | | - |
124 | | - if let Some(toolchain) = rustc_path.file_name() { |
125 | | - let arch = extract_arch(toolchain.to_str().unwrap()); |
| 40 | + if let Ok(bin_paths) = env::var("PATH") { |
| 41 | + for item in bin_paths.split(':') { |
| 42 | + let mut possible_path = PathBuf::from(item); |
126 | 43 |
|
127 | | - paths.push( |
128 | | - rustc_path |
129 | | - .join("lib") |
130 | | - .join("rustlib") |
131 | | - .join(arch) |
132 | | - .join("codegen-backends"), |
133 | | - ); |
| 44 | + possible_path.pop(); |
| 45 | + possible_path.push("lib"); |
| 46 | + paths.push(possible_path); |
134 | 47 | } |
135 | 48 | } |
136 | 49 |
|
137 | | - Ok(paths) |
| 50 | + paths |
138 | 51 | } |
139 | 52 |
|
140 | | -// Fails if using nightly build from a specific date |
141 | | -// e.g. nightly-2018-11-30-x86_64-unknown-linux-gnu |
142 | | -fn extract_arch(toolchain: &str) -> String { |
143 | | - toolchain |
144 | | - .split('-') |
145 | | - // Skip `nightly` rust version prefix. |
146 | | - .skip(1) |
147 | | - // Also skip rust version specification if exists. |
148 | | - .skip_while(|item| match item.chars().next() { |
149 | | - None | Some('0'...'9') => true, |
150 | | - _ => false, |
151 | | - }) |
152 | | - .collect::<Vec<_>>() |
153 | | - .join("-") |
154 | | -} |
| 53 | +fn find_library_in_directory(directory: &Path) -> Option<PathBuf> { |
| 54 | + match read_dir(directory) { |
| 55 | + Ok(files) => files |
| 56 | + .filter_map(Result::ok) |
| 57 | + .find(|file| file.file_name().to_string_lossy().starts_with("libLLVM")) |
| 58 | + .map(|file| file.path()), |
155 | 59 |
|
156 | | -fn find_rustc() -> Option<PathBuf> { |
157 | | - if let Some(path) = env::var_os("RUSTC") { |
158 | | - Some(path.into()) |
159 | | - } else if let Ok(output) = Command::new("rustup").args(&["which", "rustc"]).output() { |
160 | | - Some(String::from_utf8_lossy(&output.stdout).trim().into()) |
161 | | - } else { |
162 | | - None |
163 | | - } |
164 | | -} |
165 | | - |
166 | | -fn find_arch(rustc: &Path, sysroot: &Path) -> Option<String> { |
167 | | - if let Ok(path) = env::var("HOST") { |
168 | | - Some(path) |
169 | | - } else if let Ok(output) = Command::new(&rustc).args(&["-vV"]).output() { |
170 | | - for line in String::from_utf8_lossy(&output.stdout).lines() { |
171 | | - if line.starts_with("host") { |
172 | | - return Some(line.trim_start_matches("host:").trim().to_string()); |
173 | | - } |
174 | | - } |
175 | | - None |
176 | | - } else if let Some(toolchain) = sysroot.file_name() { |
177 | | - Some(extract_arch(toolchain.to_str().unwrap())) |
178 | | - } else { |
179 | | - None |
| 60 | + Err(_) => None, |
180 | 61 | } |
181 | 62 | } |
0 commit comments