musl and glibc
Why Zainium OS has two C libraries, how glibc is installed next to musl, and the conflicts the layout prevents.
Every dynamically linked Linux program is bound to one C library: its ELF header names that library's loader, and its code calls that library's ABI. The two C libraries in wide use are not interchangeable:
- musl — small, strict and easy to audit; a clean base to build a whole operating system from source. The Zainium base is built on musl.
- glibc — the C library of most distributions. Prebuilt software — commercial applications, games, vendor SDKs, many language runtimes — is published for glibc and does not run on musl.
On a classic Linux layout both would fight over /lib, /lib64, /usr/include, the loader path, ldd and the compiler. Zainium OS gives each its own directory, so both run on one system.
Where each one lives
| musl | glibc | |
|---|---|---|
| Directory | /overlayer/syshub/x86_64-zainium-linux-musl | /overlayer/zexlib/union/x86_64-zainium-linux-gnu |
| Layer | base | userland (optional package) |
| Loader | lib/ld-musl-x86_64.so.1 | lib/ld-linux-x86-64.so.2 |
| C library | lib/libc.so | lib/libc.so.6 |
| Compiler | gcc, g++, cc, c99 | x86_64-zainium-linux-gnu-gcc, -g++ |
ldd | on PATH | in glibc's bin, not on PATH |
Nothing of glibc goes into the shared bin, lib or include, so the compiler, the headers, ldd and every program of the base stay musl's.
Installing glibc
elevate zex install glibc # loader, libraries, locales, tools
elevate zex install glibc-toolchain # gcc and g++ for glibc, with glibc-dev

Building for glibc
Plain gcc builds for musl. Use the triplet compiler for glibc:
x86_64-zainium-linux-gnu-gcc hello.c -o hello
./hello
To make the unprefixed names (cc, gcc, g++, cpp, pkg-config) use glibc:
eval "$(sys-resolver env glibc)" # this shell only
elevate sys-resolver set glibc # system default (set musl to go back)
sys-resolver get # show the current default
ZAINIUM_LIBC=glibc make # one command
On the live ISO, the same program built both ways — each binary names its own loader:

Running prebuilt glibc programs
A program built on another distribution asks for /lib64/ld-linux-x86-64.so.2, which Zainium does not have. It is started with glibc's loader automatically, once glibc is installed. zex installs glibc programs and libraries unchanged — it never rewrites them to musl.
The rules that keep them apart
- Each program names the loader of the C library it was linked against.
- glibc's loader searches only glibc's directory. The libraries in
/overlayer/syshub/libare built for musl and cannot load into a glibc process; glibc's ownlibstdc++andlibgcc_slive in its directory. The one library in both islibsys_resolver.so, which needs no C library and is preloaded on purpose: it maps the paths programs from other distributions ask for. - Both read the same system configuration: users, groups, hosts, DNS and the time zone come from
/overlayer/syshub/etc;/bin/shis/overlayer/syshub/bin/sh. - glibc's loader reads its cache and preload list (
ld.so.cache,ld.so.preload) only from glibc's ownetc, never from the base's. - The base never contains glibc-linked files; base upgrades reject them, so removing glibc can never break the base.
Conflicts this prevents
| Conflict | Prevented by |
|---|---|
Two loaders and two libc files in /lib and /lib64 | each in its own triplet directory |
Headers of one library compiled against the other's libc | each compiler uses only its own headers |
| A glibc program loading a musl-built library | glibc's loader never searches the shared lib |
libstdc++ of one ABI loaded by the other | one copy per C library |
One ld.so.cache listing both | glibc's cache lists only glibc libraries |
glibc's ldd replacing musl's | glibc's tools stay off PATH |
pkg-config returning the wrong .pc files | a separate search path per toolchain |
| Users, DNS or time zone read from different places | both read /overlayer/syshub/etc |
Tested
Every rule on this page is checked by a script on an installed system with glibc 2.44: building for both libraries, each program's loader, a program built for other distributions, users, groups, DNS and the time zone, threads, dlopen, locales, iconv, C++, and that nothing of one library leaks into the other. The last run passed 35 of 35 checks — see the glibc test report, and run the script yourself:
elevate zex install glibc glibc-toolchain
python3 -I glibc-tests.py
The same design, written for any distribution, is part of the Dualayer Hierarchy Standard.