@@ -19,8 +19,10 @@ use crate::core::build_steps::{check, clean, compile, dist, doc, install, run, s
1919use crate :: core:: config:: flags:: { Color , Subcommand } ;
2020use crate :: core:: config:: { DryRun , SplitDebuginfo , TargetSelection } ;
2121use crate :: utils:: cache:: { Cache , Interned , INTERNER } ;
22- use crate :: utils:: helpers:: { self , add_dylib_path, add_link_lib_path, add_rustdoc_lld_flags, exe} ;
23- use crate :: utils:: helpers:: { libdir, output, t, LldThreads } ;
22+ use crate :: utils:: helpers:: {
23+ self , add_dylib_path, add_link_lib_path, add_rustdoc_lld_flags, dylib_path, dylib_path_var,
24+ exe, libdir, output, t, LldThreads ,
25+ } ;
2426use crate :: Crate ;
2527use crate :: EXTRA_CHECK_CFGS ;
2628use crate :: { Build , CLang , DocTests , GitRepo , Mode } ;
@@ -1152,6 +1154,43 @@ impl<'a> Builder<'a> {
11521154 self . ensure ( tool:: Rustdoc { compiler } )
11531155 }
11541156
1157+ pub fn cargo_clippy_cmd ( & self , run_compiler : Compiler ) -> Command {
1158+ let initial_sysroot_bin = self . initial_rustc . parent ( ) . unwrap ( ) ;
1159+ // Set PATH to include the sysroot bin dir so clippy can find cargo.
1160+ let path = t ! ( env:: join_paths(
1161+ // The sysroot comes first in PATH to avoid using rustup's cargo.
1162+ std:: iter:: once( PathBuf :: from( initial_sysroot_bin) )
1163+ . chain( env:: split_paths( & t!( env:: var( "PATH" ) ) ) )
1164+ ) ) ;
1165+
1166+ if run_compiler. stage == 0 {
1167+ // `ensure(Clippy { stage: 0 })` *builds* clippy with stage0, it doesn't use the beta clippy.
1168+ let cargo_clippy = self . initial_rustc . parent ( ) . unwrap ( ) . join ( "cargo-clippy" ) ;
1169+ let mut cmd = Command :: new ( cargo_clippy) ;
1170+ cmd. env ( "PATH" , & path) ;
1171+ return cmd;
1172+ }
1173+
1174+ let build_compiler = self . compiler ( run_compiler. stage - 1 , self . build . build ) ;
1175+ self . ensure ( tool:: Clippy {
1176+ compiler : build_compiler,
1177+ target : self . build . build ,
1178+ extra_features : vec ! [ ] ,
1179+ } ) ;
1180+ let cargo_clippy = self . ensure ( tool:: CargoClippy {
1181+ compiler : build_compiler,
1182+ target : self . build . build ,
1183+ extra_features : vec ! [ ] ,
1184+ } ) ;
1185+ let mut dylib_path = dylib_path ( ) ;
1186+ dylib_path. insert ( 0 , self . sysroot ( run_compiler) . join ( "lib" ) ) ;
1187+
1188+ let mut cmd = Command :: new ( cargo_clippy. unwrap ( ) ) ;
1189+ cmd. env ( dylib_path_var ( ) , env:: join_paths ( & dylib_path) . unwrap ( ) ) ;
1190+ cmd. env ( "PATH" , path) ;
1191+ cmd
1192+ }
1193+
11551194 pub fn rustdoc_cmd ( & self , compiler : Compiler ) -> Command {
11561195 let mut cmd = Command :: new ( & self . bootstrap_out . join ( "rustdoc" ) ) ;
11571196 cmd. env ( "RUSTC_STAGE" , compiler. stage . to_string ( ) )
@@ -1200,7 +1239,12 @@ impl<'a> Builder<'a> {
12001239 target : TargetSelection ,
12011240 cmd : & str ,
12021241 ) -> 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+
12041248 // Run cargo from the source root so it can find .cargo/config.
12051249 // This matters when using vendoring and the working directory is outside the repository.
12061250 cargo. current_dir ( & self . src ) ;
@@ -1324,6 +1368,23 @@ impl<'a> Builder<'a> {
13241368 compiler. stage
13251369 } ;
13261370
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+
13271388 let mut rustflags = Rustflags :: new ( target) ;
13281389 if stage != 0 {
13291390 if let Ok ( s) = env:: var ( "CARGOFLAGS_NOT_BOOTSTRAP" ) {
@@ -1335,41 +1396,18 @@ impl<'a> Builder<'a> {
13351396 cargo. args ( s. split_whitespace ( ) ) ;
13361397 }
13371398 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" ) ;
13731411 }
13741412
13751413 let use_new_symbol_mangling = match self . config . rust_new_symbol_mangling {
@@ -1564,18 +1602,6 @@ impl<'a> Builder<'a> {
15641602
15651603 let want_rustdoc = self . doc_tests != DocTests :: No ;
15661604
1567- // We synthetically interpret a stage0 compiler used to build tools as a
1568- // "raw" compiler in that it's the exact snapshot we download. Normally
1569- // the stage0 build means it uses libraries build by the stage0
1570- // compiler, but for tools we just use the precompiled libraries that
1571- // we've downloaded
1572- let use_snapshot = mode == Mode :: ToolBootstrap ;
1573- assert ! ( !use_snapshot || stage == 0 || self . local_rebuild) ;
1574-
1575- let maybe_sysroot = self . sysroot ( compiler) ;
1576- let sysroot = if use_snapshot { self . rustc_snapshot_sysroot ( ) } else { & maybe_sysroot } ;
1577- let libdir = self . rustc_libdir ( compiler) ;
1578-
15791605 // Clear the output directory if the real rustc we're using has changed;
15801606 // Cargo cannot detect this as it thinks rustc is bootstrap/debug/rustc.
15811607 //
@@ -1611,20 +1637,17 @@ impl<'a> Builder<'a> {
16111637 )
16121638 . env ( "RUSTC_ERROR_METADATA_DST" , self . extended_error_dir ( ) )
16131639 . env ( "RUSTC_BREAK_ON_ICE" , "1" ) ;
1614- // Clippy support is a hack and uses the default `cargo-clippy` in path.
1615- // Don't override RUSTC so that the `cargo-clippy` in path will be run.
1616- if cmd != "clippy" {
1617- // Set RUSTC_WRAPPER to the bootstrap shim, which switches between beta and in-tree
1618- // sysroot depending on whether we're building build scripts.
1619- // NOTE: we intentionally use RUSTC_WRAPPER so that we can support clippy - RUSTC is not
1620- // respected by clippy-driver; RUSTC_WRAPPER happens earlier, before clippy runs.
1621- cargo. env ( "RUSTC_WRAPPER" , self . bootstrap_out . join ( "rustc" ) ) ;
1622-
1623- // Someone might have set some previous rustc wrapper (e.g.
1624- // sccache) before bootstrap overrode it. Respect that variable.
1625- if let Some ( existing_wrapper) = env:: var_os ( "RUSTC_WRAPPER" ) {
1626- cargo. env ( "RUSTC_WRAPPER_REAL" , existing_wrapper) ;
1627- }
1640+
1641+ // Set RUSTC_WRAPPER to the bootstrap shim, which switches between beta and in-tree
1642+ // sysroot depending on whether we're building build scripts.
1643+ // NOTE: we intentionally use RUSTC_WRAPPER so that we can support clippy - RUSTC is not
1644+ // respected by clippy-driver; RUSTC_WRAPPER happens earlier, before clippy runs.
1645+ cargo. env ( "RUSTC_WRAPPER" , self . bootstrap_out . join ( "rustc" ) ) ;
1646+
1647+ // Someone might have set some previous rustc wrapper (e.g.
1648+ // sccache) before bootstrap overrode it. Respect that variable.
1649+ if let Some ( existing_wrapper) = env:: var_os ( "RUSTC_WRAPPER" ) {
1650+ cargo. env ( "RUSTC_WRAPPER_REAL" , existing_wrapper) ;
16281651 }
16291652
16301653 // Dealing with rpath here is a little special, so let's go into some
0 commit comments