Skip to content

Commit e4ad71b

Browse files
committed
Switch to dynamically linked BDWGC
This works by ensuring that the bootstrap phase puts libgc.so inside the sysroot, where the librustc-driver and libtest objects are already given to search at load time in their RPATH.
1 parent 8c2114a commit e4ad71b

File tree

21 files changed

+216
-68
lines changed

21 files changed

+216
-68
lines changed

.buildbot.config.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
[alloy]
22
bdwgc-assertions = true
3+
bdwgc-link-shared = true
34

45
[rust]
56
codegen-units = 0 # Use many compilation units.

.buildbot.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ sh rustup.sh --default-host x86_64-unknown-linux-gnu \
2828
-y
2929
export PATH=$(pwd)/.cargo/bin/:$PATH
3030

31-
rustup toolchain link alloy build/x86_64-unknown-linux-gnu/stage1
31+
rustup toolchain link alloy build/x86_64-unknown-linux-gnu/stage2
3232

3333
# Build and test yksom
3434
git clone --recursive https://github.com/softdevteam/yksom

.buildbot_dockerfile_debian

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ FROM debian:latest
22
ARG CI_UID
33
RUN useradd -m -u ${CI_UID} ci
44
RUN apt-get update && \
5-
apt-get -y install build-essential curl cmake python3 git ninja-build time autoconf libtool libssl-dev pkg-config
5+
apt-get -y install build-essential curl cmake python3 git ninja-build \
6+
time autoconf libclang-dev libtool libssl-dev pkg-config
67
WORKDIR /ci
78
RUN chown ${CI_UID}:${CI_UID} .
89
COPY --chown=${CI_UID}:${CI_UID} . .

compiler/rustc_codegen_ssa/src/back/link.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1318,6 +1318,12 @@ fn link_sanitizer_runtime(
13181318
}
13191319
}
13201320

