]> git.lizzy.rs Git - rust.git/blob - src/bootstrap/check.rs
Lint on redundant trailing semicolon after item
[rust.git] / src / bootstrap / check.rs
1 //! Implementation of compiling the compiler and standard library, in "check"-based modes.
2
3 use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
4 use crate::cache::Interned;
5 use crate::compile::{add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo};
6 use crate::config::TargetSelection;
7 use crate::tool::{prepare_tool_cargo, SourceType};
8 use crate::INTERNER;
9 use crate::{Compiler, Mode, Subcommand};
10 use std::path::PathBuf;
11
12 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
13 pub struct Std {
14     pub target: TargetSelection,
15 }
16
17 /// Returns args for the subcommand itself (not for cargo)
18 fn args(builder: &Builder<'_>) -> Vec<String> {
19     fn strings<'a>(arr: &'a [&str]) -> impl Iterator<Item = String> + 'a {
20         arr.iter().copied().map(String::from)
21     }
22
23     if let Subcommand::Clippy { fix, .. } = builder.config.cmd {
24         let mut args = vec![];
25         if fix {
26             #[rustfmt::skip]
27             args.extend(strings(&[
28                 "--fix", "-Zunstable-options",
29                 // FIXME: currently, `--fix` gives an error while checking tests for libtest,
30                 // possibly because libtest is not yet built in the sysroot.
31                 // As a workaround, avoid checking tests and benches when passed --fix.
32                 "--lib", "--bins", "--examples",
33             ]));
34         }
35         args.extend(strings(&["--", "--cap-lints", "warn"]));
36         args
37     } else {
38         vec![]
39     }
40 }
41
42 fn cargo_subcommand(kind: Kind) -> &'static str {
43     match kind {
44         Kind::Check => "check",
45         Kind::Clippy => "clippy",
46         Kind::Fix => "fix",
47         _ => unreachable!(),
48     }
49 }
50
51 impl Step for Std {
52     type Output = ();
53     const DEFAULT: bool = true;
54
55     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
56         run.all_krates("test")
57     }
58
59     fn make_run(run: RunConfig<'_>) {
60         run.builder.ensure(Std { target: run.target });
61     }
62
63     fn run(self, builder: &Builder<'_>) {
64         let target = self.target;
65         let compiler = builder.compiler(0, builder.config.build);
66
67         let mut cargo = builder.cargo(
68             compiler,
69             Mode::Std,
70             SourceType::InTree,
71             target,
72             cargo_subcommand(builder.kind),
73         );
74         std_cargo(builder, target, compiler.stage, &mut cargo);
75
76         builder.info(&format!("Checking std artifacts ({} -> {})", &compiler.host, target));
77         run_cargo(
78             builder,
79             cargo,
80             args(builder),
81             &libstd_stamp(builder, compiler, target),
82             vec![],
83             true,
84         );
85
86         let libdir = builder.sysroot_libdir(compiler, target);
87         let hostdir = builder.sysroot_libdir(compiler, compiler.host);
88         add_to_sysroot(&builder, &libdir, &hostdir, &libstd_stamp(builder, compiler, target));
89
90         // Then run cargo again, once we've put the rmeta files for the library
91         // crates into the sysroot. This is needed because e.g., core's tests
92         // depend on `libtest` -- Cargo presumes it will exist, but it doesn't
93         // since we initialize with an empty sysroot.
94         //
95         // Currently only the "libtest" tree of crates does this.
96
97         if let Subcommand::Check { all_targets: true, .. } = builder.config.cmd {
98             let mut cargo = builder.cargo(
99                 compiler,
100                 Mode::Std,
101                 SourceType::InTree,
102                 target,
103                 cargo_subcommand(builder.kind),
104             );
105             std_cargo(builder, target, compiler.stage, &mut cargo);
106             cargo.arg("--all-targets");
107
108             // Explicitly pass -p for all dependencies krates -- this will force cargo
109             // to also check the tests/benches/examples for these crates, rather
110             // than just the leaf crate.
111             for krate in builder.in_tree_crates("test", Some(target)) {
112                 cargo.arg("-p").arg(krate.name);
113             }
114
115             builder.info(&format!(
116                 "Checking std test/bench/example targets ({} -> {})",
117                 &compiler.host, target
118             ));
119             run_cargo(
120                 builder,
121                 cargo,
122                 args(builder),
123                 &libstd_test_stamp(builder, compiler, target),
124                 vec![],
125                 true,
126             );
127         }
128     }
129 }
130
131 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
132 pub struct Rustc {
133     pub target: TargetSelection,
134 }
135
136 impl Step for Rustc {
137     type Output = ();
138     const ONLY_HOSTS: bool = true;
139     const DEFAULT: bool = true;
140
141     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
142         run.all_krates("rustc-main")
143     }
144
145     fn make_run(run: RunConfig<'_>) {
146         run.builder.ensure(Rustc { target: run.target });
147     }
148
149     /// Builds the compiler.
150     ///
151     /// This will build the compiler for a particular stage of the build using
152     /// the `compiler` targeting the `target` architecture. The artifacts
153     /// created will also be linked into the sysroot directory.
154     fn run(self, builder: &Builder<'_>) {
155         let compiler = builder.compiler(0, builder.config.build);
156         let target = self.target;
157
158         builder.ensure(Std { target });
159
160         let mut cargo = builder.cargo(
161             compiler,
162             Mode::Rustc,
163             SourceType::InTree,
164             target,
165             cargo_subcommand(builder.kind),
166         );
167         rustc_cargo(builder, &mut cargo, target);
168         if let Subcommand::Check { all_targets: true, .. } = builder.config.cmd {
169             cargo.arg("--all-targets");
170         }
171
172         // Explicitly pass -p for all compiler krates -- this will force cargo
173         // to also check the tests/benches/examples for these crates, rather
174         // than just the leaf crate.
175         for krate in builder.in_tree_crates("rustc-main", Some(target)) {
176             cargo.arg("-p").arg(krate.name);
177         }
178
179         builder.info(&format!("Checking compiler artifacts ({} -> {})", &compiler.host, target));
180         run_cargo(
181             builder,
182             cargo,
183             args(builder),
184             &librustc_stamp(builder, compiler, target),
185             vec![],
186             true,
187         );
188
189         let libdir = builder.sysroot_libdir(compiler, target);
190         let hostdir = builder.sysroot_libdir(compiler, compiler.host);
191         add_to_sysroot(&builder, &libdir, &hostdir, &librustc_stamp(builder, compiler, target));
192     }
193 }
194
195 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
196 pub struct CodegenBackend {
197     pub target: TargetSelection,
198     pub backend: Interned<String>,
199 }
200
201 impl Step for CodegenBackend {
202     type Output = ();
203     const ONLY_HOSTS: bool = true;
204     const DEFAULT: bool = true;
205
206     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
207         run.paths(&["compiler/rustc_codegen_cranelift", "rustc_codegen_cranelift"])
208     }
209
210     fn make_run(run: RunConfig<'_>) {
211         for &backend in &[INTERNER.intern_str("cranelift")] {
212             run.builder.ensure(CodegenBackend { target: run.target, backend });
213         }
214     }
215
216     fn run(self, builder: &Builder<'_>) {
217         let compiler = builder.compiler(0, builder.config.build);
218         let target = self.target;
219         let backend = self.backend;
220
221         builder.ensure(Rustc { target });
222
223         let mut cargo = builder.cargo(
224             compiler,
225             Mode::Codegen,
226             SourceType::Submodule,
227             target,
228             cargo_subcommand(builder.kind),
229         );
230         cargo
231             .arg("--manifest-path")
232             .arg(builder.src.join(format!("compiler/rustc_codegen_{}/Cargo.toml", backend)));
233         rustc_cargo_env(builder, &mut cargo, target);
234
235         builder.info(&format!(
236             "Checking {} artifacts ({} -> {})",
237             backend, &compiler.host.triple, target.triple
238         ));
239
240         run_cargo(
241             builder,
242             cargo,
243             args(builder),
244             &codegen_backend_stamp(builder, compiler, target, backend),
245             vec![],
246             true,
247         );
248     }
249 }
250
251 macro_rules! tool_check_step {
252     ($name:ident, $path:expr, $source_type:expr) => {
253         #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
254         pub struct $name {
255             pub target: TargetSelection,
256         }
257
258         impl Step for $name {
259             type Output = ();
260             const ONLY_HOSTS: bool = true;
261             const DEFAULT: bool = true;
262
263             fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
264                 run.path($path)
265             }
266
267             fn make_run(run: RunConfig<'_>) {
268                 run.builder.ensure($name { target: run.target });
269             }
270
271             fn run(self, builder: &Builder<'_>) {
272                 let compiler = builder.compiler(0, builder.config.build);
273                 let target = self.target;
274
275                 builder.ensure(Rustc { target });
276
277                 let mut cargo = prepare_tool_cargo(
278                     builder,
279                     compiler,
280                     Mode::ToolRustc,
281                     target,
282                     cargo_subcommand(builder.kind),
283                     $path,
284                     $source_type,
285                     &[],
286                 );
287
288                 if let Subcommand::Check { all_targets: true, .. } = builder.config.cmd {
289                     cargo.arg("--all-targets");
290                 }
291
292                 builder.info(&format!(
293                     "Checking {} artifacts ({} -> {})",
294                     stringify!($name).to_lowercase(),
295                     &compiler.host.triple,
296                     target.triple
297                 ));
298                 run_cargo(
299                     builder,
300                     cargo,
301                     args(builder),
302                     &stamp(builder, compiler, target),
303                     vec![],
304                     true,
305                 );
306
307                 let libdir = builder.sysroot_libdir(compiler, target);
308                 let hostdir = builder.sysroot_libdir(compiler, compiler.host);
309                 add_to_sysroot(&builder, &libdir, &hostdir, &stamp(builder, compiler, target));
310
311                 /// Cargo's output path in a given stage, compiled by a particular
312                 /// compiler for the specified target.
313                 fn stamp(
314                     builder: &Builder<'_>,
315                     compiler: Compiler,
316                     target: TargetSelection,
317                 ) -> PathBuf {
318                     builder
319                         .cargo_out(compiler, Mode::ToolRustc, target)
320                         .join(format!(".{}-check.stamp", stringify!($name).to_lowercase()))
321                 }
322             }
323         }
324     };
325 }
326
327 tool_check_step!(Rustdoc, "src/tools/rustdoc", SourceType::InTree);
328 // Clippy is a hybrid. It is an external tool, but uses a git subtree instead
329 // of a submodule. Since the SourceType only drives the deny-warnings
330 // behavior, treat it as in-tree so that any new warnings in clippy will be
331 // rejected.
332 tool_check_step!(Clippy, "src/tools/clippy", SourceType::InTree);
333
334 tool_check_step!(Bootstrap, "src/bootstrap", SourceType::InTree);
335
336 /// Cargo's output path for the standard library in a given stage, compiled
337 /// by a particular compiler for the specified target.
338 fn libstd_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf {
339     builder.cargo_out(compiler, Mode::Std, target).join(".libstd-check.stamp")
340 }
341
342 /// Cargo's output path for the standard library in a given stage, compiled
343 /// by a particular compiler for the specified target.
344 fn libstd_test_stamp(
345     builder: &Builder<'_>,
346     compiler: Compiler,
347     target: TargetSelection,
348 ) -> PathBuf {
349     builder.cargo_out(compiler, Mode::Std, target).join(".libstd-check-test.stamp")
350 }
351
352 /// Cargo's output path for librustc in a given stage, compiled by a particular
353 /// compiler for the specified target.
354 fn librustc_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf {
355     builder.cargo_out(compiler, Mode::Rustc, target).join(".librustc-check.stamp")
356 }
357
358 /// Cargo's output path for librustc_codegen_llvm in a given stage, compiled by a particular
359 /// compiler for the specified target and backend.
360 fn codegen_backend_stamp(
361     builder: &Builder<'_>,
362     compiler: Compiler,
363     target: TargetSelection,
364     backend: Interned<String>,
365 ) -> PathBuf {
366     builder
367         .cargo_out(compiler, Mode::Codegen, target)
368         .join(format!(".librustc_codegen_{}-check.stamp", backend))
369 }