]>
Commit | Line | Data |
---|---|---|
a7813a04 XL |
1 | //! Sanity checking performed by rustbuild before actually executing anything. |
2 | //! | |
3 | //! This module contains the implementation of ensuring that the build | |
4 | //! environment looks reasonable before progressing. This will verify that | |
5 | //! various programs like git and python exist, along with ensuring that all C | |
6 | //! compilers for cross-compiling are found. | |
7 | //! | |
8 | //! In theory if we get past this phase it's a bug if a build fails, but in | |
9 | //! practice that's likely not true! | |
10 | ||
041b39d2 | 11 | use std::collections::HashMap; |
7453a54e | 12 | use std::env; |
dfeec247 | 13 | use std::ffi::{OsStr, OsString}; |
0731742a | 14 | use std::fs; |
041b39d2 | 15 | use std::path::PathBuf; |
2c00a5a8 | 16 | use std::process::Command; |
7453a54e | 17 | |
48663c56 | 18 | use build_helper::{output, t}; |
7453a54e | 19 | |
74b04a01 | 20 | use crate::config::Target; |
0731742a | 21 | use crate::Build; |
7453a54e | 22 | |
1b1a35ee | 23 | pub struct Finder { |
041b39d2 XL |
24 | cache: HashMap<OsString, Option<PathBuf>>, |
25 | path: OsString, | |
26 | } | |
27 | ||
28 | impl Finder { | |
1b1a35ee | 29 | pub fn new() -> Self { |
dfeec247 | 30 | Self { cache: HashMap::new(), path: env::var_os("PATH").unwrap_or_default() } |
041b39d2 XL |
31 | } |
32 | ||
1b1a35ee XL |
33 | pub fn maybe_have<S: Into<OsString>>(&mut self, cmd: S) -> Option<PathBuf> { |
34 | let cmd: OsString = cmd.into(); | |
532ac7d7 | 35 | let path = &self.path; |
dfeec247 XL |
36 | self.cache |
37 | .entry(cmd.clone()) | |
38 | .or_insert_with(|| { | |
39 | for path in env::split_paths(path) { | |
40 | let target = path.join(&cmd); | |
41 | let mut cmd_exe = cmd.clone(); | |
42 | cmd_exe.push(".exe"); | |
43 | ||
44 | if target.is_file() // some/path/git | |
532ac7d7 | 45 | || path.join(&cmd_exe).exists() // some/path/git.exe |
dfeec247 XL |
46 | || target.join(&cmd_exe).exists() |
47 | // some/path/git/git.exe | |
48 | { | |
49 | return Some(target); | |
50 | } | |
041b39d2 | 51 | } |
dfeec247 XL |
52 | None |
53 | }) | |
54 | .clone() | |
041b39d2 XL |
55 | } |
56 | ||
1b1a35ee | 57 | pub fn must_have<S: AsRef<OsStr>>(&mut self, cmd: S) -> PathBuf { |
041b39d2 XL |
58 | self.maybe_have(&cmd).unwrap_or_else(|| { |
59 | panic!("\n\ncouldn't find required command: {:?}\n\n", cmd.as_ref()); | |
60 | }) | |
61 | } | |
62 | } | |
63 | ||
7453a54e | 64 | pub fn check(build: &mut Build) { |
041b39d2 | 65 | let path = env::var_os("PATH").unwrap_or_default(); |
5bcae85e SL |
66 | // On Windows, quotes are invalid characters for filename paths, and if |
67 | // one is present as part of the PATH then that can lead to the system | |
68 | // being unable to identify the files properly. See | |
69 | // https://github.com/rust-lang/rust/issues/34959 for more details. | |
a1dfa0c6 | 70 | if cfg!(windows) && path.to_string_lossy().contains('\"') { |
041b39d2 | 71 | panic!("PATH contains invalid character '\"'"); |
5bcae85e | 72 | } |
7453a54e | 73 | |
041b39d2 | 74 | let mut cmd_finder = Finder::new(); |
ff7c6d11 | 75 | // If we've got a git directory we're gonna need git to update |
7453a54e | 76 | // submodules and learn about various other aspects. |
041b39d2 XL |
77 | if build.rust_info.is_git() { |
78 | cmd_finder.must_have("git"); | |
7453a54e SL |
79 | } |
80 | ||
7cac9316 | 81 | // We need cmake, but only if we're actually building LLVM or sanitizers. |
dfeec247 XL |
82 | let building_llvm = build |
83 | .hosts | |
84 | .iter() | |
85 | .map(|host| { | |
86 | build | |
87 | .config | |
88 | .target_config | |
89 | .get(host) | |
90 | .map(|config| config.llvm_config.is_none()) | |
91 | .unwrap_or(true) | |
92 | }) | |
416331ca | 93 | .any(|build_llvm_ourselves| build_llvm_ourselves); |
7cac9316 | 94 | if building_llvm || build.config.sanitizers { |
041b39d2 | 95 | cmd_finder.must_have("cmake"); |
7cac9316 XL |
96 | } |
97 | ||
dfeec247 XL |
98 | build.config.python = build |
99 | .config | |
100 | .python | |
101 | .take() | |
102 | .map(|p| cmd_finder.must_have(p)) | |
532ac7d7 | 103 | .or_else(|| env::var_os("BOOTSTRAP_PYTHON").map(PathBuf::from)) // set by bootstrap.py |
041b39d2 | 104 | .or_else(|| Some(cmd_finder.must_have("python"))); |
c30ab7b3 | 105 | |
dfeec247 XL |
106 | build.config.nodejs = build |
107 | .config | |
108 | .nodejs | |
109 | .take() | |
110 | .map(|p| cmd_finder.must_have(p)) | |
041b39d2 XL |
111 | .or_else(|| cmd_finder.maybe_have("node")) |
112 | .or_else(|| cmd_finder.maybe_have("nodejs")); | |
9e0c209e | 113 | |
dfeec247 XL |
114 | build.config.gdb = build |
115 | .config | |
116 | .gdb | |
117 | .take() | |
118 | .map(|p| cmd_finder.must_have(p)) | |
041b39d2 | 119 | .or_else(|| cmd_finder.maybe_have("gdb")); |
c30ab7b3 | 120 | |
7453a54e SL |
121 | // We're gonna build some custom C code here and there, host triples |
122 | // also build some C++ shims for LLVM so we need a C++ compiler. | |
3b2f2976 | 123 | for target in &build.targets { |
c30ab7b3 SL |
124 | // On emscripten we don't actually need the C compiler to just |
125 | // build the target artifacts, only for testing. For the sake | |
126 | // of easier bot configuration, just skip detection. | |
127 | if target.contains("emscripten") { | |
128 | continue; | |
129 | } | |
130 | ||
48663c56 XL |
131 | // We don't use a C compiler on wasm32 |
132 | if target.contains("wasm32") { | |
133 | continue; | |
134 | } | |
135 | ||
83c7162d XL |
136 | if !build.config.dry_run { |
137 | cmd_finder.must_have(build.cc(*target)); | |
138 | if let Some(ar) = build.ar(*target) { | |
139 | cmd_finder.must_have(ar); | |
140 | } | |
3157f602 | 141 | } |
7453a54e | 142 | } |
7453a54e | 143 | |
3b2f2976 | 144 | for host in &build.hosts { |
83c7162d XL |
145 | if !build.config.dry_run { |
146 | cmd_finder.must_have(build.cxx(*host).unwrap()); | |
147 | } | |
c30ab7b3 SL |
148 | } |
149 | ||
a7813a04 | 150 | // Externally configured LLVM requires FileCheck to exist |
3b2f2976 | 151 | let filecheck = build.llvm_filecheck(build.build); |
9e0c209e | 152 | if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests { |
32a655c1 | 153 | panic!("FileCheck executable {:?} does not exist", filecheck); |
a7813a04 XL |
154 | } |
155 | ||
3b2f2976 | 156 | for target in &build.targets { |
cc61c64b | 157 | // Can't compile for iOS unless we're on macOS |
dfeec247 | 158 | if target.contains("apple-ios") && !build.build.contains("apple-darwin") { |
cc61c64b | 159 | panic!("the iOS target is only supported on macOS"); |
7453a54e SL |
160 | } |
161 | ||
3dfed10e XL |
162 | build |
163 | .config | |
164 | .target_config | |
165 | .entry(target.clone()) | |
166 | .or_insert(Target::from_triple(&target.triple)); | |
83c7162d | 167 | |
74b04a01 | 168 | if target.contains("-none-") || target.contains("nvptx") { |
83c7162d | 169 | if build.no_std(*target) == Some(false) { |
9fa01778 | 170 | panic!("All the *-none-* and nvptx* targets are no-std targets") |
83c7162d XL |
171 | } |
172 | } | |
173 | ||
3b2f2976 | 174 | // Make sure musl-root is valid |
2c00a5a8 | 175 | if target.contains("musl") { |
3b2f2976 XL |
176 | // If this is a native target (host is also musl) and no musl-root is given, |
177 | // fall back to the system toolchain in /usr before giving up | |
178 | if build.musl_root(*target).is_none() && build.config.build == *target { | |
dfeec247 | 179 | let target = build.config.target_config.entry(target.clone()).or_default(); |
3b2f2976 XL |
180 | target.musl_root = Some("/usr".into()); |
181 | } | |
f035d41b XL |
182 | match build.musl_libdir(*target) { |
183 | Some(libdir) => { | |
184 | if fs::metadata(libdir.join("libc.a")).is_err() { | |
185 | panic!("couldn't find libc.a in musl libdir: {}", libdir.display()); | |
7453a54e | 186 | } |
7453a54e | 187 | } |
dfeec247 XL |
188 | None => panic!( |
189 | "when targeting MUSL either the rust.musl-root \ | |
c30ab7b3 | 190 | option or the target.$TARGET.musl-root option must \ |
dfeec247 XL |
191 | be specified in config.toml" |
192 | ), | |
7453a54e SL |
193 | } |
194 | } | |
195 | ||
196 | if target.contains("msvc") { | |
197 | // There are three builds of cmake on windows: MSVC, MinGW, and | |
198 | // Cygwin. The Cygwin build does not have generators for Visual | |
199 | // Studio, so detect that here and error. | |
200 | let out = output(Command::new("cmake").arg("--help")); | |
201 | if !out.contains("Visual Studio") { | |
dfeec247 XL |
202 | panic!( |
203 | " | |
7453a54e SL |
204 | cmake does not support Visual Studio generators. |
205 | ||
206 | This is likely due to it being an msys/cygwin build of cmake, | |
207 | rather than the required windows version, built using MinGW | |
208 | or Visual Studio. | |
209 | ||
210 | If you are building under msys2 try installing the mingw-w64-x86_64-cmake | |
211 | package instead of cmake: | |
212 | ||
213 | $ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake | |
dfeec247 XL |
214 | " |
215 | ); | |
7453a54e SL |
216 | } |
217 | } | |
218 | } | |
54a0048b | 219 | |
476ff2be | 220 | if let Some(ref s) = build.config.ccache { |
041b39d2 | 221 | cmd_finder.must_have(s); |
476ff2be | 222 | } |
2c00a5a8 XL |
223 | |
224 | if build.config.channel == "stable" { | |
0731742a | 225 | let stage0 = t!(fs::read_to_string(build.src.join("src/stage0.txt"))); |
2c00a5a8 | 226 | if stage0.contains("\ndev:") { |
dfeec247 XL |
227 | panic!( |
228 | "bootstrapping from a dev compiler in a stable release, but \ | |
229 | should only be bootstrapping from a released compiler!" | |
230 | ); | |
2c00a5a8 XL |
231 | } |
232 | } | |
7453a54e | 233 | } |