Cross-compilation sysroots
This document is the design and implementation plan for packaging and distributing minimal sysroots that let kit users cross-compile for every platform in the release support set from any host.
Goals
- One
kit sysroot install <triple>installs everything needed to cross-compile for that target. - Sysroots are minimal: stubs and headers only, no full framework trees or large dynamic libraries.
- Every sysroot ships as a signed
.kpkg, distributed through kit's existing CAS + package infrastructure. - Macros and library versions are versioned and reproducible; the kpkg hash is the identity of a sysroot release.
- macOS SDK headers are legally redistributable only by the user; the macOS kpkg references them by CAS blob hash but does not embed them. Users populate the blobs from a local SDK once; thereafter the kpkg installs normally.
Support set
| Triple pattern | libc variant | Notes |
|---|---|---|
{x86_64,aarch64,riscv64}-linux-musl |
musl static + stub .so |
Compiled from musl source |
{x86_64,aarch64,riscv64}-linux-gnu |
glibc stub .so |
Stubs generated from reference glibc |
{x86_64,aarch64}-windows-gnu |
mingw-w64 UCRT | Import stubs + headers, open source |
aarch64-apple-macos{14,15} |
libSystem stub | .tbd stubs; headers by hash |
{x86_64,aarch64,riscv64}-freebsd |
FreeBSD libc stub | Stubs + headers, BSD license |
{x86_64,aarch64,riscv64,riscv32}-none |
freestanding | kit rt/ only; no sysroot kpkg |
Freestanding targets require no sysroot kpkg; libkit_rt.a and
rt/include/ serve that role and are already in-tree.
Sysroot kpkg layout
Single-root layout note (see ../RELEASE.md): kit consolidates everything it manages under one root,
$KIT_HOME(default$XDG_DATA_HOME/kit≡~/.local/share/kit). Installed sysroots therefore belong at$KIT_HOME/sysroots/<triple>/. The build/test provisioning today caches them under$XDG_CACHE_HOME/kit/sysroots(KIT_SYSROOTS_DIRinmk/env.mk); the SYSROOTS implementation should adopt the$KIT_HOME/sysrootslocation when it lands as a user-facing feature.
Each installed sysroot unpacks into $KIT_HOME/sysroots/<triple>/:
<triple>/
include/ system headers
lib/
crt1.o C runtime entry (where applicable)
crti.o
crtn.o
libc.a static libc (musl only; absent on stub-only platforms)
libc.so stub or real shared library
libm.so
libpthread.so
... other platform libs
tbd/ macOS .tbd stubs (macOS targets only)
The cc driver's -target flag resolves the sysroot by triple lookup under
~/.kit/sysroots/. Explicit --sysroot=<path> overrides this.
Library stubs
ELF stub .so (Linux glibc, FreeBSD)
A stub .so contains only what the linker needs: SONAME, exported symbol
table, and GNU version info (.gnu.version, .gnu.version_r). No PT_LOAD
segment, no .text, no .data. The file is ~10–50 KB instead of hundreds of
KB for the real library.
Kit will include a stub generator (src/obj/elf_stub.c, exposed as
kit sysroot gen-elf-stub) that:
- Reads a real
.so(dynsym + versioning sections). - Emits a minimal ELF with the same SONAME, all exported symbols as
STT_NOTYPE/STB_GLOBAL/SHN_ABS, and the original.gnu.version_rchain. - Records the source library's build-id in a
.note.kit.stubsection for traceability.
Stubs are generated offline from a reference installation (a glibc or FreeBSD system) and committed into the sysroot kpkg. They must be regenerated when the upstream ABI version changes.
macOS .tbd stubs
Apple's Text-Based Stub Library (.tbd, YAML) is the native macOS stub format
used inside Xcode SDKs. Kit's Mach-O linker already knows how to read .tbd
files (required for linking against system frameworks). The macOS sysroot kpkg
contains .tbd files for libSystem, libm, libpthread, libc++, and the
core framework stubs.
The .tbd files are open/YAML; they can be extracted from any macOS SDK
installation and are small.
Windows import stubs (.dll.a)
mingw-w64 provides import stub archives for the Windows SDK DLLs (kernel32, ucrtbase, etc.) under a MIT-compatible license. The Windows sysroot kpkg bundles these directly alongside the mingw-w64 UCRT headers. No generation step is needed; the mingw-w64 tree is the upstream source.
musl: compiled from source
For *-linux-musl targets kit compiles musl directly rather than shipping
pre-built archives. Advantages: reproducible, architecture-correct, no
redistribution complexity, and a good exercise of kit's self-compilation
pipeline.
The musl source tree (a pinned release tarball, verified by BLAKE2b hash) is
bundled in the kpkg for each architecture. kit sysroot install aarch64-linux-musl fetches the kpkg, extracts the musl source, and compiles
it with kit cc -target aarch64-linux-musl into:
libc.a— static archivelibc.so(stub only; the real.sofor dynamic musl is the runtime-providedld-musl-<arch>.so.1)- CRT objects:
crt1.o,rcrt1.o(PIE),Scrt1.o,crti.o,crtn.o
The compile is cached by the musl source hash, so reinstalling the same kpkg version is a no-op.
macOS SDK headers: CAS-referenced blobs
Apple's SDK headers may not be redistributed by third parties. The macOS sysroot kpkg solves this by referencing the header blobs by CAS hash without embedding them:
# excerpt from the macOS sysroot kpkg manifest
headers:
required_blobs:
- hash: "sha256:abc123..." # usr/include/stdio.h
install_path: include/stdio.h
- hash: "sha256:def456..." # usr/include/sys/types.h
install_path: include/sys/types.h
...
When kit sysroot install aarch64-apple-macos14 runs:
- Kit resolves each required blob from the local CAS.
- If any blobs are missing, it prints the missing hashes and instructs the
user to run
kit sysroot extract-macos-headers. - Once all blobs are present, the sysroot is materialized normally.
The blobs themselves are ordinary CAS objects — the user may host them on any
CAS-compatible store (private server, S3, local NAS) and point kit at it via
KIT_CAS_REMOTE or kit cas remote add.
kit sysroot extract-macos-headers
kit sysroot extract-macos-headers [--sdk-path=<path>] [--target=<triple>]
Walks the SDK's usr/include/ (and selected framework headers), ingests each
file as a CAS blob, and prints a manifest fragment with the resulting hashes.
This is run once per SDK version by the user on their Mac. It does not upload
anything; it just populates the local CAS. The user may then push those blobs
to their preferred remote.
The manifest fragment output is what kit's sysroot release process uses to
build the macOS kpkg. For users who just want things to work locally, the
extract step followed by kit sysroot install is sufficient.
kit sysroot command surface
kit sysroot list # show installed sysroots
kit sysroot available # show sysroots available in configured remotes
kit sysroot install <triple> # fetch + install sysroot kpkg
kit sysroot install <triple> --from=<path> # install from a local kpkg file
kit sysroot remove <triple> # uninstall
kit sysroot update [<triple>] # reinstall latest version
kit sysroot path <triple> # print install path (for --sysroot= use)
kit sysroot extract-macos-headers [--sdk-path=<path>] [--target=<triple>]
kit sysroot gen-elf-stub <input.so> -o <stub.so>
kit sysroot gen-kpkg <triple> --config=<sysroot.toml> -o <output.kpkg>
gen-kpkg is the sysroot builder used offline by kit's release pipeline. It
reads a sysroot.toml that declares the source for each component (musl source
hash, upstream .so paths to stub-ify, mingw tree path, .tbd directory,
macOS header manifest), runs the appropriate generators, and emits a signed
kpkg.
Implementation work items
Infrastructure
src/obj/elf_stub.c— ELF stub.sogenerator; reads dynsym +.gnu.version_r, emits a no-PT_LOAD ELF. Exposed viakit sysroot gen-elf-stub.driver/cmd/sysroot.c— thekit sysrootsubcommand (list / available / install / remove / update / path / extract-macos-headers / gen-elf-stub / gen-kpkg).include/kit/sysroot.h+src/api/sysroot.c— public API for sysroot resolution, used by theccdriver's-targetlookup.sysroot.tomlschema — declarative input format forgen-kpkg; one file per(triple, libc-variant, libc-version).- macOS blob-reference manifest support in kpkg reader — when a kpkg
declares
required_blobs, validate presence before materializing, and emit a helpful error with theextract-macos-headershint if missing.
Sysroot sources and generation
- musl — pin a musl release (tarball + BLAKE2b), write a
sysroot.tomlper{x86_64,aarch64,riscv64}-linux-musl, implement the in-install compile step. - Linux glibc — generate ELF stubs from a reference glibc
{x86_64,aarch64,riscv64}installation (targeting glibc 2.35 as a reasonable minimum). Package headers + stubs + CRT objects into kpkgs. - Windows — package mingw-w64 headers + import stubs for
{x86_64,aarch64}-windows-gnu. Validate against the VM test suite (test-hosted). - macOS — generate
.tbdstubs, write header manifest, validate the blob-reference install flow on a local macOS SDK. Target macOS 14 and 15. - FreeBSD — generate ELF stubs + package headers from a FreeBSD 14
{x86_64,aarch64,riscv64}installation.
CI and distribution
- Release pipeline script (
scripts/gen_sysroots.sh) — runsgen-kpkgfor each sysroot, signs the resulting kpkgs, and pushes to the release CAS remote. kit sysroot availablefetches the index from the configured release remote and shows version + size for each triple.- Add sysroot install smoke tests to
test/hostedfor each supported triple: install sysroot, compilehello.c, run on target (or VM).
Open questions
- glibc version targeting: ship stubs for a single baseline version (e.g. 2.35) or per-version kpkgs? Per-version is more correct but multiplies the release surface. Start with a single baseline and version the kpkg (users who need an older ABI can pin the kpkg version).
- FreeBSD version: FreeBSD 14 as the baseline. FreeBSD moves slowly; one kpkg version per major release is likely sufficient.
- macOS SDK scraping automation: the
extract-macos-headersstep is manual. A CI job running on a macOS runner could automate it, but requires a macOS SDK license. For now the manifest is generated manually when an SDK version changes and the blob hashes are committed to the release pipeline config. - CAS remote hosting: where are the kpkgs and blobs hosted? Options: GitHub Releases (artifacts, size-limited), S3/R2, or a self-hosted kit CAS instance. This is a release infrastructure question, not a kit code question.