@@ -18,7 +18,9 @@ use crate::core::build_steps::{check, clean, compile, dist, doc, install, run, s
18
18
use crate :: core:: config:: flags:: { Color , Subcommand } ;
19
19
use crate :: core:: config:: { DryRun , SplitDebuginfo , TargetSelection } ;
20
20
use crate :: utils:: cache:: { Cache , Interned , INTERNER } ;
21
- use crate :: utils:: helpers:: { self , add_dylib_path, add_link_lib_path, exe, libdir, output, t} ;
21
+ use crate :: utils:: helpers:: {
22
+ self , add_dylib_path, add_link_lib_path, dylib_path, dylib_path_var, exe, libdir, output, t,
23
+ } ;
22
24
use crate :: Crate ;
23
25
use crate :: EXTRA_CHECK_CFGS ;
24
26
use crate :: { Build , CLang , DocTests , GitRepo , Mode } ;
@@ -1150,6 +1152,43 @@ impl<'a> Builder<'a> {
1150
1152
self . ensure ( tool:: Rustdoc { compiler } )
1151
1153
}
1152
1154
1155
+ pub fn cargo_clippy_cmd ( & self , run_compiler : Compiler ) -> Command {
1156
+ let initial_sysroot_bin = self . initial_rustc . parent ( ) . unwrap ( ) ;
1157
+ // Set PATH to include the sysroot bin dir so clippy can find cargo.
1158
+ let path = t ! ( env:: join_paths(
1159
+ // The sysroot comes first in PATH to avoid using rustup's cargo.
1160
+ std:: iter:: once( PathBuf :: from( initial_sysroot_bin) )
1161
+ . chain( env:: split_paths( & t!( env:: var( "PATH" ) ) ) )
1162
+ ) ) ;
1163
+
1164
+ if run_compiler. stage == 0 {
1165
+ // `ensure(Clippy { stage: 0 })` *builds* clippy with stage0, it doesn't use the beta clippy.
1166
+ let cargo_clippy = self . initial_rustc . parent ( ) . unwrap ( ) . join ( "cargo-clippy" ) ;
1167
+ let mut cmd = Command :: new ( cargo_clippy) ;
1168
+ cmd. env ( "PATH" , & path) ;
1169
+ return cmd;
1170
+ }
1171
+
1172
+ let build_compiler = self . compiler ( run_compiler. stage - 1 , self . build . build ) ;
1173
+ self . ensure ( tool:: Clippy {
1174
+ compiler : build_compiler,
1175
+ target : self . build . build ,
1176
+ extra_features : vec ! [ ] ,
1177
+ } ) ;
1178
+ let cargo_clippy = self . ensure ( tool:: CargoClippy {
1179
+ compiler : build_compiler,
1180
+ target : self . build . build ,
1181
+ extra_features : vec ! [ ] ,
1182
+ } ) ;
1183
+ let mut dylib_path = dylib_path ( ) ;
1184
+ dylib_path. insert ( 0 , self . sysroot ( run_compiler) . join ( "lib" ) ) ;
1185
+
1186
+ let mut cmd = Command :: new ( cargo_clippy. unwrap ( ) ) ;
1187
+ cmd. env ( dylib_path_var ( ) , env:: join_paths ( & dylib_path) . unwrap ( ) ) ;
1188
+ cmd. env ( "PATH" , path) ;
1189
+ cmd
1190
+ }
1191
+
1153
1192
pub fn rustdoc_cmd ( & self , compiler : Compiler ) -> Command {
1154
1193
let mut cmd = Command :: new ( & self . bootstrap_out . join ( "rustdoc" ) ) ;
1155
1194
cmd. env ( "RUSTC_STAGE" , compiler. stage . to_string ( ) )
@@ -1200,7 +1239,12 @@ impl<'a> Builder<'a> {
1200
1239
target : TargetSelection ,
1201
1240
cmd : & str ,
1202
1241
) -> Command {
1203
- let mut cargo = Command :: new ( & self . initial_cargo ) ;
1242
+ let mut cargo = if cmd == "clippy" {
1243
+ self . cargo_clippy_cmd ( compiler)
1244
+ } else {
1245
+ Command :: new ( & self . initial_cargo )
1246
+ } ;
1247
+
1204
1248
// Run cargo from the source root so it can find .cargo/config.
1205
1249
// This matters when using vendoring and the working directory is outside the repository.
1206
1250
cargo. current_dir ( & self . src ) ;
@@ -1324,6 +1368,23 @@ impl<'a> Builder<'a> {
1324
1368
compiler. stage
1325
1369
} ;
1326
1370
1371
+ // We synthetically interpret a stage0 compiler used to build tools as a
1372
+ // "raw" compiler in that it's the exact snapshot we download. Normally
1373
+ // the stage0 build means it uses libraries build by the stage0
1374
+ // compiler, but for tools we just use the precompiled libraries that
1375
+ // we've downloaded
1376
+ let use_snapshot = mode == Mode :: ToolBootstrap ;
1377
+ assert ! ( !use_snapshot || stage == 0 || self . local_rebuild) ;
1378
+
1379
+ let maybe_sysroot = self . sysroot ( compiler) ;
1380
+ let sysroot = if use_snapshot { self . rustc_snapshot_sysroot ( ) } else { & maybe_sysroot } ;
1381
+ let libdir = self . rustc_libdir ( compiler) ;
1382
+
1383
+ let sysroot_str = sysroot. as_os_str ( ) . to_str ( ) . expect ( "sysroot should be UTF-8" ) ;
1384
+ if !matches ! ( self . config. dry_run, DryRun :: SelfCheck ) {
1385
+ self . verbose_than ( 0 , & format ! ( "using sysroot {sysroot_str}" ) ) ;
1386
+ }
1387
+
1327
1388
let mut rustflags = Rustflags :: new ( target) ;
1328
1389
if stage != 0 {
1329
1390
if let Ok ( s) = env:: var ( "CARGOFLAGS_NOT_BOOTSTRAP" ) {
@@ -1335,41 +1396,18 @@ impl<'a> Builder<'a> {
1335
1396
cargo. args ( s. split_whitespace ( ) ) ;
1336
1397
}
1337
1398
rustflags. env ( "RUSTFLAGS_BOOTSTRAP" ) ;
1338
- if cmd == "clippy" {
1339
- // clippy overwrites sysroot if we pass it to cargo.
1340
- // Pass it directly to clippy instead.
1341
- // NOTE: this can't be fixed in clippy because we explicitly don't set `RUSTC`,
1342
- // so it has no way of knowing the sysroot.
1343
- rustflags. arg ( "--sysroot" ) ;
1344
- rustflags. arg (
1345
- self . sysroot ( compiler)
1346
- . as_os_str ( )
1347
- . to_str ( )
1348
- . expect ( "sysroot must be valid UTF-8" ) ,
1349
- ) ;
1350
- // Only run clippy on a very limited subset of crates (in particular, not build scripts).
1351
- cargo. arg ( "-Zunstable-options" ) ;
1352
- // Explicitly does *not* set `--cfg=bootstrap`, since we're using a nightly clippy.
1353
- let host_version = Command :: new ( "rustc" ) . arg ( "--version" ) . output ( ) . map_err ( |_| ( ) ) ;
1354
- let output = host_version. and_then ( |output| {
1355
- if output. status . success ( ) {
1356
- Ok ( output)
1357
- } else {
1358
- Err ( ( ) )
1359
- }
1360
- } ) . unwrap_or_else ( |_| {
1361
- eprintln ! (
1362
- "error: `x.py clippy` requires a host `rustc` toolchain with the `clippy` component"
1363
- ) ;
1364
- eprintln ! ( "help: try `rustup component add clippy`" ) ;
1365
- crate :: exit!( 1 ) ;
1366
- } ) ;
1367
- if !t ! ( std:: str :: from_utf8( & output. stdout) ) . contains ( "nightly" ) {
1368
- rustflags. arg ( "--cfg=bootstrap" ) ;
1369
- }
1370
- } else {
1371
- rustflags. arg ( "--cfg=bootstrap" ) ;
1372
- }
1399
+ rustflags. arg ( "--cfg=bootstrap" ) ;
1400
+ }
1401
+
1402
+ if cmd == "clippy" {
1403
+ // clippy overwrites sysroot if we pass it to cargo.
1404
+ // Pass it directly to clippy instead.
1405
+ // NOTE: this can't be fixed in clippy because we explicitly don't set `RUSTC`,
1406
+ // so it has no way of knowing the sysroot.
1407
+ rustflags. arg ( "--sysroot" ) ;
1408
+ rustflags. arg ( sysroot_str) ;
1409
+ // Only run clippy on a very limited subset of crates (in particular, not build scripts).
1410
+ cargo. arg ( "-Zunstable-options" ) ;
1373
1411
}
1374
1412
1375
1413
let use_new_symbol_mangling = match self . config . rust_new_symbol_mangling {
@@ -1583,18 +1621,6 @@ impl<'a> Builder<'a> {
1583
1621
1584
1622
let want_rustdoc = self . doc_tests != DocTests :: No ;
1585
1623
1586
- // We synthetically interpret a stage0 compiler used to build tools as a
1587
- // "raw" compiler in that it's the exact snapshot we download. Normally
1588
- // the stage0 build means it uses libraries build by the stage0
1589
- // compiler, but for tools we just use the precompiled libraries that
1590
- // we've downloaded
1591
- let use_snapshot = mode == Mode :: ToolBootstrap ;
1592
- assert ! ( !use_snapshot || stage == 0 || self . local_rebuild) ;
1593
-
1594
- let maybe_sysroot = self . sysroot ( compiler) ;
1595
- let sysroot = if use_snapshot { self . rustc_snapshot_sysroot ( ) } else { & maybe_sysroot } ;
1596
- let libdir = self . rustc_libdir ( compiler) ;
1597
-
1598
1624
// Clear the output directory if the real rustc we're using has changed;
1599
1625
// Cargo cannot detect this as it thinks rustc is bootstrap/debug/rustc.
1600
1626
//
@@ -1630,20 +1656,17 @@ impl<'a> Builder<'a> {
1630
1656
)
1631
1657
. env ( "RUSTC_ERROR_METADATA_DST" , self . extended_error_dir ( ) )
1632
1658
. env ( "RUSTC_BREAK_ON_ICE" , "1" ) ;
1633
- // Clippy support is a hack and uses the default `cargo-clippy` in path.
1634
- // Don't override RUSTC so that the `cargo-clippy` in path will be run.
1635
- if cmd != "clippy" {
1636
- // Set RUSTC_WRAPPER to the bootstrap shim, which switches between beta and in-tree
1637
- // sysroot depending on whether we're building build scripts.
1638
- // NOTE: we intentionally use RUSTC_WRAPPER so that we can support clippy - RUSTC is not
1639
- // respected by clippy-driver; RUSTC_WRAPPER happens earlier, before clippy runs.
1640
- cargo. env ( "RUSTC_WRAPPER" , self . bootstrap_out . join ( "rustc" ) ) ;
1641
-
1642
- // Someone might have set some previous rustc wrapper (e.g.
1643
- // sccache) before bootstrap overrode it. Respect that variable.
1644
- if let Some ( existing_wrapper) = env:: var_os ( "RUSTC_WRAPPER" ) {
1645
- cargo. env ( "RUSTC_WRAPPER_REAL" , existing_wrapper) ;
1646
- }
1659
+
1660
+ // Set RUSTC_WRAPPER to the bootstrap shim, which switches between beta and in-tree
1661
+ // sysroot depending on whether we're building build scripts.
1662
+ // NOTE: we intentionally use RUSTC_WRAPPER so that we can support clippy - RUSTC is not
1663
+ // respected by clippy-driver; RUSTC_WRAPPER happens earlier, before clippy runs.
1664
+ cargo. env ( "RUSTC_WRAPPER" , self . bootstrap_out . join ( "rustc" ) ) ;
1665
+
1666
+ // Someone might have set some previous rustc wrapper (e.g.
1667
+ // sccache) before bootstrap overrode it. Respect that variable.
1668
+ if let Some ( existing_wrapper) = env:: var_os ( "RUSTC_WRAPPER" ) {
1669
+ cargo. env ( "RUSTC_WRAPPER_REAL" , existing_wrapper) ;
1647
1670
}
1648
1671
1649
1672
// Dealing with rpath here is a little special, so let's go into some
0 commit comments