1 //! Implementation of compiling the compiler and standard library, in "check"-based modes.
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}
;
9 use crate::{Compiler, Mode, Subcommand}
;
10 use std
::path
::PathBuf
;
12 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
14 pub target
: TargetSelection
,
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
)
23 if let Subcommand
::Clippy { fix, .. }
= builder
.config
.cmd
{
24 // disable the most spammy clippy lints
25 let ignored_lints
= vec
![
26 "many_single_char_names", // there are a lot in stdarch
29 "missing_safety_doc", // almost 3K warnings
31 "needless_lifetimes", // people want to keep the lifetimes
32 "wrong_self_convention",
34 let mut args
= vec
![];
37 args
.extend(strings(&[
38 "--fix", "-Zunstable-options",
39 // FIXME: currently, `--fix` gives an error while checking tests for libtest,
40 // possibly because libtest is not yet built in the sysroot.
41 // As a workaround, avoid checking tests and benches when passed --fix.
42 "--lib", "--bins", "--examples",
45 args
.extend(strings(&["--", "--cap-lints", "warn"]));
46 args
.extend(ignored_lints
.iter().map(|lint
| format
!("-Aclippy::{}", lint
)));
53 fn cargo_subcommand(kind
: Kind
) -> &'
static str {
55 Kind
::Check
=> "check",
56 Kind
::Clippy
=> "clippy",
64 const DEFAULT
: bool
= true;
66 fn should_run(run
: ShouldRun
<'_
>) -> ShouldRun
<'_
> {
67 run
.all_krates("test")
70 fn make_run(run
: RunConfig
<'_
>) {
71 run
.builder
.ensure(Std { target: run.target }
);
74 fn run(self, builder
: &Builder
<'_
>) {
75 let target
= self.target
;
76 let compiler
= builder
.compiler(builder
.top_stage
, builder
.config
.build
);
78 let mut cargo
= builder
.cargo(
83 cargo_subcommand(builder
.kind
),
85 std_cargo(builder
, target
, compiler
.stage
, &mut cargo
);
87 builder
.info(&format
!(
88 "Checking stage{} std artifacts ({} -> {})",
89 builder
.top_stage
, &compiler
.host
, target
95 &libstd_stamp(builder
, compiler
, target
),
100 // We skip populating the sysroot in non-zero stage because that'll lead
101 // to rlib/rmeta conflicts if std gets built during this session.
102 if compiler
.stage
== 0 {
103 let libdir
= builder
.sysroot_libdir(compiler
, target
);
104 let hostdir
= builder
.sysroot_libdir(compiler
, compiler
.host
);
105 add_to_sysroot(&builder
, &libdir
, &hostdir
, &libstd_stamp(builder
, compiler
, target
));
108 // Then run cargo again, once we've put the rmeta files for the library
109 // crates into the sysroot. This is needed because e.g., core's tests
110 // depend on `libtest` -- Cargo presumes it will exist, but it doesn't
111 // since we initialize with an empty sysroot.
113 // Currently only the "libtest" tree of crates does this.
115 if let Subcommand
::Check { all_targets: true, .. }
= builder
.config
.cmd
{
116 let mut cargo
= builder
.cargo(
121 cargo_subcommand(builder
.kind
),
123 std_cargo(builder
, target
, compiler
.stage
, &mut cargo
);
124 cargo
.arg("--all-targets");
126 // Explicitly pass -p for all dependencies krates -- this will force cargo
127 // to also check the tests/benches/examples for these crates, rather
128 // than just the leaf crate.
129 for krate
in builder
.in_tree_crates("test", Some(target
)) {
130 cargo
.arg("-p").arg(krate
.name
);
133 builder
.info(&format
!(
134 "Checking stage{} std test/bench/example targets ({} -> {})",
135 builder
.top_stage
, &compiler
.host
, target
141 &libstd_test_stamp(builder
, compiler
, target
),
149 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
151 pub target
: TargetSelection
,
154 impl Step
for Rustc
{
156 const ONLY_HOSTS
: bool
= true;
157 const DEFAULT
: bool
= true;
159 fn should_run(run
: ShouldRun
<'_
>) -> ShouldRun
<'_
> {
160 run
.all_krates("rustc-main")
163 fn make_run(run
: RunConfig
<'_
>) {
164 run
.builder
.ensure(Rustc { target: run.target }
);
167 /// Builds the compiler.
169 /// This will build the compiler for a particular stage of the build using
170 /// the `compiler` targeting the `target` architecture. The artifacts
171 /// created will also be linked into the sysroot directory.
172 fn run(self, builder
: &Builder
<'_
>) {
173 let compiler
= builder
.compiler(builder
.top_stage
, builder
.config
.build
);
174 let target
= self.target
;
176 if compiler
.stage
!= 0 {
177 // If we're not in stage 0, then we won't have a std from the beta
178 // compiler around. That means we need to make sure there's one in
179 // the sysroot for the compiler to find. Otherwise, we're going to
180 // fail when building crates that need to generate code (e.g., build
181 // scripts and their dependencies).
182 builder
.ensure(crate::compile
::Std { target: compiler.host, compiler }
);
183 builder
.ensure(crate::compile
::Std { target, compiler }
);
185 builder
.ensure(Std { target }
);
188 let mut cargo
= builder
.cargo(
193 cargo_subcommand(builder
.kind
),
195 rustc_cargo(builder
, &mut cargo
, target
);
196 if let Subcommand
::Check { all_targets: true, .. }
= builder
.config
.cmd
{
197 cargo
.arg("--all-targets");
200 // Explicitly pass -p for all compiler krates -- this will force cargo
201 // to also check the tests/benches/examples for these crates, rather
202 // than just the leaf crate.
203 for krate
in builder
.in_tree_crates("rustc-main", Some(target
)) {
204 cargo
.arg("-p").arg(krate
.name
);
207 builder
.info(&format
!(
208 "Checking stage{} compiler artifacts ({} -> {})",
209 builder
.top_stage
, &compiler
.host
, target
215 &librustc_stamp(builder
, compiler
, target
),
220 let libdir
= builder
.sysroot_libdir(compiler
, target
);
221 let hostdir
= builder
.sysroot_libdir(compiler
, compiler
.host
);
222 add_to_sysroot(&builder
, &libdir
, &hostdir
, &librustc_stamp(builder
, compiler
, target
));
226 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
227 pub struct CodegenBackend
{
228 pub target
: TargetSelection
,
229 pub backend
: Interned
<String
>,
232 impl Step
for CodegenBackend
{
234 const ONLY_HOSTS
: bool
= true;
235 const DEFAULT
: bool
= true;
237 fn should_run(run
: ShouldRun
<'_
>) -> ShouldRun
<'_
> {
238 run
.paths(&["compiler/rustc_codegen_cranelift", "rustc_codegen_cranelift"])
241 fn make_run(run
: RunConfig
<'_
>) {
242 for &backend
in &[INTERNER
.intern_str("cranelift")] {
243 run
.builder
.ensure(CodegenBackend { target: run.target, backend }
);
247 fn run(self, builder
: &Builder
<'_
>) {
248 let compiler
= builder
.compiler(builder
.top_stage
, builder
.config
.build
);
249 let target
= self.target
;
250 let backend
= self.backend
;
252 builder
.ensure(Rustc { target }
);
254 let mut cargo
= builder
.cargo(
257 SourceType
::Submodule
,
259 cargo_subcommand(builder
.kind
),
262 .arg("--manifest-path")
263 .arg(builder
.src
.join(format
!("compiler/rustc_codegen_{}/Cargo.toml", backend
)));
264 rustc_cargo_env(builder
, &mut cargo
, target
);
266 builder
.info(&format
!(
267 "Checking stage{} {} artifacts ({} -> {})",
268 builder
.top_stage
, backend
, &compiler
.host
.triple
, target
.triple
275 &codegen_backend_stamp(builder
, compiler
, target
, backend
),
282 macro_rules
! tool_check_step
{
283 ($name
:ident
, $path
:literal
, $
($alias
:literal
, )* $source_type
:path
) => {
284 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
286 pub target
: TargetSelection
,
289 impl Step
for $name
{
291 const ONLY_HOSTS
: bool
= true;
292 const DEFAULT
: bool
= true;
294 fn should_run(run
: ShouldRun
<'_
>) -> ShouldRun
<'_
> {
295 run
.paths(&[ $path
, $
($alias
),* ])
298 fn make_run(run
: RunConfig
<'_
>) {
299 run
.builder
.ensure($name { target: run.target }
);
302 fn run(self, builder
: &Builder
<'_
>) {
303 let compiler
= builder
.compiler(builder
.top_stage
, builder
.config
.build
);
304 let target
= self.target
;
306 builder
.ensure(Rustc { target }
);
308 let mut cargo
= prepare_tool_cargo(
313 cargo_subcommand(builder
.kind
),
319 if let Subcommand
::Check { all_targets: true, .. }
= builder
.config
.cmd
{
320 cargo
.arg("--all-targets");
323 // Enable internal lints for clippy and rustdoc
324 // NOTE: this doesn't enable lints for any other tools unless they explicitly add `#![warn(rustc::internal)]`
325 // See https://github.com/rust-lang/rust/pull/80573#issuecomment-754010776
326 cargo
.rustflag("-Zunstable-options");
328 builder
.info(&format
!(
329 "Checking stage{} {} artifacts ({} -> {})",
331 stringify
!($name
).to_lowercase(),
332 &compiler
.host
.triple
,
339 &stamp(builder
, compiler
, target
),
344 let libdir
= builder
.sysroot_libdir(compiler
, target
);
345 let hostdir
= builder
.sysroot_libdir(compiler
, compiler
.host
);
346 add_to_sysroot(&builder
, &libdir
, &hostdir
, &stamp(builder
, compiler
, target
));
348 /// Cargo's output path in a given stage, compiled by a particular
349 /// compiler for the specified target.
351 builder
: &Builder
<'_
>,
353 target
: TargetSelection
,
356 .cargo_out(compiler
, Mode
::ToolRustc
, target
)
357 .join(format
!(".{}-check.stamp", stringify
!($name
).to_lowercase()))
364 tool_check_step
!(Rustdoc
, "src/tools/rustdoc", "src/librustdoc", SourceType
::InTree
);
365 // Clippy is a hybrid. It is an external tool, but uses a git subtree instead
366 // of a submodule. Since the SourceType only drives the deny-warnings
367 // behavior, treat it as in-tree so that any new warnings in clippy will be
369 tool_check_step
!(Clippy
, "src/tools/clippy", SourceType
::InTree
);
371 tool_check_step
!(Bootstrap
, "src/bootstrap", SourceType
::InTree
);
373 /// Cargo's output path for the standard library in a given stage, compiled
374 /// by a particular compiler for the specified target.
375 fn libstd_stamp(builder
: &Builder
<'_
>, compiler
: Compiler
, target
: TargetSelection
) -> PathBuf
{
376 builder
.cargo_out(compiler
, Mode
::Std
, target
).join(".libstd-check.stamp")
379 /// Cargo's output path for the standard library in a given stage, compiled
380 /// by a particular compiler for the specified target.
381 fn libstd_test_stamp(
382 builder
: &Builder
<'_
>,
384 target
: TargetSelection
,
386 builder
.cargo_out(compiler
, Mode
::Std
, target
).join(".libstd-check-test.stamp")
389 /// Cargo's output path for librustc in a given stage, compiled by a particular
390 /// compiler for the specified target.
391 fn librustc_stamp(builder
: &Builder
<'_
>, compiler
: Compiler
, target
: TargetSelection
) -> PathBuf
{
392 builder
.cargo_out(compiler
, Mode
::Rustc
, target
).join(".librustc-check.stamp")
395 /// Cargo's output path for librustc_codegen_llvm in a given stage, compiled by a particular
396 /// compiler for the specified target and backend.
397 fn codegen_backend_stamp(
398 builder
: &Builder
<'_
>,
400 target
: TargetSelection
,
401 backend
: Interned
<String
>,
404 .cargo_out(compiler
, Mode
::Codegen
, target
)
405 .join(format
!(".librustc_codegen_{}-check.stamp", backend
))