Skip to content

Commit

Permalink
Auto merge of #122362 - Zoxc:rustc_driver_static_std, r=<try>
Browse files Browse the repository at this point in the history
Link `std` statically in `rustc_driver`

This makes `rustc_driver` statically link to `std`. This is done by not passing `-C prefer-dynamic` when building `rustc_driver`. However building `rustc-main` won't work currently as it tries to dynamically link to both `rustc_driver` and `std` resulting in a crate graph with `std` duplicated. To fix that new command line option `-Z prefer_deps_of_dynamic` is added which prevents linking to a dylib if there's a static variant of it already statically linked into another dylib dependency.

The main motivation for this change is to enable `#[global_allocator]` to be used in `rustc_driver` allowing overriding the allocator used in rustc on all platforms.
  • Loading branch information
bors committed Mar 12, 2024
2 parents 0fa7fea + d5cdb9e commit 380a85b
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 17 deletions.
1 change: 1 addition & 0 deletions compiler/rustc_interface/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -806,6 +806,7 @@ fn test_unstable_options_tracking_hash() {
tracked!(plt, Some(true));
tracked!(polonius, Polonius::Legacy);
tracked!(precise_enum_drop_elaboration, false);
tracked!(prefer_deps_of_dynamic, true);
tracked!(print_fuel, Some("abc".to_string()));
tracked!(profile, true);
tracked!(profile_emit, Some(PathBuf::from("abc")));
Expand Down
45 changes: 33 additions & 12 deletions compiler/rustc_metadata/src/dependency_format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ use crate::errors::{
RequiredPanicStrategy, RlibRequired, RustcLibRequired, TwoPanicRuntimes,
};

use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir::def_id::CrateNum;
use rustc_middle::middle::dependency_format::{Dependencies, DependencyList, Linkage};
use rustc_middle::ty::TyCtxt;
Expand Down Expand Up @@ -156,25 +156,46 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
Linkage::Dynamic | Linkage::IncludedFromDylib => {}
}

let all_dylibs = || {
tcx.crates(()).iter().filter(|&&cnum| {
!tcx.dep_kind(cnum).macros_only() && tcx.used_crate_source(cnum).dylib.is_some()
})
};

let mut upstream_in_dylibs = FxHashSet::default();

if sess.opts.unstable_opts.prefer_deps_of_dynamic || tcx.features().rustc_private {
// Find all libraries statically linked to upstream dylibs.
for &cnum in all_dylibs() {
let deps = tcx.dylib_dependency_formats(cnum);
for &(depnum, style) in deps.iter() {
if let RequireStatic = style {
upstream_in_dylibs.insert(depnum);
}
}
}
}

let mut formats = FxHashMap::default();

// Sweep all crates for found dylibs. Add all dylibs, as well as their
// dependencies, ensuring there are no conflicts. The only valid case for a
// dependency to be relied upon twice is for both cases to rely on a dylib.
for &cnum in tcx.crates(()).iter() {
if tcx.dep_kind(cnum).macros_only() {
for &cnum in all_dylibs() {
if upstream_in_dylibs.contains(&cnum) {
info!("skipping dylib: {}", tcx.crate_name(cnum));
// If this dylib is also available statically linked to another dylib
// we try to use that instead.
continue;
}

let name = tcx.crate_name(cnum);
let src = tcx.used_crate_source(cnum);
if src.dylib.is_some() {
info!("adding dylib: {}", name);
add_library(tcx, cnum, RequireDynamic, &mut formats);
let deps = tcx.dylib_dependency_formats(cnum);
for &(depnum, style) in deps.iter() {
info!("adding {:?}: {}", style, tcx.crate_name(depnum));
add_library(tcx, depnum, style, &mut formats);
}
info!("adding dylib: {}", name);
add_library(tcx, cnum, RequireDynamic, &mut formats);
let deps = tcx.dylib_dependency_formats(cnum);
for &(depnum, style) in deps.iter() {
info!("adding {:?}: {}", style, tcx.crate_name(depnum));
add_library(tcx, depnum, style, &mut formats);
}
}

Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1810,6 +1810,8 @@ options! {
"use a more precise version of drop elaboration for matches on enums (default: yes). \
This results in better codegen, but has caused miscompilations on some tier 2 platforms. \
See #77382 and #74551."),
prefer_deps_of_dynamic: bool = (false, parse_bool, [TRACKED],
"prefer linking to static dependencies of dynamic libraries over available dynamic libraries (default: no)"),
#[rustc_lint_opt_deny_field_access("use `Session::print_codegen_stats` instead of this field")]
print_codegen_stats: bool = (false, parse_bool, [UNTRACKED],
"print codegen statistics (default: no)"),
Expand Down
16 changes: 13 additions & 3 deletions src/bootstrap/src/bin/rustc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,19 @@ fn main() {
rustc_real
};

// Get the name of the crate we're compiling, if any.
let crate_name = arg("--crate-name");

// We want everything statically linked into `rustc_driver`, so remove `-C prefer-dynamic`
if crate_name == Some("rustc_driver") && stage != "0" {
if let Some(i) = args.iter().enumerate().position(|(i, a)| {
a == "-C" && args.get(i + 1).map(|a| a == "prefer-dynamic").unwrap_or(false)
}) {
args.remove(i);
args.remove(i);
}
}

let mut cmd = if let Some(wrapper) = env::var_os("RUSTC_WRAPPER_REAL") {
let mut cmd = Command::new(wrapper);
cmd.arg(rustc_driver);
Expand All @@ -100,9 +113,6 @@ fn main() {
};
cmd.args(&args).env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());

// Get the name of the crate we're compiling, if any.
let crate_name = arg("--crate-name");

if let Some(crate_name) = crate_name {
if let Some(target) = env::var_os("RUSTC_TIME") {
if target == "all"
Expand Down
7 changes: 6 additions & 1 deletion src/bootstrap/src/core/build_steps/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1788,7 +1788,12 @@ impl Step for Assemble {
let src_libdir = builder.sysroot_libdir(build_compiler, host);
for f in builder.read_dir(&src_libdir) {
let filename = f.file_name().into_string().unwrap();
if (is_dylib(&filename) || is_debug_info(&filename)) && !proc_macros.contains(&filename)
let can_be_rustc_dep = filename.starts_with("rustc_driver-")
|| filename.starts_with("librustc_driver-")
|| build_compiler.stage == 0;
if can_be_rustc_dep
&& (is_dylib(&filename) || is_debug_info(&filename))
&& !proc_macros.contains(&filename)
{
builder.copy(&f.path(), &rustc_libdir.join(&filename));
}
Expand Down
8 changes: 7 additions & 1 deletion src/bootstrap/src/core/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2029,10 +2029,16 @@ impl<'a> Builder<'a> {
// When we build Rust dylibs they're all intended for intermediate
// usage, so make sure we pass the -Cprefer-dynamic flag instead of
// linking all deps statically into the dylib.
if matches!(mode, Mode::Std | Mode::Rustc) {
if matches!(mode, Mode::Std) {
rustflags.arg("-Cprefer-dynamic");
}

// We need this to prevent users of `rustc_driver` from linking to dynamically to `std`
// which does not work as `std` is statically linked into `rustc_driver`.
if stage > 0 {
rustflags.arg("-Zprefer-deps-of-dynamic");
}

// When building incrementally we default to a lower ThinLTO import limit
// (unless explicitly specified otherwise). This will produce a somewhat
// slower code but give way better compile times.
Expand Down

0 comments on commit 380a85b

Please sign in to comment.