]> git.proxmox.com Git - rustc.git/blobdiff - src/bootstrap/compile.rs
New upstream version 1.64.0+dfsg1
[rustc.git] / src / bootstrap / compile.rs
index b4807d1ab3af2f1edf62b6bcd8bb1ee1e8d3daff..dd2b9d59366eab0b5bfc38dfe20a116a8381afca 100644 (file)
@@ -13,7 +13,7 @@ use std::fs;
 use std::io::prelude::*;
 use std::io::BufReader;
 use std::path::{Path, PathBuf};
-use std::process::{exit, Command, Stdio};
+use std::process::{Command, Stdio};
 use std::str;
 
 use serde::Deserialize;
@@ -25,14 +25,36 @@ use crate::config::{LlvmLibunwind, TargetSelection};
 use crate::dist;
 use crate::native;
 use crate::tool::SourceType;
+use crate::util::get_clang_cl_resource_dir;
 use crate::util::{exe, is_debug_info, is_dylib, output, symlink_dir, t, up_to_date};
 use crate::LLVM_TOOLS;
 use crate::{CLang, Compiler, DependencyType, GitRepo, Mode};
 
-#[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub struct Std {
     pub target: TargetSelection,
     pub compiler: Compiler,
+    /// Whether to build only a subset of crates in the standard library.
+    ///
+    /// This shouldn't be used from other steps; see the comment on [`Rustc`].
+    crates: Interned<Vec<String>>,
+}
+
+impl Std {
+    pub fn new(compiler: Compiler, target: TargetSelection) -> Self {
+        Self { target, compiler, crates: Default::default() }
+    }
+}
+
+/// Return a `-p=x -p=y` string suitable for passing to a cargo invocation.
+fn build_crates_in_set(run: &RunConfig<'_>) -> Interned<Vec<String>> {
+    let mut crates = Vec::new();
+    for krate in &run.paths {
+        let path = krate.assert_single_path();
+        let crate_name = run.builder.crate_paths[&path.path];
+        crates.push(format!("-p={crate_name}"));
+    }
+    INTERNER.intern_list(crates)
 }
 
 impl Step for Std {
@@ -43,15 +65,22 @@ impl Step for Std {
         // When downloading stage1, the standard library has already been copied to the sysroot, so
         // there's no need to rebuild it.
         let builder = run.builder;
-        run.all_krates("test")
+        run.crate_or_deps("test")
             .path("library")
             .lazy_default_condition(Box::new(|| !builder.download_rustc()))
     }
 
     fn make_run(run: RunConfig<'_>) {
+        // Normally, people will pass *just* library if they pass it.
+        // But it's possible (although strange) to pass something like `library std core`.
+        // Build all crates anyway, as if they hadn't passed the other args.
+        let has_library =
+            run.paths.iter().any(|set| set.assert_single_path().path.ends_with("library"));
+        let crates = if has_library { Default::default() } else { build_crates_in_set(&run) };
         run.builder.ensure(Std {
             compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()),
             target: run.target,
+            crates,
         });
     }
 
@@ -76,17 +105,22 @@ impl Step for Std {
             || builder.config.keep_stage_std.contains(&compiler.stage)
         {
             builder.info("Warning: Using a potentially old libstd. This may not behave well.");
-            builder.ensure(StdLink { compiler, target_compiler: compiler, target });
+            builder.ensure(StdLink::from_std(self, compiler));
             return;
         }
 
         builder.update_submodule(&Path::new("library").join("stdarch"));
 
+        // Profiler information requires LLVM's compiler-rt
+        if builder.config.profiler {
+            builder.update_submodule(&Path::new("src/llvm-project"));
+        }
+
         let mut target_deps = builder.ensure(StartupObjects { compiler, target });
 
         let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target);
         if compiler_to_use != compiler {
-            builder.ensure(Std { compiler: compiler_to_use, target });
+            builder.ensure(Std::new(compiler_to_use, target));
             builder.info(&format!("Uplifting stage1 std ({} -> {})", compiler_to_use.host, target));
 
             // Even if we're not building std this stage, the new sysroot must
@@ -94,11 +128,7 @@ impl Step for Std {
             copy_third_party_objects(builder, &compiler, target);
             copy_self_contained_objects(builder, &compiler, target);
 
-            builder.ensure(StdLink {
-                compiler: compiler_to_use,
-                target_compiler: compiler,
-                target,
-            });
+            builder.ensure(StdLink::from_std(self, compiler_to_use));
             return;
         }
 
@@ -115,17 +145,16 @@ impl Step for Std {
         run_cargo(
             builder,
             cargo,
-            vec![],
+            self.crates.to_vec(),
             &libstd_stamp(builder, compiler, target),
             target_deps,
             false,
         );
 
-        builder.ensure(StdLink {
-            compiler: builder.compiler(compiler.stage, builder.config.build),
-            target_compiler: compiler,
-            target,
-        });
+        builder.ensure(StdLink::from_std(
+            self,
+            builder.compiler(compiler.stage, builder.config.build),
+        ));
     }
 }
 
