Zainium Dynamics
Docs / Using Zainium OS

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

muslglibc
Directory/overlayer/syshub/x86_64-zainium-linux-musl/overlayer/zexlib/union/x86_64-zainium-linux-gnu
Layerbaseuserland (optional package)
Loaderlib/ld-musl-x86_64.so.1lib/ld-linux-x86-64.so.2
C librarylib/libc.solib/libc.so.6
Compilergcc, g++, cc, c99x86_64-zainium-linux-gnu-gcc, -g++
lddon PATHin 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

Installing glibc and its toolchain with zex

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:

One program built for glibc and for musl, each with 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/lib are built for musl and cannot load into a glibc process; glibc's own libstdc++ and libgcc_s live in its directory. The one library in both is libsys_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/sh is /overlayer/syshub/bin/sh.
  • glibc's loader reads its cache and preload list (ld.so.cache, ld.so.preload) only from glibc's own etc, 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

ConflictPrevented by
Two loaders and two libc files in /lib and /lib64each in its own triplet directory
Headers of one library compiled against the other's libceach compiler uses only its own headers
A glibc program loading a musl-built libraryglibc's loader never searches the shared lib
libstdc++ of one ABI loaded by the otherone copy per C library
One ld.so.cache listing bothglibc's cache lists only glibc libraries
glibc's ldd replacing musl'sglibc's tools stay off PATH
pkg-config returning the wrong .pc filesa separate search path per toolchain
Users, DNS or time zone read from different placesboth 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.

All documentation