1321+
fn add_bdwgc(sess: &Session, linker: &mut dyn Linker) {
1322+
let sysroot = sess.sysroot.clone();
1323+
linker.link_args(&["-rpath", &sysroot.join("lib").to_str().unwrap()]);
1324+
linker.link_dylib_by_name("gc", false, false);
1325+
}
1326+
13211327
/// Returns a boolean indicating whether the specified crate should be ignored
13221328
/// during LTO.
13231329
///
@@ -2254,6 +2260,8 @@ fn linker_with_args(
22542260
// Sanitizer libraries.
22552261
add_sanitizer_libraries(sess, flavor, crate_type, cmd);
22562262

2263+
add_bdwgc(sess, cmd);
2264+
22572265
// Object code from the current crate.
22582266
// Take careful note of the ordering of the arguments we pass to the linker
22592267
// here. Linkers will assume that things on the left depend on things to the

library/Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,7 @@ dependencies = [
409409
name = "sysroot"
410410
version = "0.0.0"
411411
dependencies = [
412+
"bdwgc",
412413
"proc_macro",
413414
"profiler_builtins",
414415
"std",

library/bdwgc/build.rs

Lines changed: 3 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -4,50 +4,6 @@ use std::process::Command;
44
#[cfg(not(all(target_pointer_width = "64", target_arch = "x86_64")))]
55
compile_error!("Requires x86_64 with 64 bit pointer width.");
66

7-
#[cfg(not(feature = "link-shared"))]
8-
fn build_bdwgc() {
9-
use std::env;
10-
use std::path::PathBuf;
11-
use std::process::Command;
12-
13-
const BDWGC_REPO: &str = "../../src/bdwgc";
14-
const BDWGC_BUILD_DIR: &str = "lib";
15-
16-
let out_dir = env::var("OUT_DIR").unwrap();
17-
let bdwgc_src = PathBuf::from(BDWGC_REPO);
18-
19-
if bdwgc_src.read_dir().unwrap().count() == 0 {
20-
Command::new("git")
21-
.args(["submodule", "update", "--init", BDWGC_REPO])
22-
.output()
23-
.expect("Failed to clone BDWGC repo");
24-
}
25-
26-
let mut build_dir = PathBuf::from(&out_dir);
27-
build_dir.push(BDWGC_BUILD_DIR);
28-
29-
let mut build = cmake::Config::new(&bdwgc_src);
30-
build
31-
.pic(true)
32-
.define("BUILD_SHARED_LIBS", "OFF")
33-
.define("enable_parallel_mark", "Off")
34-
.cflag("-DGC_ALWAYS_MULTITHREADED");
35-
36-
#[cfg(feature = "gc-assertions")]
37-
build.define("enable_gc_assertions", "ON");
38-
39-
#[cfg(not(feature = "gc-debug"))]
40-
build.profile("Release");
41-
42-
#[cfg(feature = "gc-debug")]
43-
build.profile("Debug");
44-
45-
build.build();
46-
47-
println!("cargo:rustc-link-search=native={}", &build_dir.display());
48-
println!("cargo:rustc-link-lib=static=gc");
49-
}
50-
517
fn main() {
528
let cwd = env::var("CARGO_MANIFEST_DIR").unwrap();
539
let header = Path::new(&cwd)
@@ -64,6 +20,8 @@ fn main() {
6420
let out = Path::new(&env::var("OUT_DIR").unwrap()).join("bindings.rs");
6521
let status = Command::new(bindgen)
6622
.args(&[
23+
"--ctypes-prefix",
24+
"libc",
6725
"--use-core",
6826
"-o",
6927
out.to_str().unwrap(),
@@ -77,8 +35,5 @@ fn main() {
7735
if !status.success() {
7836
panic!("bindgen failed with status: {:?}", status);
7937
}
80-
#[cfg(not(feature = "link-shared"))]
81-
build_bdwgc();
82-
#[cfg(feature = "link-shared")]
83-
println!("cargo:rustc-link-lib=dylib=gc");
38+
println!("cargo::rustc-link-lib=dylib=gc");
8439
}

library/sysroot/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ proc_macro = { path = "../proc_macro", public = true }
1111
profiler_builtins = { path = "../profiler_builtins", optional = true }
1212
std = { path = "../std", public = true }
1313
test = { path = "../test", public = true }
14+
bdwgc = { path = "../bdwgc", public = true }
1415

1516
# Forward features to the `std` crate as necessary
1617
[features]

rustfmt.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ ignore = [
3838
"src/doc/rust-by-example",
3939
"src/doc/rustc-dev-guide",
4040
"src/llvm-project",
41+
"src/tools/bindgen",
4142
"src/tools/cargo",
4243
"src/tools/clippy",
4344
"src/tools/enzyme",
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
//! Compilation of native BDWGC
2+
use std::fs;
3+
use std::path::{Path, PathBuf};
4+
use std::sync::OnceLock;
5+
6+
#[cfg(feature = "tracing")]
7+
use tracing::instrument;
8+
9+
use crate::core::build_steps::llvm;
10+
use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
11+
use crate::core::config::TargetSelection;
12+
use crate::trace;
13+
use crate::utils::build_stamp::{BuildStamp, generate_smart_stamp_hash};
14+
use crate::utils::helpers::{self, t};
15+
16+
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
17+
pub struct Bdwgc {
18+
pub target: TargetSelection,
19+
}
20+
21+
fn libgc_built_path(out_dir: &Path) -> PathBuf {
22+
out_dir.join("lib")
23+
}
24+
25+
impl Step for Bdwgc {
26+
type Output = PathBuf;
27+
const ONLY_HOSTS: bool = true;
28+
29+
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
30+
run.path("src/bdwgc")
31+
}
32+
33+
fn make_run(run: RunConfig<'_>) {
34+
run.builder.ensure(Bdwgc { target: run.target });
35+
}
36+
37+
fn run(self, builder: &Builder<'_>) -> PathBuf {
38+
builder.require_submodule("src/bdwgc", None);
39+
let target = self.target;
40+
let out_dir = builder.bdwgc_out(target);
41+
let libgc = libgc_built_path(&out_dir);
42+
if builder.config.dry_run() {
43+
return libgc;
44+
}
45+
46+
static STAMP_HASH_MEMO: OnceLock<String> = OnceLock::new();
47+
let smart_stamp_hash = STAMP_HASH_MEMO.get_or_init(|| {
48+
generate_smart_stamp_hash(
49+
builder,
50+
&builder.config.src.join("src/bdwgc"),
51+
builder.bdwgc_info.sha().unwrap_or_default(),
52+
)
53+
});
54+
55+
let stamp = BuildStamp::new(&out_dir).add_stamp(smart_stamp_hash);
56+
57+
trace!("checking build stamp to see if we need to rebuild BDWGC artifacts");
58+
if stamp.is_up_to_date() {
59+
trace!(?out_dir, "bdwgc build artifacts are up to date");
60+
if stamp.stamp().is_empty() {
61+
builder.info(
62+
"Could not determine the BDWGC submodule commit hash. \
63+
Assuming that an BDWGC rebuild is necessary.",
64+
);
65+
} else {
66+
builder.info(&format!(
67+
"To force BDWGC to rebuild, remove the file `{}`",
68+
stamp.path().display()
69+
));
70+
return libgc;
71+
}
72+
}
73+
74+
trace!(?target, "(re)building BDWGC artifacts");
75+
builder.info(&format!("Building BDWGC for {}", target));
76+
t!(stamp.remove());
77+
let _time = helpers::timeit(builder);
78+
t!(fs::create_dir_all(&out_dir));
79+
80+
builder.config.update_submodule(Path::new("src").join("bdwgc").to_str().unwrap());
81+
let mut cfg = cmake::Config::new(builder.src.join("src/bdwgc"));
82+
llvm::configure_cmake(builder, target, &mut cfg, true, llvm::LdFlags::default(), &[]);
83+
84+
let profile = match (builder.config.bdwgc_debug, builder.config.bdwgc_assertions) {
85+
(true, _) => "Debug",
86+
(false, false) => "Release",
87+
(false, true) => "RelWithDebInfo",
88+
};
89+
trace!(?profile);
90+
91+
let assertions = if builder.config.bdwgc_assertions { "ON" } else { "OFF" };
92+
let shared = if builder.config.bdwgc_link_shared { "ON" } else { "OFF" };
93+
94+
cfg.out_dir(&out_dir)
95+
.pic(true)
96+
.profile(profile)
97+
.define("BUILD_SHARED_LIBS", shared)
98+
.define("enable_parallel_mark", "OFF")
99+
.define("enable_gc_assertions", assertions)
100+
.cflag("-DGC_ALWAYS_MULTITHREADED");
101+
102+
cfg.build();
103+
104+
t!(stamp.write());
105+
libgc
106+
}
107+
}

src/bootstrap/src/core/build_steps/compile.rs

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use tracing::{instrument, span};
2121

2222
use crate::core::build_steps::gcc::{Gcc, add_cg_gcc_cargo_flags};
2323
use crate::core::build_steps::tool::{Bindgen, SourceType};
24-
use crate::core::build_steps::{dist, llvm};
24+
use crate::core::build_steps::{bdwgc, dist, llvm};
2525
use crate::core::builder;
2626
use crate::core::builder::{
2727
Builder, Cargo, Kind, PathSet, RunConfig, ShouldRun, Step, TaskPath, crate_description,
@@ -283,6 +283,8 @@ impl Step for Std {
283283
}
284284
cargo
285285
};
286+
let bindgen = builder.ensure(Bindgen { target });
287+
cargo.env("RUSTC_BINDGEN", &bindgen.tool_path);
286288

287289
// See src/bootstrap/synthetic_targets.rs
288290
if target.is_synthetic() {
@@ -292,7 +294,7 @@ impl Step for Std {
292294
cargo.rustflag(rustflag);
293295
}
294296

295-
let bindgen = builder.ensure(Bindgen { compiler, target });
297+
let bindgen = builder.ensure(Bindgen { target });
296298
cargo.env("RUSTC_BINDGEN", bindgen.tool_path);
297299

298300
let _guard = builder.msg(
@@ -333,6 +335,33 @@ fn copy_and_stamp(
333335
target_deps.push((target, dependency_type));
334336
}
335337

338+
fn copy_libgc(
339+
builder: &Builder<'_>,
340+
target: TargetSelection,
341+
libdir: &Path,
342+
) -> Vec<(PathBuf, DependencyType)> {
343+
let mut v = Vec::new();
344+
let install_dir = builder.ensure(bdwgc::Bdwgc { target });
345+
if !install_dir.exists() {
346+
return v;
347+
}
348+
for obj in fs::read_dir(install_dir).unwrap() {
349+
let p = obj.unwrap().path();
350+
if !p.file_name().unwrap().to_str().unwrap().starts_with("libgc") {
351+
continue;
352+
}
353+
if p.is_symlink() {
354+
builder.install(&t!(fs::canonicalize(&p)), &libdir, 0o644);
355+
let full_dest = libdir.join(p.file_name().unwrap());
356+
builder.copy_link(&p, &full_dest);
357+
} else {
358+
builder.install(&p, &libdir, 0o644);
359+
}
360+
v.push((p, DependencyType::Target));
361+
}
362+
v
363+
}
364+
336365
fn copy_llvm_libunwind(builder: &Builder<'_>, target: TargetSelection, libdir: &Path) -> PathBuf {
337366
let libunwind_path = builder.ensure(llvm::Libunwind { target });
338367
let libunwind_source = libunwind_path.join("libunwind.a");
@@ -368,6 +397,11 @@ fn copy_third_party_objects(
368397
target_deps.push((libunwind_path, DependencyType::Target));
369398
}
370399

400+
if builder.config.bdwgc_link_shared {
401+
let libgc_objs = copy_libgc(builder, target, &builder.rustc_libdir(*compiler));
402+
target_deps.extend(libgc_objs)
403+
}
404+
371405
target_deps
372406
}
373407

@@ -537,6 +571,8 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car
537571
cargo.env("MACOSX_DEPLOYMENT_TARGET", target);
538572
}
539573
}
574+
let bindgen = builder.ensure(Bindgen { target });
575+
cargo.env("RUSTC_BINDGEN", &bindgen.tool_path);
540576

541577
// Paths needed by `library/profiler_builtins/build.rs`.
542578
if let Some(path) = builder.config.profiler_path(target) {
@@ -549,6 +585,12 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car
549585
cargo.env("RUST_COMPILER_RT_FOR_PROFILER", compiler_rt);
550586
}
551587

588+
// Evenutally we stick libgc.so in the current compiler stage's sysroot where the linker will
589+
// find it. But first, we must explicitly link the build directory because of bootstrap
590+
// ordering: the first thing rust does is build library/std with stage 0 which doesn't yet know
591+
// about libgc.
592+
cargo.rustflag("-L").rustflag(builder.bdwgc_out(target).join("lib").to_str().unwrap());
593+
552594
// Determine if we're going to compile in optimized C intrinsics to
553595
// the `compiler-builtins` crate. These intrinsics live in LLVM's
554596
// `compiler-rt` repository.
@@ -1191,6 +1233,9 @@ pub fn rustc_cargo(
11911233
}
11921234
}
11931235

1236+
let bindgen = builder.ensure(Bindgen { target });
1237+
cargo.env("RUSTC_BINDGEN", &bindgen.tool_path);
1238+
11941239
// Building with protected visibility reduces the number of dynamic relocations needed, giving
11951240
// us a faster startup time. However GNU ld < 2.40 will error if we try to link a shared object
11961241
// with direct references to protected symbols, so for now we only use protected symbols if
@@ -1351,6 +1396,9 @@ pub fn rustc_cargo_env(
13511396
}
13521397
}
13531398

1399+
// Paths needed by `library/bdwgc/build.rs`.
1400+
let bindgen = builder.ensure(Bindgen { target });
1401+
cargo.env("RUSTC_BINDGEN", &bindgen.tool_path);
13541402
// Build jemalloc on AArch64 with support for page sizes up to 64K
13551403
// See: https://github.com/rust-lang/rust/pull/135081
13561404
if builder.config.jemalloc(target)

0 commit comments

Comments
 (0)