Skip to content

Commit 3ee4325

Browse files
committed
Link std statically in rustc_driver
1 parent 730d5d4 commit 3ee4325

File tree

9 files changed

+70
-11
lines changed

9 files changed

+70
-11
lines changed

Diff for: compiler/rustc/src/main.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// We need this feature as it changes `dylib` linking behavior and allows us to link to `rustc_driver`.
2+
#![feature(rustc_private)]
3+
14
// A note about jemalloc: rustc uses jemalloc when built for CI and
25
// distribution. The obvious way to do this is with the `#[global_allocator]`
36
// mechanism. However, for complicated reasons (see

Diff for: compiler/rustc_metadata/src/dependency_format.rs

+30-6
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
//! Additionally, the algorithm is geared towards finding *any* solution rather
5252
//! than finding a number of solutions (there are normally quite a few).
5353
54-
use rustc_data_structures::fx::FxHashMap;
54+
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
5555
use rustc_hir::def_id::CrateNum;
5656
use rustc_middle::bug;
5757
use rustc_middle::middle::dependency_format::{Dependencies, DependencyList, Linkage};
@@ -160,18 +160,43 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
160160
Linkage::Dynamic | Linkage::IncludedFromDylib => {}
161161
}
162162

163+
let all_dylibs = || {
164+
tcx.crates(()).iter().filter(|&&cnum| {
165+
!tcx.dep_kind(cnum).macros_only() && tcx.used_crate_source(cnum).dylib.is_some()
166+
})
167+
};
168+
169+
let mut upstream_in_dylibs = FxHashSet::default();
170+
171+
if tcx.features().rustc_private {
172+
// We need this to prevent users of `rustc_driver` from linking dynamically to `std`
173+
// which does not work as `std` is also statically linked into `rustc_driver`.
174+
175+
// Find all libraries statically linked to upstream dylibs.
176+
for &cnum in all_dylibs() {
177+
let deps = tcx.dylib_dependency_formats(cnum);
178+
for &(depnum, style) in deps.iter() {
179+
if let RequireStatic = style {
180+
upstream_in_dylibs.insert(depnum);
181+
}
182+
}
183+
}
184+
}
185+
163186
let mut formats = FxHashMap::default();
164187

