Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
status: open
kind: tooling
opened: 2026-09-29
---

# Every build still removes an in-tree LLVM that no build makes any more

`llvm::retire_in_tree` removes a bootstrap build directory's own `<host>/llvm`,
`<host>/lld`, `<host>/ci-llvm` and `cache/llvm-*`. It runs at four sites on
every build: the primary's `reassemble`, `compiler::place`, `compiler::choose`
on the way back to the primary's compiler, and the std build
(`sysroot::prepare_std_build`).

Since the LLVM store, no build makes any of these. Every compiler build links
the store's `llvm-config`, and the std build sets `download-ci-llvm = false`.
What the four sites remove is what a build directory kept from before the
store. After a checkout's first build at that code, they remove nothing, but
they keep asking, on every build, a `read_dir` of `cache/` and a `stat` of
each name.

Exit: delete `retire_in_tree`, `in_tree` and the four call sites once no
checkout that builds holds a build directory made before the store. A host
cannot know that for any other host, so the owner sets the date.
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
status: open
kind: tooling
opened: 2026-09-29
---

# The fork's bootstrap takes LLD from beside an external `llvm-config`, and no upstream pull request numbers it

`ToyOSOrg/rust` commit `d9f8a5ca8db` ("bootstrap: take LLD from beside an
external llvm-config that is Rust's LLVM") accepts `rust.lld = true` with an
external `llvm-config` for the host when that `llvm-config` has
`llvm-has-rust-patches = true` and an `lld` sits in its `bin/`, and takes that
`lld` as `rust-lld`; before it, bootstrap refused the combination. Every
compiler build ToyOS runs relies on it (`src/llvm.rs`).

It is a configuration change, which upstream records in
`src/bootstrap/src/utils/change_tracker.rs` under the number of the pull
request that makes it. No such pull request exists, because none is sent for
now, so the fork carries no entry (`src/forkcheck.rs`).

Exit: an upstream pull request carries the change with its `change_tracker`
entry, and the fork takes it from there.
7 changes: 4 additions & 3 deletions issues/build/python-and-cc-are-declared.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,10 @@ Python search list (`src/main.rs:18`, `:28`). The expensive half is untouched.
**CMake and Ninja joined the list on 2026-09-27, by the owner's ruling**: rustc's
LLVM is built from source, from `ToyOSOrg/llvm-project`, with clang beside it,
and rustc's bootstrap builds LLVM with CMake driving Ninja. Both are declared
where the others are — `ALSO_USED` in `src/main.rs`, because a build whose
LLVM commit this host has already built runs neither — and in the README's
Prerequisites. On macOS they come from Homebrew (`brew install cmake ninja`),
where the others are — CMake in `REQUIRED` in `src/main.rs`, because every
build keys the host's LLVM on `cmake --version` (`src/llvm.rs`), and Ninja in
`ALSO_USED`, because a build whose LLVM this host has already built runs it
not — and in the README's Prerequisites. On macOS they come from Homebrew (`brew install cmake ninja`),
with no workaround; on the nightly's toolchain runner at the versions
`.github/workflows/nightly.yml` pins from Ubuntu 24.04's archive (`cmake
3.28.3-1build7`, `ninja-build 1.11.1-2`); the two portability jobs install
Expand Down
20 changes: 13 additions & 7 deletions src/buildlock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,11 @@
//!
//! **The lock order is a constraint, not a preference:** a compiler
//! key's lock → a sysroot key's lock → the worktree build lock → the global one
//! → artifact. A key's lock is taken with the worktree lock put down
//! ([`Held::without_shared`]), because the key's builder takes the worktree lock
//! exclusively.
//! → an LLVM key's lock → artifact. A compiler's or a sysroot's key lock is
//! taken with the worktree lock put down ([`Held::without_shared`]), because the
//! key's builder takes the worktree lock exclusively; an LLVM key's is taken
//! inside the worktree or global lock covering the fork build directory its
//! builder writes.
//!
//! Holder death: `flock` is released by the kernel when the open file
//! description closes, so a builder that is SIGKILLed mid-phase — routine here
Expand Down Expand Up @@ -239,26 +241,30 @@ fn integration_path(root: &Path) -> PathBuf {
git_lock_dir(root).join("integration")
}

/// A content-addressed product of the host, locked per key: a sysroot, or a
/// compiler a worktree's fork checkout names (`src/compiler.rs`).
/// A content-addressed product of the host, locked per key: a sysroot, a
/// compiler a worktree's fork checkout names (`src/compiler.rs`), or the LLVM
/// a compiler links (`src/llvm.rs`).
#[derive(Clone, Copy)]
pub enum Keyed {
Sysroot,
Compiler,
Llvm,
}

impl Keyed {
fn dir(self) -> &'static str {
match self {
Keyed::Sysroot => "sysroots",
Keyed::Compiler => "compilers",
Keyed::Llvm => "llvm",
}
}

fn name(self) -> &'static str {
pub(crate) fn name(self) -> &'static str {
match self {
Keyed::Sysroot => "sysroot",
Keyed::Compiler => "compiler",
Keyed::Llvm => "LLVM",
}
}
}
Expand Down Expand Up @@ -673,7 +679,7 @@ pub(crate) mod tests {
}

/// This test binary, to run the one `#[ignore]`d test `test` names.
fn rerun(test: &str) -> Command {
pub(crate) fn rerun(test: &str) -> Command {
let mut rerun = Command::new(std::env::current_exe().unwrap());
rerun.args(["--exact", test, "--include-ignored", "--nocapture"]);
rerun
Expand Down
10 changes: 5 additions & 5 deletions src/clang.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,9 +149,9 @@ fn resource_version(llvm: &Path) -> PathBuf {
}
}

/// Give `stage2` the C toolchain of the LLVM bootstrap installed beside it.
pub(crate) fn provision(stage2: &Path) {
let llvm = &stage2.parent().expect("stage2 is under a build directory").join("llvm");
/// Give `stage2` the C toolchain of the LLVM at `llvm` (`src/llvm.rs`), the one
/// its rustc links.
pub(crate) fn provision(stage2: &Path, llvm: &Path) {
let bin = bin(stage2);
let from = llvm.join("bin/clang");
let to = bin.join("clang");
Expand Down Expand Up @@ -208,7 +208,7 @@ mod tests {
let said = refused.downcast_ref::<String>().expect("a formatted refusal");
assert!(said.contains("clang") && said.contains("ld.lld") && said.contains("include"), "{said}");

provision(&stage2);
provision(&stage2, &llvm);
assert_eq!(defect(&stage2), None);
assert_eq!(fs::read_to_string(bin(&stage2).join("clang")).unwrap(), "the clang");
assert!(!fs::symlink_metadata(bin(&stage2).join("clang")).unwrap().file_type().is_symlink(), "clang is a copy, not the link");
Expand All @@ -221,7 +221,7 @@ mod tests {
// Provisioning again, from another LLVM, replaces what was there.
fs::remove_dir_all(llvm.join("lib/clang/22")).unwrap();
write(&llvm.join("lib/clang/23/include/stddef.h"), "v23");
provision(&stage2);
provision(&stage2, &llvm);
assert!(!resource_parent(&stage2).join("22").exists(), "the old headers stayed beside the new");
assert_eq!(fs::read_to_string(resource_parent(&stage2).join("23/include/stddef.h")).unwrap(), "v23");

Expand Down
Loading
Loading