Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
9193ce8
A C++ runtime for ToyOS: libc++, libc++abi and libunwind in every C s…
Japabu Sep 30, 2026
715cce8
libc's arch module names what its long double readers widen by C name
Japabu Sep 30, 2026
691e993
Merge origin/main (#616, #625) into wt/toyos-libcxx
Japabu Sep 30, 2026
679890c
Merge origin/main (#632, #536) into wt/toyos-libcxx
Japabu Sep 30, 2026
e9feb8a
libc: no thread handle before its tid, EPERM from a condition wait, o…
Japabu Sep 30, 2026
9dc8e5c
cxx_runtime: the concurrency, exit and printf claims each get a line …
Japabu Sep 30, 2026
bed5d0a
build: the runtimes' sources are their commit's; CMake, Ninja and Pyt…
Japabu Sep 30, 2026
68b0faa
libc: strtonum passes clippy's adopted lints, which now reach it thro…
Japabu Sep 30, 2026
1c03875
Merge remote-tracking branch 'origin/main' into wt/toyos-libcxx
Japabu Sep 30, 2026
26a4bfb
tests: cxx_runtime's lines are not all the host's
Japabu Sep 30, 2026
df98e4d
Merge remote-tracking branch 'origin/main' into wt/toyos-libcxx
Japabu Sep 30, 2026
355525a
build: the C++ runtime builds under n2, from its pinned commit
Japabu Sep 30, 2026
9f0297a
issues: the runtime takes no Ninja; config.guess's shell and the runt…
Japabu Sep 30, 2026
1a747af
tests: cxx_runtime's ceiling is c_hello's, and its lines claim no ord…
Japabu Sep 30, 2026
888e3f2
Merge origin/main (#617) into wt/toyos-libcxx
Japabu Sep 30, 2026
3f5d0f5
build: n2 is installed as its README directs, and a std build asks fo…
Japabu Sep 30, 2026
7d75fe1
issues: the Ninja row is main's again, and config.guess's tools are j…
Japabu Sep 30, 2026
b46413b
build: n2 is installed once, in a directory its whole install names
Japabu Sep 30, 2026
7d44860
Carry #644's issue that a Rust std binary cannot link the C++ runtime
Japabu Sep 30, 2026
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
2 changes: 1 addition & 1 deletion .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ jobs:
fetch-depth: 0

# CMake and Ninja are what bootstrap builds LLVM and clang with, pinned to
# the versions Ubuntu 24.04 released (src/main.rs's `ALSO_USED`).
# the versions Ubuntu 24.04 released.
- name: disk, QEMU, CMake and Ninja
run: |
sudo rm -rf /usr/local/lib/android /usr/share/dotnet /opt/ghc \
Expand Down
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,8 +240,7 @@ ninja`); on Debian and Ubuntu they are `build-essential`, `python3`, `cmake`
and `ninja-build`.

`cargo run` names anything it needs and cannot find, before it does anything
else — including the Python that only the toolchain bootstrap runs, which
costs that bootstrap rather than the build.
else.
Everything this project depends on that it did not write is named
where it is carried: `NOTICE` lists every committed third-party file with its
hash, upstream and licence.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
status: open
kind: defect
opened: 2026-09-30
---

# A Finder file in a store directory panics its sweep

`keystore::sweep_by` takes every entry of a store directory as `<key>` or
`<key>.<suffix>`, so a `.DS_Store` the macOS Finder writes there names the key
`""`, and `buildlock::keyed_idle` then opens the lock directory itself:
`build lock: open <primary>/.git/toyos-build-locks/llvm/: Is a directory (os
error 21)`. It happened after an LLVM placement, whose product was whole, so
the next build went on; the sweep had removed nothing.

**Exit**: a sweep passes over a store entry that names no key, with a test.
27 changes: 27 additions & 0 deletions issues/build/a-rust-std-binary-cannot-link-the-cxx-runtime.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
status: open
kind: defect
opened: 2026-09-30
---

# A Rust std binary cannot link the C++ runtime

LLVM is C++, so a rustc that carries it links the C++ runtime into
`librustc_driver.so` beside std. The runtime #637 builds into the C sysroot,
`lib/libc++.a` (sysroot `de0de8ee7862147a`), does not link there. Linking
rustc's LLVM wrapper (`compiler/rustc_llvm/llvm-wrapper`, whole), the 71 LLVM
archives rustc links, `libc++.a` and the Rust sysroot's archives with `ld.lld
-shared` gives:

- **Two unwinders.** `libc++.a` carries LLVM's libunwind
(`LIBCXXABI_ENABLE_STATIC_UNWINDER`) and std carries the `unwinding` crate,
and both define the Itanium `_Unwind_*` interface: 17 duplicate symbols,
`_Unwind_Resume` among them, at libunwind's `UnwindLevel1.c` and at
`unwinding`'s `src/unwinder/mod.rs:346`.
- **Local-exec thread-locals.** libc++abi's `eh_globals` is reached through
`R_X86_64_TPOFF32`, twice `cannot be used with -shared`: the runtime is
compiled as position-independent executable code, not for a shared object.

**Exit**: a Rust std shared object and a Rust std executable each link the C++
runtime with one unwinder and no relocation error, and a guest case runs a Rust
std program in which C++ code throws and catches an exception.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ opened: 2026-09-27

# libc's C headers are written by hand, and nothing holds them to its definitions

`userland/libc/include/` is 32 headers typed beside the Rust that defines what
`userland/libc/include/` is headers typed beside the Rust that defines what
they declare, and no build or test compares the two. clang, compiling
doomgeneric for the first time, found two places they had already parted:

Expand All @@ -20,8 +20,7 @@ doomgeneric for the first time, found two places they had already parted:
Both are fixed in the headers. The class is not: a signature changed in
`userland/libc/src` changes no header, and the C sysroot
ships whatever the headers say. The corpus shows the
surface is also incomplete — `stdint.h` has no `least`/`fast` types, so clang's
own `stdatomic.h` does not compile (`124_atomic_counter`), and `pthread.h` and
surface is also incomplete — `pthread.h` and
`signal.h` stop short of `PTHREAD_PROCESS_SHARED` and `SIGUSR1`.

**Generating them with cbindgen was priced and not taken**: it is a new
Expand Down

This file was deleted.

This file was deleted.

15 changes: 15 additions & 0 deletions issues/build/libcxx-is-built-without-std-filesystem.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
status: open
kind: defect
opened: 2026-09-30
---

# libc++ for ToyOS is built without `std::filesystem`

`src/libcxx.rs` configures the C++ runtime with `LIBCXX_ENABLE_FILESYSTEM=OFF`,
so a ToyOS C++ program that includes `<filesystem>` does not compile. libc++'s
filesystem is written on the POSIX directory, `stat` and path calls, and libc
has no `dirent.h`.

**Exit**: libc carries what libc++'s `src/filesystem` calls, the option goes,
and a guest test lists a directory through `std::filesystem`.
23 changes: 23 additions & 0 deletions issues/build/libcxx-takes-the-generic-locale-path-on-toyos.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
status: open
kind: defect
opened: 2026-09-30
---

# libc++ takes its generic locale path on ToyOS

`libcxx/include/__locale_dir/locale_base_api.h` in `ToyOSOrg/llvm-project`
sends ToyOS down its fallback arm, the one it marks temporary: libc++ reaches
the locale through global `_l` names and `bsd_locale_fallbacks.h`, which is why
libc's `locale.rs` carries every `_l` function libc++ calls. Upstream moves
each platform to a header of its own under `__locale_dir/support/`, and a new
platform is asked for one.

ToyOS's is Fuchsia's shape: one C locale, `uselocale` around the calls that
read it, and `support/no_locale/`'s characters and number readers.

**Exit**: `__locale_dir/support/toyos.h`, its `__toyos__` arm in
`locale_base_api.h`, and its entries in `libcxx/include/CMakeLists.txt` and
the module map, in the fork; libc's `_l` functions that only the fallback
called go. It moves the LLVM key, so every host builds LLVM again: it rides
with the next change to the fork's `src/llvm-project`.
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@ arrives and is not one. M4 and M5 are stages of `issues/build/toyos-builds-itsel

| tool | runs | verdict | exit |
|---|---|---|---|
| Python | LLVM's CMake, whenever this host builds an LLVM (`src/llvm.rs`) | admitted: no Rust tool does the job, LLVM's CMake requires one (`find_package(Python3 … REQUIRED)` in `rust/src/llvm-project/llvm/CMakeLists.txt`) | M5 runs it in the guest |
| CMake | rustc's bootstrap, for LLVM and clang; `src/llvm.rs`, for the LLVM's key | admitted: no Rust tool does the job, LLVM, clang and LLD are described in CMake, and upstream's only other descriptions are a GN overlay it does not support and a Bazel one | M5 runs it in the guest |
| Python | LLVM's CMake, whenever this host builds an LLVM (`src/llvm.rs`); the C++ runtime's CMake, in every sysroot build (`src/libcxx.rs`), and its build, which runs `libcxx/utils/generate_iwyu_mapping.py` for a header it installs | admitted: no Rust tool does the job, LLVM's CMake requires one (`find_package(Python3 … REQUIRED)` in `rust/src/llvm-project/llvm/CMakeLists.txt`), and so does the runtimes', unconditionally (`runtimes/CMakeLists.txt`): configured as `src/libcxx.rs` does with no Python on `PATH` or in CMake's search, it found none and stopped, exit 1, and with only `python3` added it configured, exit 0 | M5 runs it in the guest |
| CMake | rustc's bootstrap, for LLVM and clang; `src/llvm.rs`, for the LLVM's key; `src/libcxx.rs`, for the C++ runtime in every sysroot build | admitted: no Rust tool does the job, LLVM, clang and LLD are described in CMake, and upstream's only other descriptions are a GN overlay it does not support and a Bazel one | M5 runs it in the guest |
| Ninja | runs the build CMake generates for LLVM | refused: a Rust tool does it, n2 (`github.com/evmar/n2` at `b1fead5`), named `ninja` as its README directs for CMake: CMake's Ninja generator configured `rust/src/llvm-project/llvm` for it and it built `llvm-tblgen`, exit 0 each; named `n2`, CMake refuses its version, exit 1 | rustc's bootstrap builds LLVM under n2 |
| `sh` running LLVM's `config.guess`, and the POSIX tools and `cc` it runs | LLVM's CMake, whenever this host builds an LLVM, and the C++ runtime's, in every sysroot build, ask it the host's triple, unconditionally (`get_host_triple` in `rust/src/llvm-project/llvm/cmake/modules/GetHostTriple.cmake`, which runs `sh` by name) | refused: a Rust tool does the shell's part, brush 0.4.0: on the development host (macOS, arm64) `config.guess` printed `/bin/sh`'s triple under it, `arm64-apple-darwin27.0.0`, exit 0 each. The script runs `sed`, `uname`, `mktemp`, `grep`, `rm`, `rmdir` and `cc` there under either shell, and that `cc` is the `cc` rows'. Five of the other six are refused, uutils' doing each: under brush with sed 0.2.0, grep 0.2.0 and coreutils 0.12.0's `mktemp`, `rm` and `rmdir`, and nothing else on `PATH` but the host's `uname` and `cc`, it printed that triple, exit 0. `uname` is admitted: coreutils 0.12.0's answers `-p` with `unknown` where macOS's answers `arm`, and `config.guess` reads that as PowerPC, `powerpc-apple-darwin27.0.0`, exit 0 | CMake finds brush as its `sh`, uutils' `sed`, `grep`, `mktemp`, `rm` and `rmdir`, and a Rust `uname` that answers `-p` as the host's does; or M5 runs it in the guest |
| `git` for worktrees, submodules, checkouts, fixtures and rustc's bootstrap | adds, removes and prunes worktrees (`src/worktree.rs`, `src/sysroot.rs`); updates submodules (`src/lib.rs`, `src/sysroot.rs`, `src/licence.rs`, `src/release.rs`); fetches the fork from the primary's and checks it out (`src/sysroot.rs`); fast-forwards the primary (`src/sync.rs`); makes the tests' fixture repositories; runs inside rustc's bootstrap | admitted: no Rust tool does the job, gitoxide 0.85 adds, removes and prunes no worktree, updates no submodule, stages, resets and pushes nothing, checks out only a fresh clone and fetches a local path by spawning `git`; a fixture must be what `git` makes, and bootstrap runs `git` itself | M4 runs it in the guest |
| `git` for reads, a config write, and clones and fetches over HTTPS | `rev-parse`, `show-ref`, `for-each-ref`, `rev-list`, `log`, `branch --contains`, `merge-base`, `ls-tree`, `ls-files`, `cat-file`, `config --get-regexp`, `worktree list`, `status`, `diff`, `ls-remote` and `grep`, in the build system and its tests; `config --global --add safe.directory` in the nightly's containers; `src/sync.rs`'s fetch of `origin`; every workflow's checkout | refused: a Rust tool does it, gitoxide 0.85, which reads refs, objects, the index, config, worktrees and status, adds a value to a config file and writes it (gix-config 0.58's `File::section_mut_or_create_new`, `SectionMut::push`, `File::write_to`), walks history, diffs, and lists, fetches and clones a remote over HTTPS; `grep` is a search of the files its index names | those are gitoxide's |
| `git` for reads, a config write, a commit's paths written out, and clones and fetches over HTTPS | `rev-parse`, `show-ref`, `for-each-ref`, `rev-list`, `log`, `branch --contains`, `merge-base`, `ls-tree`, `ls-files`, `cat-file`, `config --get-regexp`, `worktree list`, `status`, `diff`, `ls-remote` and `grep`, in the build system and its tests; `config --global --add safe.directory` in the nightly's containers; `checkout <commit> -- <paths>` through an index of its own, which writes the C++ runtime's sources out of the LLVM commit into the stored LLVM (`src/llvm.rs`); `src/sync.rs`'s fetch of `origin`; every workflow's checkout | refused: a Rust tool does it, gitoxide 0.85, which reads refs, objects, the index, config, worktrees and status, adds a value to a config file and writes it (gix-config 0.58's `File::section_mut_or_create_new`, `SectionMut::push`, `File::write_to`), walks history, diffs, and lists, fetches and clones a remote over HTTPS; `grep` is a search of the files its index names; and gitoxide's CLI 0.59 (gix 0.88) wrote the runtimes' sources of LLVM `849da7d6` into an empty directory, each path's tree through `gix rev parse`, `gix index from-tree` and `gix free index checkout-exclusive`, exit 0 each: the 18759 files `git` writes there, byte for byte and mode for mode | those are gitoxide's |
| `cc`, `c++` and `ar` on a Linux host, `build-essential` on the nightly's runners | rustc links every host binary through `cc`; `cc` and `c++` compile LLVM, clang, LLD and `rustc_llvm` (`src/llvm.rs` names both to bootstrap) and `ring`'s C for `tests/https-server-host` and `tests/https-fetch-host`; `ar` archives what `cc::Build` compiles | admitted: no Rust tool compiles C or C++, or takes rustc's host link | M5: no host in the loop |
| the toolchain's own `clang`, `llvm-ar`, `rust-lld` and `llvm-config`, built from `ToyOSOrg/llvm-project` | rustc links every guest binary with `rust-lld`; `clang` compiles the C corpus and `hello.c` (`tests/common/compile.rs`, `tests/common/clang.rs`) and, with `llvm-ar`, doomgeneric through `cc::Build` (`src/clang.rs`); rustc's bootstrap asks `llvm-config` how to link LLVM | admitted: our fork's C++, which ToyOS can one day build and run; no Rust tool compiles C, `cc::Build` archives with an `ar`, bootstrap reads LLVM through `llvm-config`, and `CLAUDE.md` links everything with `rust-lld` | M5: no host in the loop |
| `ovmf-generic` | the UEFI firmware of the nightly's guest containers (`src/firmware.rs`), packaged by Debian apart from QEMU | admitted: QEMU's own firmware, and no Rust firmware does its job | the instrument's QEMU carries its own firmware |
Expand Down
25 changes: 25 additions & 0 deletions issues/build/the-cxx-runtime-is-rebuilt-with-every-sysroot.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
status: open
kind: tooling
opened: 2026-09-30
---

# The C++ runtime is rebuilt with every sysroot

`src/sysroot.rs` builds each target's libc++, libc++abi and libunwind into the
C sysroot after libc, so every change the sysroot key sees, an edit to
`toyos-abi/src`, `toyos/src` or libc's `src/` among them, configures and
builds both targets' runtimes again.

The runtime is a function of the LLVM key, libc's `include/` and
`src/libcxx.rs` only if no configure probe links: the runtimes' `try_compile`
builds an executable by default, which links `CMAKE_SYSROOT`'s
`libtoyos_c.a`, so today libc's archive decides probe answers too.
`CMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY` stops the link, but a probe
that only a link answers (`check_function_exists`, `check_library_exists`)
then answers yes for anything: its configure's results are owed a comparison
against today's before it is set.

**Exit**: with the probes shown not to need a link, the runtime is a store
product of its own, keyed on the LLVM key, libc's `include/` and
`src/libcxx.rs`, and a sysroot build takes it (the store is #629's).
20 changes: 20 additions & 0 deletions issues/build/the-cxx-runtime-names-toyos-to-cmake-as-unix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
status: open
kind: defect
opened: 2026-09-30
---

# The C++ runtime's configure names ToyOS to CMake as `UNIX`

CMake has no platform module for ToyOS, so `src/libcxx.rs` configures the
runtimes with `CMAKE_SYSTEM_NAME=ToyOS` and sets `UNIX=ON` beside it: the one
fact a platform module would give that the runtimes' build branches on. CMake
says so on every configure, once per check it runs: `System is unknown to
cmake, create: Platform/ToyOS to use this system`. Everything else a platform
module sets (library prefixes and suffixes, search paths, the shared-library
flags) CMake leaves at its defaults, which the runtimes' static-only build
happens not to read.

**Exit**: CMake knows ToyOS, a `Modules/Platform/ToyOS.cmake` that sets what
its Unix-like neighbours set, and `UNIX=ON` goes from `src/libcxx.rs` with the
line every configure prints.
15 changes: 3 additions & 12 deletions issues/build/toyos-builds-itself.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,14 @@ with lld, one build of one fork, `ToyOSOrg/llvm-project`. The C
library stays `userland/libc`, ours. Each stage lands on x86-64 first and on
AArch64 one step behind, on `issues/kernel/toyos-runs-on-arm64.md`'s track.

- **M1 — clang cross-built, toyos-cc gone.** The host builds LLVM, clang and
lld from the fork as part of the toolchain; a C program compiled by that
clang against libc's C sysroot runs in QEMU, doomgeneric is built by it, and
toyos-cc is deleted. *Exit*: `c_hello`, `doom_frames` and the C corpus green
on clang, and toyos-cc's crate, tests and image row gone. Left for AArch64: clang's driver knows `aarch64-unknown-toyos`,
an AArch64 userland build makes its C sysroot and doomgeneric compiles
against it; no AArch64 C program has been linked and run.
- **M2 — clang and lld as a package inside ToyOS; toyos-ld gone.** clang, lld
and their runtime built *for* ToyOS on the host and installed by
`/system/bin/pkg`; `clang hello.c && ./a.out` works in the guest. *Exit*:
the in-guest compile-and-run test passes, and toyos-ld — today the only
linker a ToyOS process can run — is deleted with its crate, its
`[programs]` row and its tests.
- **M3 — libc++, and an LLVM-backed rustc inside ToyOS.** libc++, libc++abi
and libunwind for ToyOS; a C++ program with exceptions and threads runs; the
hosted rustc carries LLVM instead of Cranelift. *Exit*: that C++ test, and a
- **M3 — an LLVM-backed rustc inside ToyOS.** The
hosted rustc carries LLVM instead of Cranelift. *Exit*: a
Rust program compiled and run inside ToyOS by the hosted rustc.
- **M4 — ToyOS builds ToyOS byte-identical to the host.** cargo, rustc and
clang in the guest build a userland program and then the kernel, and the
Expand All @@ -47,8 +39,7 @@ and the network stack under it (`issues/hardware/the-lan-is-not-yet-production-g
gigabyte of toolchain, and threads and `mmap` mature enough for LLVM
(`issues/kernel/std-and-libc-drop-the-answer-thread-join-gives.md`).
M2 and M4 also need libc to start a child process
(`issues/kernel/a-childs-end-is-an-event-and-a-parent-takes-its-children-down.md`). M3 needs
locale support or libc++'s no-localization build. M4 needs git in the guest, storage durable and fast
(`issues/kernel/a-childs-end-is-an-event-and-a-parent-takes-its-children-down.md`). M4 needs git in the guest, storage durable and fast
enough for an LLVM build tree
(`issues/filesystem/storage-is-layers-and-a-role-is-a-filesystem.md`), and
memory beyond what 2 MiB process pages allow
Expand Down
2 changes: 1 addition & 1 deletion rust
Submodule rust updated 1 files
+1 −1 src/llvm-project
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ pub mod kernelkeys;
pub mod keystore;
pub mod lan;
pub mod libc;
pub mod libcxx;
pub mod llvm;
pub mod licence;
pub mod metal;
Expand Down
Loading
Loading