libycxx is a new implementation of the whole C++26 standard library for the latest GCC and Clang, with its own Itanium C++ ABI runtime. It is written from the working draft, not from anyone else’s code, and tested against the standard rather than against itself.
An existing project that knows nothing about libycxx: pass -DCMAKE_TOOLCHAIN_FILE=/opt/libycxx/lib/cmake/libycxx/toolchain.cmake (Getting started).
C++26every headerthe C++26 library, freestanding and hosted
2,824own testsspec-derived, all passing in CI on Linux and macOS
17,098external testslibc++ and libstdc++ suites, run unmodified
19real-world projectsbuilt and tested against libycxx, linkage proved
01
What it is
A standard library that a program selects explicitly, in place of the
toolchain’s libstdc++ or libc++, for the latest GCC and Clang on Linux and macOS.
libycxx is layered. A freestanding core needs no operating system, no C
library and no heap unless one is supplied. The hosted library adds everything
that needs the environment — streams, files, threads, clocks, locales — and reaches the system
only through a small C-linkage platform abstraction layer. Underneath sits
libycxx’s own Itanium C++ ABI runtime, so a program built with it depends on
neither libsupc++ nor libc++abi.
Every header of the C++26 library is provided, with the deprecated features
the draft still specifies (Annex D, marked [[deprecated]]) and without
the ones it has removed.
Language support & utilities
<type_traits>, <expected>, <optional>, <variant>, the function wrappers including function_ref, indirect and polymorphic, constexpr exceptions on GCC.
Containers & ranges
Every container, constexpr, including <hive>, <inplace_vector>, <flat_map> and <mdspan>; every range factory and adaptor; every std:: and ranges:: algorithm.
Text
<format> and <print> in full, <charconv> with shortest round-trip floating point, <regex> with all six grammars, <text_encoding> with the IANA registry.
Numerics
<random> with philox_engine and all 20 distributions, <simd>, <linalg>, <cmath>, <complex>, <valarray>.
Time
<chrono> in full: the calendar, utc/tai/gps clocks with leap seconds, the time zone database on the system’s zoneinfo, every formatter and parser.
Concurrency
Threads, atomics, latches, barriers and semaphores, <rcu>, <hazard_pointer>, and senders and receivers in <execution> with parallel_scheduler.
I/O & locales
Iostreams, <spanstream>, <syncstream>, <filesystem>, every standard facet, and named locales from the C library.
Diagnostics
<stacktrace> with ELF/DWARF symbolization and its own demangler, <debugging>, <contracts> and <meta> (reflection) where GCC supports them.
Freestanding, hosted and modules
Every core header, every header with a freestanding subset and every header of the
draft’s freestanding table compiles with -ffreestanding-nostdlib-nostdinc-fno-exceptions-fno-rtti; a smoke test links for x86_64-unknown-none-elf and
riscv64-unknown-elf. An optional runtime archive, ycxx::freestanding,
supplies allocation, floating-point <charconv> and the atomic wait tables to
programs without an operating system.
The standard library modules std and std.compat are generated from
the headers and built per project with the project’s own flags, from CMake
(ycxx::modules) or with tools/ycxx-modules.
Audited against the draft
Three audits walk the synopses of the working draft and generate a check for every
declaration, on both compilers (docs/SPEC_COVERAGE.md):
Text, numerics, time, I/O, threads, execution, Annex D
6,367
13,237
What remains open is compiler-blocked: Clang 23 has no reflection or
contracts and cannot throw during constant evaluation; GCC 16 lacks
is_within_lifetime.
03
How it is built
A handful of rules, written down in DECISIONS.md with their reasons
and the alternatives that were rejected.
Clean room
Written from the C++ working draft, WG21 papers, POSIX and the published Itanium C++ ABI —
never from the source or headers of another standard library or C++ runtime. The libc++ and
libstdc++ test suites are run as oracles, never copied into the repository and never edited.
Hidden namespaces and reserved names
Standard entities are declared directly in std; details live in
ycxx::detail, and the bases of standard types in ycxx::adl_free, a
namespace with no functions, so argument-dependent lookup never reaches the internals. Every
name the headers use for themselves is a reserved identifier: a program may
#define any name the standard does not declare, which a test with 5,874 such
macros checks. Every namespace block carries hidden visibility, so a program or shared object
exports nothing of libycxx and another C++ runtime in the process — Apple’s libc++abi, say —
keeps its own.
Strict preprocessor policy
One file, config.hpp, inspects compiler and target macros and turns each answer
into a constexpr value or a type; the library then uses if constexpr,
requires and templates. It defines no function-like macros, and facts about the
target are probed against the real toolchain at configure time, not written down.
Platform layer and hosted layers
The hosted library reaches the system through the C primitives of
ycxx/pal.h, implemented on POSIX by default. They are grouped into layers —
memory, console, clock, threads,
random, files, environment, debug,
clib — that an integrator can provide one by one. Containers, exceptions and
std::print then run over a heap and a serial port, as in the bare-metal x86_64
example booted by Limine in QEMU. A feature whose layer is absent fails to compile or link,
naming the layer, never silently at run time.
Its own ABI runtime
libycxx-abi.a implements exception allocation, throw, catch and rethrow, the
personality routine and LSDA parsing, type_info and the RTTI classes,
__dynamic_cast, static-local guards, terminate and new handlers and the reference
counting exception_ptr needs, from the Itanium C++ ABI documents. Only stack
unwinding comes from the toolchain’s unwinder.
Named locales on the C library
std::locale("de_DE.UTF-8") accepts every name the C library’s
newlocale accepts, on glibc and Darwin’s libc. Each named category holds
_byname facets for char and wchar_t built on one shared
locale_t, using the _l functions per call; the global C locale and
other threads are never touched.
Deliberate divergences
Where the draft and the established libraries disagree, libycxx follows the draft and says
so; where the letter of the draft would break portable code, it follows practice and says
that too. The full list is in STATUS.md (“Deliberate divergences”):
to_chars without a precision follows P3505 and the draft’s “smallest number
of characters”, where older tests encode the C++17 rule.
Floating-point from_chars leaves the value unmodified on
result_out_of_range, as the draft says.
<regex>’s ECMAScript grammar follows ECMA-262 (\a is an
identity escape; a back-reference may precede its group).
regex_traits::transform_primary in the classic locale returns the whole sort
key, so [[=a=]] keeps working there, as portable code expects.
expected’s operator== with a value deduces its left operand, to
avoid a constraint recursion the literal signature causes.
04
How it is tested
Against the specification, by several independent oracles, in every
configuration a user can select — and every run explains itself.
Its own suite, written from the draft
2,824 tests in tests/ycxx, written by an author who may read only the
working draft and cppreference — never libc++’s or libstdc++’s tests, nor any
implementation, libycxx’s included. A failing test is a library bug until the draft shows
otherwise; tests are never weakened to fit. Tests that must not compile name the diagnostic
they expect, and hardened preconditions have death tests. Running the suite against libstdc++
validates the tests themselves: every difference is listed and triaged.
Own suite on Linux (pass / fail / expected failure): default from CI, 2026-10-07; the others as recorded in STATUS.md, 2026-10-05/06
Configuration
GCC 16.2
Clang 23.1
Default
2,723 / 0 / 15
2,698 / 0 / 40
Hardened (YCXX_HARDENED=1)
2,425 / 0 / 13
2,418 / 0 / 20
No exceptions (-fno-exceptions)
1,941 / 0 / 7
1,941 / 0 / 7
AddressSanitizer
—
2,685 / 0 / 39
ThreadSanitizer
2,722 / 0 / 15
2,695 / 0 / 39
libc++ and libstdc++ conformance suites
Both suites run unmodified from pinned releases (LLVM 23.1.2’s libcxx/test/std,
GCC 16.2.0’s libstdc++ testsuite), fetched on demand and never vendored.
Full runs of 2026-10-05/06 (pass / fail / unsupported)
Suite
GCC 16.2
Clang 23.1
libc++ (8,543 tests)
7,494 / 211 / 836
7,495 / 215 / 832
libstdc++ (8,555 tests)
6,206 / 13 / 2,335
6,161 / 13 / 2,344*
Every failure is categorised in tests/libcxx/TRIAGE.md and
tests/libstdcxx/TRIAGE.md. Most are tests that rely on headers libstdc++ and libc++
include from one another, on their own specifics or pre-C++26 values, or on not running as root.
Skipped tests carry a category and a reason and name the libycxx test that covers the subject.
*Projected from the full run with the final lists.
Sanitizers, hardening and library modes
All three suites run under AddressSanitizer, UndefinedBehaviorSanitizer and
ThreadSanitizer, linked with a libycxx built with the same sanitizers — an uninstrumented
library would hide every hand-off through its own mutexes and reference counts. The own suite
also runs hardened, with -fno-exceptions and at -O2, each with its own
report.
Nineteen real-world projects
tools/realworld builds open-source projects against libycxx with both compilers
and runs their own test suites; then it proves the build was libycxx’s alone: every
translation unit’s command, every object’s headers, every image’s needed libraries and
symbols, and libycxx’s allocation table in every image. A self-test built with the toolchain’s
library is rejected on every count.
Runs of 2026-10-07: every project built and passed with both compilers (CTest tests passed, GCC / Clang)
Project
Release
GCC
Clang
GoogleTest
v1.18.0
63
63
Abseil
20260817.0
242
242
Google Benchmark
v1.9.5
83
83
Catch2
v3.16.0
81
81
CLI11
v2.7.2
82
82
doctest
v2.5.3
191
191
EnTT
v4.0.0
15
15
{fmt}
12.2.0
21
21
glaze
v9.0.0
145
140
Microsoft GSL
v5.0.1
15
15
nlohmann/json
v3.12.0
101
101
libcoro
v0.16.0
1†
1†
magic_enum
v0.9.8
12 + 3 xfail
15
oneTBB
v2023.1.0
141
141
range-v3
0.12.0
234
236
simdjson
v5.0.2
153
153
spdlog
v1.17.0
1†
1†
Taskflow
v4.1.0
2,909
2,909
yaml-cpp
0.8.0
1†
1†
†One CTest test runs the project’s whole suite. All 19 also pass under
AddressSanitizer, and five under ThreadSanitizer; neither reported anything in libycxx. The
projects found three libycxx bugs (each fixed with a test) and four compiler bugs; their patches
are to their own non-standard code, each with a category and reason.
Continuous integration, without baselines
Every push runs the policy checks, both library builds, the freestanding check, the CMake
package test and the own suite on Linux (the gcc:16 container,
Clang 23 from apt.llvm.org) and macOS (Apple Silicon, Homebrew’s GCC 16,
Clang 23), and on Linux a sample of both external suites. Nightly, the whole external suites run on
both compilers and both platforms, with the sanitizer, hardened, no-exceptions and
-O2 configurations and the real-world projects. The platform and compiler matrix lists what each
combination has passed.
There is no list of tolerated failures. A test reported FAIL fails the run, and every
failure is resolved where its cause is decided: a libycxx bug is fixed; a
test that does not apply is skipped with its category and reason; a cause
outside the test and the library — a compiler bug, an ABI limit, a draft defect — is an
expected failure with its reason, and an unexpected pass fails the run so
the mark goes when the cause does.
Every test, passing ones included, records its commands, exit statuses and output; each run
writes an HTML report with its provenance, and a Markdown copy ready to paste to a person or an
assistant.
05
Platform and compiler matrix
Exactly what has been confirmed, where, and with which compiler. A ✓ means
a CI run or a run recorded in STATUS.md passed with no unexpected failure; anything
less is said in words.
Hosted library. Dates are those of the recorded run.
Linux on aarch64 and other architectures: not built or tested. — means not run.
Freestanding and bare metal
Target
Compiler
What is checked
x86_64-unknown-none-elf, riscv64-unknown-elf
Clang 23.1
✓ every freestanding header compiles; the smoke test links
x86_64, freestanding
GCC 16.2
✓ every freestanding header compiles; the smoke test links
Bare x86_64 kernel, Limine in QEMU 8.2
GCC 16.2, Clang 23.1
✓ boots and passes: containers, std::print and exceptions over the program’s own heap and consoleg
Darwin arm64 and x86_64
Clang 23.1
Cross-compiled only: every core header and the freestanding runtime compile for both Darwin targets
a CI run of 2026-10-07 (commit d48ba32), 2,824 tests; no failures. Expected failures carry their cause in the test (compiler gaps, ABI limits, a draft defect); the rest are unsupported in that configuration.
b Full runs of 2026-10-05/06 recorded in STATUS.md: 211 and 215 libc++ failures, 13 libstdc++ failures per compiler, each categorised in the suites’ TRIAGE.md. The Clang libstdc++ figure is projected from the full run with the final skip lists. The CI sample (selected directories) passes on every push.
c Own suite, runs of 2026-10-05 recorded in STATUS.md: hardened 2,425 / 2,418 pass and -fno-exceptions 1,941 pass, no failures. The nightly also runs -O2, for which STATUS.md records no result.
d Runs of 2026-10-07 recorded in STATUS.md, with the linkage proof for every project.
e ASan and TSan: whole own suite, 2026-10-06, no failures (GCC TSan with a GCC built with libsanitizer). The nightly ASan job also enables UBSan; STATUS.md records the ASan run.
f The nightly workflow runs both external suites on macOS; STATUS.md records no macOS result yet, and named locales and <stacktrace> symbolization are less exercised there.
gexamples/hosted-layers, run by the CMake package test on Linux.
06
Getting started
Build libycxx once per compiler, install it, and point a project at the
installation. docs/BUILDING_PROJECTS.md covers CMake, Meson, make, autotools, Bazel,
Conan and vcpkg.
1. Toolchains
tools/toolchain/provision finds GCC 16.2 and Clang 23.1 or installs
them; activation puts them on PATH.
shell
git clone https://github.com/yrashk/libycxx && cd libycxx
# finds GCC 16.2 and Clang 23.1, or downloads/builds what is missingsource tools/toolchain/activate.sh --provision
A project of your own links ycxx::ycxx, which compiles against libycxx’s
headers and links its archives and ABI runtime instead of libstdc++ or libc++:
An existing project that knows nothing about libycxx is built with the installed toolchain
file, the compiler wrappers, a Meson native file, or pkg-config (with
PKG_CONFIG_PATH set to the installation’s lib/pkgconfig):
ycxx-c++ is the compiler libycxx was built with, plus its headers, C++26 and
its archives. Each C++ dependency must be built from source the same way: libycxx has its own
ABI, so a distribution’s prebuilt C++ libraries cannot be linked in. C libraries are fine.
4. Check the result
shell
# was everything built against libycxx, and nothing else?/opt/libycxx-gcc/bin/ycxx-check-binary build
# libycxx's own gate: policy checks, builds, freestanding, own suitetools/test
07
Status and limitations
Every header of C++26 is in place and the own suite passes on both compilers,
on Linux and macOS. What libycxx is not yet, plainly:
Young, without a stable ABI
Version 0.1.0. Type layouts change between commits: rebuild everything, dependencies included, when libycxx changes, and keep one installation per compiler.
C++26 only
Older -std= modes are raised to C++26, so features C++26 removed (auto_ptr, <strstream>, …) and libstdc++/libc++ extensions do not compile. Code relying on headers those libraries include from one another needs a few #includes.
One runtime per image
libycxx links statically and hides its symbols, so each shared library has its own runtime state: terminate and new handlers, throw; and current_exception do not cross shared-library boundaries.
Compiler gaps
<meta> needs GCC with -freflection and <contracts> GCC’s -fcontracts; Clang 23 has neither and cannot throw during constant evaluation. GCC 16 cannot mix #include and import std; in one translation unit.
macOS is newer
The macOS job runs the gate on every push, but parts written for Darwin are less exercised: named locales there, and <stacktrace> symbolization, which reads ELF and DWARF only. Modules are tested on Linux only.
Open work
Remaining external-suite failures are triaged; two libycxx bugs are open among them. <filesystem> and the time zone database have no hosted-layer primitives yet. About ten benchmarks remain over 1.5× slower than libstdc++.
STATUS.md is the full record: per-area results, known compiler gaps, the draft
defects noticed along the way, and what comes next.