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;
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 {
// 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,
});
}
|| 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
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;
}
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),
+ ));
}
}
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 {
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 {
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,
});
}
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);
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));
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),
+ ));
}
}
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
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 {
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(
// 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" {
});
if !ok {
- exit(1);
+ crate::detail_exit(1);
}
// Ok now we need to actually find all the files listed in `toplevel`. We've