]>
Commit | Line | Data |
---|---|---|
3b2f2976 XL |
1 | use std::fs; |
2 | use std::env; | |
3 | use std::path::PathBuf; | |
ff7c6d11 | 4 | use std::process::{Command, exit}; |
8faf50e0 | 5 | use std::collections::HashSet; |
3b2f2976 | 6 | |
48663c56 XL |
7 | use build_helper::t; |
8 | ||
0731742a XL |
9 | use crate::Mode; |
10 | use crate::Compiler; | |
11 | use crate::builder::{Step, RunConfig, ShouldRun, Builder}; | |
416331ca | 12 | use crate::util::{exe, add_lib_path, CiEnv}; |
0731742a | 13 | use crate::compile; |
0731742a XL |
14 | use crate::channel::GitInfo; |
15 | use crate::channel; | |
16 | use crate::cache::Interned; | |
17 | use crate::toolstate::ToolState; | |
3b2f2976 | 18 | |
8faf50e0 XL |
19 | #[derive(Debug, Clone, Hash, PartialEq, Eq)] |
20 | pub enum SourceType { | |
21 | InTree, | |
22 | Submodule, | |
23 | } | |
24 | ||
0531ce1d | 25 | #[derive(Debug, Clone, Hash, PartialEq, Eq)] |
3b2f2976 XL |
26 | struct ToolBuild { |
27 | compiler: Compiler, | |
28 | target: Interned<String>, | |
29 | tool: &'static str, | |
ea8adc8c | 30 | path: &'static str, |
3b2f2976 | 31 | mode: Mode, |
8faf50e0 XL |
32 | is_optional_tool: bool, |
33 | source_type: SourceType, | |
0531ce1d | 34 | extra_features: Vec<String>, |
3b2f2976 XL |
35 | } |
36 | ||
37 | impl Step for ToolBuild { | |
abe05a73 | 38 | type Output = Option<PathBuf>; |
3b2f2976 | 39 | |
9fa01778 | 40 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
3b2f2976 XL |
41 | run.never() |
42 | } | |
43 | ||
9fa01778 | 44 | /// Builds a tool in `src/tools` |
3b2f2976 XL |
45 | /// |
46 | /// This will build the specified tool with the specified `host` compiler in | |
47 | /// `stage` into the normal cargo output directory. | |
9fa01778 | 48 | fn run(self, builder: &Builder<'_>) -> Option<PathBuf> { |
3b2f2976 XL |
49 | let compiler = self.compiler; |
50 | let target = self.target; | |
51 | let tool = self.tool; | |
ea8adc8c | 52 | let path = self.path; |
8faf50e0 | 53 | let is_optional_tool = self.is_optional_tool; |
3b2f2976 XL |
54 | |
55 | match self.mode { | |
8faf50e0 XL |
56 | Mode::ToolRustc => { |
57 | builder.ensure(compile::Rustc { compiler, target }) | |
58 | } | |
59 | Mode::ToolStd => { | |
60 | builder.ensure(compile::Std { compiler, target }) | |
61 | } | |
62 | Mode::ToolBootstrap => {} // uses downloaded stage0 compiler libs | |
94b46f34 | 63 | _ => panic!("unexpected Mode for tool build") |
3b2f2976 XL |
64 | } |
65 | ||
8faf50e0 XL |
66 | let mut cargo = prepare_tool_cargo( |
67 | builder, | |
68 | compiler, | |
69 | self.mode, | |
70 | target, | |
71 | "build", | |
72 | path, | |
73 | self.source_type, | |
0bf4aa26 | 74 | &self.extra_features, |
8faf50e0 | 75 | ); |
0531ce1d | 76 | |
83c7162d | 77 | builder.info(&format!("Building stage{} tool {} ({})", compiler.stage, tool, target)); |
0531ce1d | 78 | let mut duplicates = Vec::new(); |
dc9dc135 | 79 | let is_expected = compile::stream_cargo(builder, &mut cargo, vec![], &mut |msg| { |
0531ce1d | 80 | // Only care about big things like the RLS/Cargo for now |
8faf50e0 XL |
81 | match tool { |
82 | | "rls" | |
83 | | "cargo" | |
84 | | "clippy-driver" | |
0731742a | 85 | | "miri" |
dc9dc135 | 86 | | "rustfmt" |
8faf50e0 XL |
87 | => {} |
88 | ||
89 | _ => return, | |
0531ce1d XL |
90 | } |
91 | let (id, features, filenames) = match msg { | |
92 | compile::CargoMessage::CompilerArtifact { | |
93 | package_id, | |
94 | features, | |
532ac7d7 XL |
95 | filenames, |
96 | target: _, | |
0531ce1d XL |
97 | } => { |
98 | (package_id, features, filenames) | |
99 | } | |
100 | _ => return, | |
101 | }; | |
102 | let features = features.iter().map(|s| s.to_string()).collect::<Vec<_>>(); | |
103 | ||
104 | for path in filenames { | |
105 | let val = (tool, PathBuf::from(&*path), features.clone()); | |
106 | // we're only interested in deduplicating rlibs for now | |
107 | if val.1.extension().and_then(|s| s.to_str()) != Some("rlib") { | |
108 | continue | |
109 | } | |
110 | ||
416331ca XL |
111 | // Don't worry about compiles that turn out to be host |
112 | // dependencies or build scripts. To skip these we look for | |
113 | // anything that goes in `.../release/deps` but *doesn't* go in | |
114 | // `$target/release/deps`. This ensure that outputs in | |
115 | // `$target/release` are still considered candidates for | |
116 | // deduplication. | |
117 | if let Some(parent) = val.1.parent() { | |
118 | if parent.ends_with("release/deps") { | |
119 | let maybe_target = parent | |
120 | .parent() | |
121 | .and_then(|p| p.parent()) | |
122 | .and_then(|p| p.file_name()) | |
123 | .and_then(|p| p.to_str()) | |
124 | .unwrap(); | |
125 | if maybe_target != &*target { | |
126 | continue; | |
127 | } | |
0531ce1d XL |
128 | } |
129 | } | |
130 | ||
416331ca XL |
131 | // Record that we've built an artifact for `id`, and if one was |
132 | // already listed then we need to see if we reused the same | |
133 | // artifact or produced a duplicate. | |
83c7162d | 134 | let mut artifacts = builder.tool_artifacts.borrow_mut(); |
0531ce1d XL |
135 | let prev_artifacts = artifacts |
136 | .entry(target) | |
b7449926 | 137 | .or_default(); |
416331ca XL |
138 | let prev = match prev_artifacts.get(&*id) { |
139 | Some(prev) => prev, | |
140 | None => { | |
141 | prev_artifacts.insert(id.to_string(), val); | |
142 | continue; | |
0531ce1d | 143 | } |
416331ca XL |
144 | }; |
145 | if prev.1 == val.1 { | |
146 | return; // same path, same artifact | |
0531ce1d | 147 | } |
416331ca XL |
148 | |
149 | // If the paths are different and one of them *isn't* inside of | |
150 | // `release/deps`, then it means it's probably in | |
151 | // `$target/release`, or it's some final artifact like | |
152 | // `libcargo.rlib`. In these situations Cargo probably just | |
153 | // copied it up from `$target/release/deps/libcargo-xxxx.rlib`, | |
154 | // so if the features are equal we can just skip it. | |
155 | let prev_no_hash = prev.1.parent().unwrap().ends_with("release/deps"); | |
156 | let val_no_hash = val.1.parent().unwrap().ends_with("release/deps"); | |
157 | if prev.2 == val.2 || !prev_no_hash || !val_no_hash { | |
158 | return; | |
159 | } | |
160 | ||
161 | // ... and otherwise this looks like we duplicated some sort of | |
162 | // compilation, so record it to generate an error later. | |
163 | duplicates.push(( | |
164 | id.to_string(), | |
165 | val, | |
166 | prev.clone(), | |
167 | )); | |
0531ce1d XL |
168 | } |
169 | }); | |
170 | ||
a1dfa0c6 | 171 | if is_expected && !duplicates.is_empty() { |
0731742a | 172 | println!("duplicate artifacts found when compiling a tool, this \ |
0531ce1d XL |
173 | typically means that something was recompiled because \ |
174 | a transitive dependency has different features activated \ | |
175 | than in a previous build:\n"); | |
8faf50e0 XL |
176 | println!("the following dependencies are duplicated although they \ |
177 | have the same features enabled:"); | |
178 | for (id, cur, prev) in duplicates.drain_filter(|(_, cur, prev)| cur.2 == prev.2) { | |
179 | println!(" {}", id); | |
180 | // same features | |
181 | println!(" `{}` ({:?})\n `{}` ({:?})", cur.0, cur.1, prev.0, prev.1); | |
182 | } | |
183 | println!("the following dependencies have different features:"); | |
0531ce1d XL |
184 | for (id, cur, prev) in duplicates { |
185 | println!(" {}", id); | |
8faf50e0 XL |
186 | let cur_features: HashSet<_> = cur.2.into_iter().collect(); |
187 | let prev_features: HashSet<_> = prev.2.into_iter().collect(); | |
188 | println!(" `{}` additionally enabled features {:?} at {:?}", | |
189 | cur.0, &cur_features - &prev_features, cur.1); | |
190 | println!(" `{}` additionally enabled features {:?} at {:?}", | |
191 | prev.0, &prev_features - &cur_features, prev.1); | |
0531ce1d | 192 | } |
a1dfa0c6 | 193 | println!(); |
b7449926 XL |
194 | println!("to fix this you will probably want to edit the local \ |
195 | src/tools/rustc-workspace-hack/Cargo.toml crate, as \ | |
196 | that will update the dependency graph to ensure that \ | |
197 | these crates all share the same feature set"); | |
0531ce1d XL |
198 | panic!("tools should not compile multiple copies of the same crate"); |
199 | } | |
3b2f2976 | 200 | |
83c7162d | 201 | builder.save_toolstate(tool, if is_expected { |
ff7c6d11 XL |
202 | ToolState::TestFail |
203 | } else { | |
204 | ToolState::BuildFail | |
205 | }); | |
206 | ||
207 | if !is_expected { | |
8faf50e0 | 208 | if !is_optional_tool { |
ff7c6d11 XL |
209 | exit(1); |
210 | } else { | |
a1dfa0c6 | 211 | None |
ff7c6d11 XL |
212 | } |
213 | } else { | |
94b46f34 | 214 | let cargo_out = builder.cargo_out(compiler, self.mode, target) |
abe05a73 | 215 | .join(exe(tool, &compiler.host)); |
83c7162d XL |
216 | let bin = builder.tools_dir(compiler).join(exe(tool, &compiler.host)); |
217 | builder.copy(&cargo_out, &bin); | |
abe05a73 | 218 | Some(bin) |
abe05a73 | 219 | } |
3b2f2976 XL |
220 | } |
221 | } | |
222 | ||
ea8adc8c | 223 | pub fn prepare_tool_cargo( |
9fa01778 | 224 | builder: &Builder<'_>, |
3b2f2976 | 225 | compiler: Compiler, |
94b46f34 | 226 | mode: Mode, |
3b2f2976 | 227 | target: Interned<String>, |
ea8adc8c XL |
228 | command: &'static str, |
229 | path: &'static str, | |
8faf50e0 | 230 | source_type: SourceType, |
0bf4aa26 | 231 | extra_features: &[String], |
3b2f2976 | 232 | ) -> Command { |
94b46f34 | 233 | let mut cargo = builder.cargo(compiler, mode, target, command); |
83c7162d | 234 | let dir = builder.src.join(path); |
3b2f2976 XL |
235 | cargo.arg("--manifest-path").arg(dir.join("Cargo.toml")); |
236 | ||
237 | // We don't want to build tools dynamically as they'll be running across | |
238 | // stages and such and it's just easier if they're not dynamically linked. | |
239 | cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1"); | |
240 | ||
8faf50e0 XL |
241 | if source_type == SourceType::Submodule { |
242 | cargo.env("RUSTC_EXTERNAL_TOOL", "1"); | |
243 | } | |
244 | ||
0bf4aa26 XL |
245 | let mut features = extra_features.iter().cloned().collect::<Vec<_>>(); |
246 | if builder.build.config.cargo_native_static { | |
247 | if path.ends_with("cargo") || | |
248 | path.ends_with("rls") || | |
249 | path.ends_with("clippy") || | |
0731742a | 250 | path.ends_with("miri") || |
0bf4aa26 XL |
251 | path.ends_with("rustfmt") |
252 | { | |
253 | cargo.env("LIBZ_SYS_STATIC", "1"); | |
254 | features.push("rustc-workspace-hack/all-static".to_string()); | |
255 | } | |
3b2f2976 XL |
256 | } |
257 | ||
ea8adc8c XL |
258 | // if tools are using lzma we want to force the build script to build its |
259 | // own copy | |
260 | cargo.env("LZMA_API_STATIC", "1"); | |
261 | ||
83c7162d XL |
262 | cargo.env("CFG_RELEASE_CHANNEL", &builder.config.channel); |
263 | cargo.env("CFG_VERSION", builder.rust_version()); | |
13cf67c4 | 264 | cargo.env("CFG_RELEASE_NUM", channel::CFG_RELEASE_NUM); |
3b2f2976 | 265 | |
532ac7d7 | 266 | let info = GitInfo::new(builder.config.ignore_git, &dir); |
3b2f2976 XL |
267 | if let Some(sha) = info.sha() { |
268 | cargo.env("CFG_COMMIT_HASH", sha); | |
269 | } | |
270 | if let Some(sha_short) = info.sha_short() { | |
271 | cargo.env("CFG_SHORT_COMMIT_HASH", sha_short); | |
272 | } | |
273 | if let Some(date) = info.commit_date() { | |
274 | cargo.env("CFG_COMMIT_DATE", date); | |
275 | } | |
a1dfa0c6 | 276 | if !features.is_empty() { |
0bf4aa26 XL |
277 | cargo.arg("--features").arg(&features.join(", ")); |
278 | } | |
3b2f2976 XL |
279 | cargo |
280 | } | |
281 | ||
416331ca XL |
282 | fn rustbook_features() -> Vec<String> { |
283 | let mut features = Vec::new(); | |
284 | ||
285 | // Due to CI budged and risk of spurious failures we want to limit jobs running this check. | |
286 | // At same time local builds should run it regardless of the platform. | |
287 | // `CiEnv::None` means it's local build and `CHECK_LINKS` is defined in x86_64-gnu-tools to | |
288 | // explicitly enable it on single job | |
289 | if CiEnv::current() == CiEnv::None || env::var("CHECK_LINKS").is_ok() { | |
290 | features.push("linkcheck".to_string()); | |
291 | } | |
292 | ||
293 | features | |
294 | } | |
295 | ||
532ac7d7 | 296 | macro_rules! bootstrap_tool { |
a1dfa0c6 | 297 | ($( |
532ac7d7 | 298 | $name:ident, $path:expr, $tool_name:expr |
a1dfa0c6 XL |
299 | $(,llvm_tools = $llvm:expr)* |
300 | $(,is_external_tool = $external:expr)* | |
416331ca | 301 | $(,features = $features:expr)* |
a1dfa0c6 XL |
302 | ; |
303 | )+) => { | |
8faf50e0 | 304 | #[derive(Copy, PartialEq, Eq, Clone)] |
3b2f2976 XL |
305 | pub enum Tool { |
306 | $( | |
307 | $name, | |
308 | )+ | |
309 | } | |
310 | ||
94b46f34 | 311 | impl Tool { |
94b46f34 XL |
312 | /// Whether this tool requires LLVM to run |
313 | pub fn uses_llvm_tools(&self) -> bool { | |
314 | match self { | |
315 | $(Tool::$name => false $(|| $llvm)*,)+ | |
316 | } | |
317 | } | |
318 | } | |
319 | ||
3b2f2976 XL |
320 | impl<'a> Builder<'a> { |
321 | pub fn tool_exe(&self, tool: Tool) -> PathBuf { | |
322 | match tool { | |
323 | $(Tool::$name => | |
324 | self.ensure($name { | |
532ac7d7 | 325 | compiler: self.compiler(0, self.config.build), |
83c7162d | 326 | target: self.config.build, |
3b2f2976 XL |
327 | }), |
328 | )+ | |
329 | } | |
330 | } | |
331 | } | |
332 | ||
333 | $( | |
334 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] | |
335 | pub struct $name { | |
336 | pub compiler: Compiler, | |
337 | pub target: Interned<String>, | |
338 | } | |
339 | ||
340 | impl Step for $name { | |
341 | type Output = PathBuf; | |
342 | ||
9fa01778 | 343 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
3b2f2976 XL |
344 | run.path($path) |
345 | } | |
346 | ||
9fa01778 | 347 | fn make_run(run: RunConfig<'_>) { |
3b2f2976 | 348 | run.builder.ensure($name { |
532ac7d7 XL |
349 | // snapshot compiler |
350 | compiler: run.builder.compiler(0, run.builder.config.build), | |
3b2f2976 XL |
351 | target: run.target, |
352 | }); | |
353 | } | |
354 | ||
9fa01778 | 355 | fn run(self, builder: &Builder<'_>) -> PathBuf { |
3b2f2976 XL |
356 | builder.ensure(ToolBuild { |
357 | compiler: self.compiler, | |
358 | target: self.target, | |
359 | tool: $tool_name, | |
532ac7d7 | 360 | mode: Mode::ToolBootstrap, |
ea8adc8c | 361 | path: $path, |
8faf50e0 XL |
362 | is_optional_tool: false, |
363 | source_type: if false $(|| $external)* { | |
364 | SourceType::Submodule | |
365 | } else { | |
366 | SourceType::InTree | |
367 | }, | |
416331ca XL |
368 | extra_features: { |
369 | // FIXME(#60643): avoid this lint by using `_` | |
370 | let mut _tmp = Vec::new(); | |
371 | $(_tmp.extend($features);)* | |
372 | _tmp | |
373 | }, | |
ff7c6d11 | 374 | }).expect("expected to build -- essential tool") |
3b2f2976 XL |
375 | } |
376 | } | |
377 | )+ | |
378 | } | |
379 | } | |
380 | ||
532ac7d7 | 381 | bootstrap_tool!( |
416331ca | 382 | Rustbook, "src/tools/rustbook", "rustbook", features = rustbook_features(); |
532ac7d7 XL |
383 | UnstableBookGen, "src/tools/unstable-book-gen", "unstable-book-gen"; |
384 | Tidy, "src/tools/tidy", "tidy"; | |
385 | Linkchecker, "src/tools/linkchecker", "linkchecker"; | |
386 | CargoTest, "src/tools/cargotest", "cargotest"; | |
387 | Compiletest, "src/tools/compiletest", "compiletest", llvm_tools = true; | |
388 | BuildManifest, "src/tools/build-manifest", "build-manifest"; | |
389 | RemoteTestClient, "src/tools/remote-test-client", "remote-test-client"; | |
390 | RustInstaller, "src/tools/rust-installer", "fabricate", is_external_tool = true; | |
391 | RustdocTheme, "src/tools/rustdoc-themes", "rustdoc-themes"; | |
3b2f2976 XL |
392 | ); |
393 | ||
532ac7d7 XL |
394 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] |
395 | pub struct ErrorIndex { | |
396 | pub compiler: Compiler, | |
397 | } | |
398 | ||
399 | impl ErrorIndex { | |
400 | pub fn command(builder: &Builder<'_>, compiler: Compiler) -> Command { | |
401 | let mut cmd = Command::new(builder.ensure(ErrorIndex { | |
402 | compiler | |
403 | })); | |
404 | add_lib_path( | |
405 | vec![PathBuf::from(&builder.sysroot_libdir(compiler, compiler.host))], | |
406 | &mut cmd, | |
407 | ); | |
408 | cmd | |
409 | } | |
410 | } | |
411 | ||
412 | impl Step for ErrorIndex { | |
413 | type Output = PathBuf; | |
414 | ||
415 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { | |
416 | run.path("src/tools/error_index_generator") | |
417 | } | |
418 | ||
419 | fn make_run(run: RunConfig<'_>) { | |
420 | // Compile the error-index in the same stage as rustdoc to avoid | |
421 | // recompiling rustdoc twice if we can. | |
422 | let stage = if run.builder.top_stage >= 2 { run.builder.top_stage } else { 0 }; | |
423 | run.builder.ensure(ErrorIndex { | |
424 | compiler: run.builder.compiler(stage, run.builder.config.build), | |
425 | }); | |
426 | } | |
427 | ||
428 | fn run(self, builder: &Builder<'_>) -> PathBuf { | |
429 | builder.ensure(ToolBuild { | |
430 | compiler: self.compiler, | |
431 | target: self.compiler.host, | |
432 | tool: "error_index_generator", | |
433 | mode: Mode::ToolRustc, | |
434 | path: "src/tools/error_index_generator", | |
435 | is_optional_tool: false, | |
436 | source_type: SourceType::InTree, | |
437 | extra_features: Vec::new(), | |
438 | }).expect("expected to build -- essential tool") | |
439 | } | |
440 | } | |
441 | ||
3b2f2976 XL |
442 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] |
443 | pub struct RemoteTestServer { | |
444 | pub compiler: Compiler, | |
445 | pub target: Interned<String>, | |
446 | } | |
447 | ||
448 | impl Step for RemoteTestServer { | |
449 | type Output = PathBuf; | |
450 | ||
9fa01778 | 451 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
3b2f2976 XL |
452 | run.path("src/tools/remote-test-server") |
453 | } | |
454 | ||
9fa01778 | 455 | fn make_run(run: RunConfig<'_>) { |
3b2f2976 | 456 | run.builder.ensure(RemoteTestServer { |
83c7162d | 457 | compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), |
3b2f2976 XL |
458 | target: run.target, |
459 | }); | |
460 | } | |
461 | ||
9fa01778 | 462 | fn run(self, builder: &Builder<'_>) -> PathBuf { |
3b2f2976 XL |
463 | builder.ensure(ToolBuild { |
464 | compiler: self.compiler, | |
465 | target: self.target, | |
466 | tool: "remote-test-server", | |
94b46f34 | 467 | mode: Mode::ToolStd, |
ea8adc8c | 468 | path: "src/tools/remote-test-server", |
8faf50e0 XL |
469 | is_optional_tool: false, |
470 | source_type: SourceType::InTree, | |
0531ce1d | 471 | extra_features: Vec::new(), |
ff7c6d11 | 472 | }).expect("expected to build -- essential tool") |
3b2f2976 XL |
473 | } |
474 | } | |
475 | ||
476 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] | |
477 | pub struct Rustdoc { | |
532ac7d7 XL |
478 | /// This should only ever be 0 or 2. |
479 | /// We sometimes want to reference the "bootstrap" rustdoc, which is why this option is here. | |
480 | pub compiler: Compiler, | |
3b2f2976 XL |
481 | } |
482 | ||
483 | impl Step for Rustdoc { | |
484 | type Output = PathBuf; | |
485 | const DEFAULT: bool = true; | |
486 | const ONLY_HOSTS: bool = true; | |
487 | ||
9fa01778 | 488 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
3b2f2976 XL |
489 | run.path("src/tools/rustdoc") |
490 | } | |
491 | ||
9fa01778 | 492 | fn make_run(run: RunConfig<'_>) { |
3b2f2976 | 493 | run.builder.ensure(Rustdoc { |
532ac7d7 | 494 | compiler: run.builder.compiler(run.builder.top_stage, run.host), |
3b2f2976 XL |
495 | }); |
496 | } | |
497 | ||
9fa01778 | 498 | fn run(self, builder: &Builder<'_>) -> PathBuf { |
532ac7d7 | 499 | let target_compiler = self.compiler; |
9fa01778 XL |
500 | if target_compiler.stage == 0 { |
501 | if !target_compiler.is_snapshot(builder) { | |
502 | panic!("rustdoc in stage 0 must be snapshot rustdoc"); | |
503 | } | |
504 | return builder.initial_rustc.with_file_name(exe("rustdoc", &target_compiler.host)); | |
505 | } | |
3b2f2976 | 506 | let target = target_compiler.host; |
9fa01778 XL |
507 | // Similar to `compile::Assemble`, build with the previous stage's compiler. Otherwise |
508 | // we'd have stageN/bin/rustc and stageN/bin/rustdoc be effectively different stage | |
509 | // compilers, which isn't what we want. Rustdoc should be linked in the same way as the | |
510 | // rustc compiler it's paired with, so it must be built with the previous stage compiler. | |
511 | let build_compiler = builder.compiler(target_compiler.stage - 1, builder.config.build); | |
512 | ||
513 | // The presence of `target_compiler` ensures that the necessary libraries (codegen backends, | |
514 | // compiler libraries, ...) are built. Rustdoc does not require the presence of any | |
515 | // libraries within sysroot_libdir (i.e., rustlib), though doctests may want it (since | |
516 | // they'll be linked to those libraries). As such, don't explicitly `ensure` any additional | |
517 | // libraries here. The intuition here is that If we've built a compiler, we should be able | |
518 | // to build rustdoc. | |
3b2f2976 | 519 | |
8faf50e0 XL |
520 | let mut cargo = prepare_tool_cargo( |
521 | builder, | |
522 | build_compiler, | |
523 | Mode::ToolRustc, | |
524 | target, | |
525 | "build", | |
526 | "src/tools/rustdoc", | |
527 | SourceType::InTree, | |
0bf4aa26 | 528 | &[], |
8faf50e0 | 529 | ); |
ea8adc8c | 530 | |
83c7162d XL |
531 | builder.info(&format!("Building rustdoc for stage{} ({})", |
532 | target_compiler.stage, target_compiler.host)); | |
533 | builder.run(&mut cargo); | |
0531ce1d | 534 | |
3b2f2976 XL |
535 | // Cargo adds a number of paths to the dylib search path on windows, which results in |
536 | // the wrong rustdoc being executed. To avoid the conflicting rustdocs, we name the "tool" | |
537 | // rustdoc a different name. | |
94b46f34 XL |
538 | let tool_rustdoc = builder.cargo_out(build_compiler, Mode::ToolRustc, target) |
539 | .join(exe("rustdoc_tool_binary", &target_compiler.host)); | |
3b2f2976 XL |
540 | |
541 | // don't create a stage0-sysroot/bin directory. | |
542 | if target_compiler.stage > 0 { | |
543 | let sysroot = builder.sysroot(target_compiler); | |
544 | let bindir = sysroot.join("bin"); | |
545 | t!(fs::create_dir_all(&bindir)); | |
546 | let bin_rustdoc = bindir.join(exe("rustdoc", &*target_compiler.host)); | |
547 | let _ = fs::remove_file(&bin_rustdoc); | |
83c7162d | 548 | builder.copy(&tool_rustdoc, &bin_rustdoc); |
3b2f2976 XL |
549 | bin_rustdoc |
550 | } else { | |
551 | tool_rustdoc | |
552 | } | |
553 | } | |
554 | } | |
555 | ||
556 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] | |
557 | pub struct Cargo { | |
558 | pub compiler: Compiler, | |
559 | pub target: Interned<String>, | |
560 | } | |
561 | ||
562 | impl Step for Cargo { | |
563 | type Output = PathBuf; | |
564 | const DEFAULT: bool = true; | |
565 | const ONLY_HOSTS: bool = true; | |
566 | ||
9fa01778 | 567 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
3b2f2976 | 568 | let builder = run.builder; |
83c7162d | 569 | run.path("src/tools/cargo").default_condition(builder.config.extended) |
3b2f2976 XL |
570 | } |
571 | ||
9fa01778 | 572 | fn make_run(run: RunConfig<'_>) { |
3b2f2976 | 573 | run.builder.ensure(Cargo { |
83c7162d | 574 | compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), |
3b2f2976 XL |
575 | target: run.target, |
576 | }); | |
577 | } | |
578 | ||
9fa01778 | 579 | fn run(self, builder: &Builder<'_>) -> PathBuf { |
dc9dc135 XL |
580 | // Cargo depends on procedural macros, so make sure the host |
581 | // libstd/libproc_macro is available. | |
582 | builder.ensure(compile::Test { | |
3b2f2976 | 583 | compiler: self.compiler, |
83c7162d | 584 | target: builder.config.build, |
3b2f2976 XL |
585 | }); |
586 | builder.ensure(ToolBuild { | |
587 | compiler: self.compiler, | |
588 | target: self.target, | |
589 | tool: "cargo", | |
94b46f34 | 590 | mode: Mode::ToolRustc, |
ea8adc8c | 591 | path: "src/tools/cargo", |
8faf50e0 XL |
592 | is_optional_tool: false, |
593 | source_type: SourceType::Submodule, | |
0531ce1d | 594 | extra_features: Vec::new(), |
ff7c6d11 | 595 | }).expect("expected to build -- essential tool") |
ea8adc8c XL |
596 | } |
597 | } | |
598 | ||
ff7c6d11 XL |
599 | macro_rules! tool_extended { |
600 | (($sel:ident, $builder:ident), | |
601 | $($name:ident, | |
602 | $toolstate:ident, | |
603 | $path:expr, | |
604 | $tool_name:expr, | |
605 | $extra_deps:block;)+) => { | |
606 | $( | |
0531ce1d | 607 | #[derive(Debug, Clone, Hash, PartialEq, Eq)] |
ff7c6d11 XL |
608 | pub struct $name { |
609 | pub compiler: Compiler, | |
610 | pub target: Interned<String>, | |
0531ce1d | 611 | pub extra_features: Vec<String>, |
ff7c6d11 | 612 | } |
ea8adc8c | 613 | |
ff7c6d11 XL |
614 | impl Step for $name { |
615 | type Output = Option<PathBuf>; | |
616 | const DEFAULT: bool = true; | |
617 | const ONLY_HOSTS: bool = true; | |
ea8adc8c | 618 | |
9fa01778 | 619 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
ff7c6d11 | 620 | let builder = run.builder; |
83c7162d | 621 | run.path($path).default_condition(builder.config.extended) |
ff7c6d11 | 622 | } |
ea8adc8c | 623 | |
9fa01778 | 624 | fn make_run(run: RunConfig<'_>) { |
ff7c6d11 | 625 | run.builder.ensure($name { |
83c7162d | 626 | compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), |
ff7c6d11 | 627 | target: run.target, |
0531ce1d | 628 | extra_features: Vec::new(), |
ff7c6d11 XL |
629 | }); |
630 | } | |
631 | ||
0531ce1d | 632 | #[allow(unused_mut)] |
9fa01778 | 633 | fn run(mut $sel, $builder: &Builder<'_>) -> Option<PathBuf> { |
ff7c6d11 XL |
634 | $extra_deps |
635 | $builder.ensure(ToolBuild { | |
636 | compiler: $sel.compiler, | |
637 | target: $sel.target, | |
638 | tool: $tool_name, | |
94b46f34 | 639 | mode: Mode::ToolRustc, |
ff7c6d11 | 640 | path: $path, |
0531ce1d | 641 | extra_features: $sel.extra_features, |
8faf50e0 XL |
642 | is_optional_tool: true, |
643 | source_type: SourceType::Submodule, | |
ff7c6d11 XL |
644 | }) |
645 | } | |
646 | } | |
647 | )+ | |
ea8adc8c | 648 | } |
ff7c6d11 | 649 | } |
ea8adc8c | 650 | |
ff7c6d11 XL |
651 | tool_extended!((self, builder), |
652 | Cargofmt, rustfmt, "src/tools/rustfmt", "cargo-fmt", {}; | |
8faf50e0 | 653 | CargoClippy, clippy, "src/tools/clippy", "cargo-clippy", { |
dc9dc135 XL |
654 | // Clippy depends on procedural macros, so make sure that's built for |
655 | // the compiler itself. | |
656 | builder.ensure(compile::Test { | |
8faf50e0 XL |
657 | compiler: self.compiler, |
658 | target: builder.config.build, | |
659 | }); | |
660 | }; | |
ff7c6d11 | 661 | Clippy, clippy, "src/tools/clippy", "clippy-driver", { |
dc9dc135 XL |
662 | // Clippy depends on procedural macros, so make sure that's built for |
663 | // the compiler itself. | |
664 | builder.ensure(compile::Test { | |
ea8adc8c | 665 | compiler: self.compiler, |
83c7162d | 666 | target: builder.config.build, |
ea8adc8c | 667 | }); |
ff7c6d11 XL |
668 | }; |
669 | Miri, miri, "src/tools/miri", "miri", {}; | |
0731742a | 670 | CargoMiri, miri, "src/tools/miri", "cargo-miri", { |
dc9dc135 XL |
671 | // Miri depends on procedural macros, so make sure that's built for |
672 | // the compiler itself. | |
673 | builder.ensure(compile::Test { | |
0731742a XL |
674 | compiler: self.compiler, |
675 | target: builder.config.build, | |
676 | }); | |
677 | }; | |
ff7c6d11 | 678 | Rls, rls, "src/tools/rls", "rls", { |
8faf50e0 XL |
679 | let clippy = builder.ensure(Clippy { |
680 | compiler: self.compiler, | |
681 | target: self.target, | |
682 | extra_features: Vec::new(), | |
683 | }); | |
684 | if clippy.is_some() { | |
685 | self.extra_features.push("clippy".to_owned()); | |
686 | } | |
dc9dc135 XL |
687 | // RLS depends on procedural macros, so make sure that's built for |
688 | // the compiler itself. | |
689 | builder.ensure(compile::Test { | |
3b2f2976 | 690 | compiler: self.compiler, |
83c7162d | 691 | target: builder.config.build, |
3b2f2976 | 692 | }); |
ff7c6d11 XL |
693 | }; |
694 | Rustfmt, rustfmt, "src/tools/rustfmt", "rustfmt", {}; | |
695 | ); | |
3b2f2976 XL |
696 | |
697 | impl<'a> Builder<'a> { | |
9fa01778 | 698 | /// Gets a `Command` which is ready to run `tool` in `stage` built for |
3b2f2976 XL |
699 | /// `host`. |
700 | pub fn tool_cmd(&self, tool: Tool) -> Command { | |
701 | let mut cmd = Command::new(self.tool_exe(tool)); | |
532ac7d7 | 702 | let compiler = self.compiler(0, self.config.build); |
3b2f2976 | 703 | let host = &compiler.host; |
dc9dc135 XL |
704 | // Prepares the `cmd` provided to be able to run the `compiler` provided. |
705 | // | |
706 | // Notably this munges the dynamic library lookup path to point to the | |
707 | // right location to run `compiler`. | |
83c7162d | 708 | let mut lib_paths: Vec<PathBuf> = vec![ |
dc9dc135 XL |
709 | self.build.rustc_snapshot_libdir(), |
710 | self.cargo_out(compiler, Mode::ToolBootstrap, *host).join("deps"), | |
3b2f2976 XL |
711 | ]; |
712 | ||
0731742a | 713 | // On MSVC a tool may invoke a C compiler (e.g., compiletest in run-make |
3b2f2976 XL |
714 | // mode) and that C compiler may need some extra PATH modification. Do |
715 | // so here. | |
716 | if compiler.host.contains("msvc") { | |
717 | let curpaths = env::var_os("PATH").unwrap_or_default(); | |
718 | let curpaths = env::split_paths(&curpaths).collect::<Vec<_>>(); | |
abe05a73 | 719 | for &(ref k, ref v) in self.cc[&compiler.host].env() { |
3b2f2976 XL |
720 | if k != "PATH" { |
721 | continue | |
722 | } | |
723 | for path in env::split_paths(v) { | |
724 | if !curpaths.contains(&path) { | |
83c7162d | 725 | lib_paths.push(path); |
3b2f2976 XL |
726 | } |
727 | } | |
728 | } | |
729 | } | |
83c7162d | 730 | |
dc9dc135 XL |
731 | add_lib_path(lib_paths, &mut cmd); |
732 | cmd | |
83c7162d | 733 | } |
3b2f2976 | 734 | } |