165188
// Sweep all crates for found dylibs. Add all dylibs, as well as their
166189
// dependencies, ensuring there are no conflicts. The only valid case for a
167190
// dependency to be relied upon twice is for both cases to rely on a dylib.
168-
for &cnum in tcx.crates(()).iter() {
169-
if tcx.dep_kind(cnum).macros_only() {
191+
for &cnum in all_dylibs() {
192+
if upstream_in_dylibs.contains(&cnum) {
193+
info!("skipping dylib: {}", tcx.crate_name(cnum));
194+
// If this dylib is also available statically linked to another dylib
195+
// we try to use that instead.
170196
continue;
171197
}
198+
172199
let name = tcx.crate_name(cnum);
173-
let src = tcx.used_crate_source(cnum);
174-
if src.dylib.is_some() {
175200
info!("adding dylib: {}", name);
176201
add_library(tcx, cnum, RequireDynamic, &mut formats, &mut unavailable_as_static);
177202
let deps = tcx.dylib_dependency_formats(cnum);
@@ -180,7 +205,6 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
180205
add_library(tcx, depnum, style, &mut formats, &mut unavailable_as_static);
181206
}
182207
}
183-
}
184208

185209
// Collect what we've got so far in the return vector.
186210
let last_crate = tcx.crates(()).len();

Diff for: src/bootstrap/src/bin/rustc.rs

+17-3
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,23 @@ fn main() {
8989
rustc_real
9090
};
9191

92+
// Get the name of the crate we're compiling, if any.
93+
let crate_name = parse_value_from_args(&orig_args, "--crate-name");
94+
95+
// We want everything statically linked into `rustc_driver`, so remove `-C prefer-dynamic`
96+
if crate_name == Some("rustc_driver") && stage != "0" {
97+
// Remove `-C prefer-dynamic` to link `std` statically into `rustc_driver`
98+
if let Some(pos) = args.iter().enumerate().position(|(i, a)| {
99+
a == "-C" && args.get(i + 1).map(|a| a == "prefer-dynamic").unwrap_or(false)
100+
}) {
101+
args.remove(pos);
102+
args.remove(pos);
103+
}
104+
if let Some(pos) = args.iter().position(|a| a == "-Cprefer-dynamic") {
105+
args.remove(pos);
106+
}
107+
}
108+
92109
let mut cmd = match env::var_os("RUSTC_WRAPPER_REAL") {
93110
Some(wrapper) if !wrapper.is_empty() => {
94111
let mut cmd = Command::new(wrapper);
@@ -99,9 +116,6 @@ fn main() {
99116
};
100117
cmd.args(&args).env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());
101118

102-
// Get the name of the crate we're compiling, if any.
103-
let crate_name = parse_value_from_args(&orig_args, "--crate-name");
104-
105119
if let Some(crate_name) = crate_name {
106120
if let Some(target) = env::var_os("RUSTC_TIME") {
107121
if target == "all"

Diff for: src/bootstrap/src/core/build_steps/compile.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -1836,7 +1836,12 @@ impl Step for Assemble {
18361836
let src_libdir = builder.sysroot_libdir(build_compiler, host);
18371837
for f in builder.read_dir(&src_libdir) {
18381838
let filename = f.file_name().into_string().unwrap();
1839-
if (is_dylib(&filename) || is_debug_info(&filename)) && !proc_macros.contains(&filename)
1839+
let can_be_rustc_dep = filename.starts_with("rustc_driver-")
1840+
|| filename.starts_with("librustc_driver-")
1841+
|| build_compiler.stage == 0;
1842+
if can_be_rustc_dep
1843+
&& (is_dylib(&filename) || is_debug_info(&filename))
1844+
&& !proc_macros.contains(&filename)
18401845
{
18411846
builder.copy_link(&f.path(), &rustc_libdir.join(&filename));
18421847
}

Diff for: src/bootstrap/src/core/builder.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2162,7 +2162,7 @@ impl<'a> Builder<'a> {
21622162
// When we build Rust dylibs they're all intended for intermediate
21632163
// usage, so make sure we pass the -Cprefer-dynamic flag instead of
21642164
// linking all deps statically into the dylib.
2165-
if matches!(mode, Mode::Std | Mode::Rustc) {
2165+
if matches!(mode, Mode::Std) {
21662166
rustflags.arg("-Cprefer-dynamic");
21672167
}
21682168

Diff for: src/tools/clippy/src/main.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// We need this feature as it changes `dylib` linking behavior and allows us to link to
2+
// `rustc_driver`.
3+
#![feature(rustc_private)]
14
// warn on lints, that are included in `rust-lang/rust`s bootstrap
25
#![warn(rust_2018_idioms, unused_lifetimes)]
36

Diff for: src/tools/clippy/tests/compile-test.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// We need this feature as it changes `dylib` linking behavior and allows us to link to
2+
// `rustc_driver`.
3+
#![feature(rustc_private)]
14
#![warn(rust_2018_idioms, unused_lifetimes)]
25
#![allow(unused_extern_crates)]
36

Diff for: src/tools/rustdoc/main.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// We need this feature as it changes `dylib` linking behavior and allows us to link to `rustc_driver`.
2+
#![feature(rustc_private)]
3+
14
fn main() {
25
rustdoc::main()
36
}

Diff for: src/tools/rustfmt/src/git-rustfmt/main.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
// We need this feature as it changes `dylib` linking behavior and allows us to link to
2+
// `rustc_driver`.
3+
#![feature(rustc_private)]
4+
15
#[macro_use]
26
extern crate tracing;
37

0 commit comments

Comments
 (0)