@@ -366,6 +395,19 @@ struct StdLink {
     pub compiler: Compiler,
     pub target_compiler: Compiler,
     pub target: TargetSelection,
+    /// Not actually used; only present to make sure the cache invalidation is correct.
+    crates: Interned<Vec<String>>,
+}
+
+impl StdLink {
+    fn from_std(std: Std, host_compiler: Compiler) -> Self {
+        Self {
+            compiler: host_compiler,
+            target_compiler: std.compiler,
+            target: std.target,
+            crates: std.crates,
+        }
+    }
 }
 
 impl Step for StdLink {
@@ -524,6 +566,18 @@ impl Step for StartupObjects {
 pub struct Rustc {
     pub target: TargetSelection,
     pub compiler: Compiler,
+    /// Whether to build a subset of crates, rather than the whole compiler.
+    ///
+    /// This should only be requested by the user, not used within rustbuild itself.
+    /// Using it within rustbuild can lead to confusing situation where lints are replayed
+    /// in two different steps.
+    crates: Interned<Vec<String>>,
+}
+
+impl Rustc {
+    pub fn new(compiler: Compiler, target: TargetSelection) -> Self {
+        Self { target, compiler, crates: Default::default() }
+    }
 }
 
 impl Step for Rustc {
@@ -532,13 +586,22 @@ impl Step for Rustc {
     const DEFAULT: bool = false;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.never()
+        let mut crates = run.builder.in_tree_crates("rustc-main", None);
+        for (i, krate) in crates.iter().enumerate() {
+            if krate.name == "rustc-main" {
+                crates.swap_remove(i);
+                break;
+            }
+        }
+        run.crates(crates)
     }
 
     fn make_run(run: RunConfig<'_>) {
+        let crates = build_crates_in_set(&run);
         run.builder.ensure(Rustc {
             compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()),
             target: run.target,
+            crates,
         });
     }
 
@@ -560,33 +623,29 @@ impl Step for Rustc {
             return;
         }
 
-        builder.ensure(Std { compiler, target });
+        builder.ensure(Std::new(compiler, target));
 
         if builder.config.keep_stage.contains(&compiler.stage) {
             builder.info("Warning: Using a potentially old librustc. This may not behave well.");
             builder.info("Warning: Use `--keep-stage-std` if you want to rebuild the compiler when it changes");
-            builder.ensure(RustcLink { compiler, target_compiler: compiler, target });
+            builder.ensure(RustcLink::from_rustc(self, compiler));
             return;
         }
 
         let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target);
         if compiler_to_use != compiler {
-            builder.ensure(Rustc { compiler: compiler_to_use, target });
+            builder.ensure(Rustc::new(compiler_to_use, target));
             builder
                 .info(&format!("Uplifting stage1 rustc ({} -> {})", builder.config.build, target));
-            builder.ensure(RustcLink {
-                compiler: compiler_to_use,
-                target_compiler: compiler,
-                target,
-            });
+            builder.ensure(RustcLink::from_rustc(self, compiler_to_use));
             return;
         }
 
         // Ensure that build scripts and proc macros have a std / libproc_macro to link against.
-        builder.ensure(Std {
-            compiler: builder.compiler(self.compiler.stage, builder.config.build),
-            target: builder.config.build,
-        });
+        builder.ensure(Std::new(
+            builder.compiler(self.compiler.stage, builder.config.build),
+            builder.config.build,
+        ));
 
         let mut cargo = builder.cargo(compiler, Mode::Rustc, SourceType::InTree, target, "build");
         rustc_cargo(builder, &mut cargo, target);
@@ -597,6 +656,12 @@ impl Step for Rustc {
             panic!("Cannot use and generate PGO profiles at the same time");
         }
 
+        // With LLD, we can use ICF (identical code folding) to reduce the executable size
+        // of librustc_driver/rustc and to improve i-cache utilization.
+        if builder.config.use_lld {
+            cargo.rustflag("-Clink-args=-Wl,--icf=all");
+        }
+
         let is_collecting = if let Some(path) = &builder.config.rust_profile_generate {
             if compiler.stage == 1 {
                 cargo.rustflag(&format!("-Cprofile-generate={}", path));
@@ -633,17 +698,16 @@ impl Step for Rustc {
         run_cargo(
             builder,
             cargo,
-            vec![],
+            self.crates.to_vec(),
             &librustc_stamp(builder, compiler, target),
             vec![],
             false,
         );
 
-        builder.ensure(RustcLink {
-            compiler: builder.compiler(compiler.stage, builder.config.build),
-            target_compiler: compiler,
-            target,
-        });
+        builder.ensure(RustcLink::from_rustc(
+            self,
+            builder.compiler(compiler.stage, builder.config.build),
+        ));
     }
 }
 
@@ -720,10 +784,38 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS
         if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) {
             cargo.env("CFG_LLVM_ROOT", s);
         }
-        // Some LLVM linker flags (-L and -l) may be needed to link rustc_llvm.
+
+        // Some LLVM linker flags (-L and -l) may be needed to link `rustc_llvm`. Its build script
+        // expects these to be passed via the `LLVM_LINKER_FLAGS` env variable, separated by
+        // whitespace.
+        //
+        // For example:
+        // - on windows, when `clang-cl` is used with instrumentation, we need to manually add
+        // clang's runtime library resource directory so that the profiler runtime library can be
+        // found. This is to avoid the linker errors about undefined references to
+        // `__llvm_profile_instrument_memop` when linking `rustc_driver`.
+        let mut llvm_linker_flags = String::new();
+        if builder.config.llvm_profile_generate && target.contains("msvc") {
+            if let Some(ref clang_cl_path) = builder.config.llvm_clang_cl {
+                // Add clang's runtime library directory to the search path
+                let clang_rt_dir = get_clang_cl_resource_dir(clang_cl_path);
+                llvm_linker_flags.push_str(&format!("-L{}", clang_rt_dir.display()));
+            }
+        }
+
+        // The config can also specify its own llvm linker flags.
         if let Some(ref s) = builder.config.llvm_ldflags {
-            cargo.env("LLVM_LINKER_FLAGS", s);
+            if !llvm_linker_flags.is_empty() {
+                llvm_linker_flags.push_str(" ");
+            }
+            llvm_linker_flags.push_str(s);
+        }
+
+        // Set the linker flags via the env var that `rustc_llvm`'s build script will read.
+        if !llvm_linker_flags.is_empty() {
+            cargo.env("LLVM_LINKER_FLAGS", llvm_linker_flags);
         }
+
         // Building with a static libstdc++ is only supported on linux right now,
         // not for MSVC or macOS
         if builder.config.llvm_static_stdcpp
@@ -758,6 +850,19 @@ struct RustcLink {
     pub compiler: Compiler,
     pub target_compiler: Compiler,
     pub target: TargetSelection,
+    /// Not actually used; only present to make sure the cache invalidation is correct.
+    crates: Interned<Vec<String>>,
+}
+
+impl RustcLink {
+    fn from_rustc(rustc: Rustc, host_compiler: Compiler) -> Self {
+        Self {
+            compiler: host_compiler,
+            target_compiler: rustc.compiler,
+            target: rustc.target,
+            crates: rustc.crates,
+        }
+    }
 }
 
 impl Step for RustcLink {
@@ -821,7 +926,7 @@ impl Step for CodegenBackend {
         let target = self.target;
         let backend = self.backend;
 
-        builder.ensure(Rustc { compiler, target });
+        builder.ensure(Rustc::new(compiler, target));
 
         if builder.config.keep_stage.contains(&compiler.stage) {
             builder.info(
@@ -1103,7 +1208,7 @@ impl Step for Assemble {
         // link to these. (FIXME: Is that correct? It seems to be correct most
         // of the time but I think we do link to these for stage2/bin compilers
         // when not performing a full bootstrap).
-        builder.ensure(Rustc { compiler: build_compiler, target: target_compiler.host });
+        builder.ensure(Rustc::new(build_compiler, target_compiler.host));
 
         for &backend in builder.config.rust_codegen_backends.iter() {
             if backend == "llvm" {
@@ -1328,7 +1433,7 @@ pub fn run_cargo(
     });
 
     if !ok {
-        exit(1);
+        crate::detail_exit(1);
     }
 
     // Ok now we need to actually find all the files listed in `toplevel`. We've