# muslkit musl-linked static libraries from Alpine, without Alpine. Alpine builds everything against musl and ships `*-static` packages for most of it. An `.apk` is just a tarball, and an `APKINDEX` is just a text file — so you don't need apk, a chroot, a container or a distro to get `libcrypto.a` built for musl. muslkit fetches the index, resolves a dependency closure, downloads the packages and unpacks them into a sysroot directory you own. Nothing is installed system-wide. Nothing needs root. ```bash muslkit add openssl-libs-static nim c -d:ssl $(muslkit nimflags) --cc:clang --clang.exe:./zigcc app.nim ``` ## Why Getting a fully static Nim (or C, or Zig) binary with TLS on a glibc distro means finding musl-built archives, and the usual answers are "install Alpine", "run Docker" or "use Nix". Alpine's mirrors already serve exactly the files — this just takes them. ## Usage ``` muslkit add ... Download packages and unpack into the sysroot muslkit list Show what the sysroot holds muslkit libs Show the static libraries in the sysroot muslkit search Search the index (names and descriptions) muslkit show Index record for one package muslkit nimflags [-l lib] Print nim flags for a static build muslkit ccflags [-l lib] Print cc/clang flags muslkit nimcfg [-o file] Write a nim.cfg fragment muslkit zigcc [-o file] Write a `zig cc -target …-musl` wrapper script muslkit env Shell exports (PKG_CONFIG_*, MUSLKIT_ROOT) muslkit path Print the sysroot path muslkit clean Remove the sysroot (cache is kept) ``` Options: `-r/--root`, `-b/--branch` (default `v3.21`, `edge` for rolling), `-a/--arch`, `-m/--mirror`, `--repo main,community`, `-l/--lib`, `--cc`, `--no-deps`, `--refresh`, `-q/--quiet`. The sysroot defaults to `$XDG_DATA_HOME/muslkit/sysroot` and honors `MUSLKIT_ROOT`. Downloads are cached under `$XDG_CACHE_HOME/muslkit`, so a second `add` is offline and the index is re-fetched only once a day. ## A full static build, start to finish ```bash muslkit add openssl-libs-static zlib-static muslkit zigcc # writes ./zigcc (needs zig on PATH) nim c -d:release -d:ssl \ --cc:clang --clang.exe:./zigcc --clang.linkerexe:./zigcc \ $(muslkit nimflags) --passL:-s \ -o:app src/app.nim ``` `muslkit nimflags` emits more than include and library paths, because two things bite every static Nim build with TLS: - **`-d:ssl` makes Nim `dlopen` libssl at runtime.** A static binary cannot, and dies at startup with `could not load: libcrypto.so(...)` — even on code paths that never touch the network. The fix is `--dynlibOverride:ssl --dynlibOverride:crypto` plus the archives on the link line. - **OpenSSL 3 removed `SSL_get_peer_certificate`,** which Nim's wrapper still references, so the link fails on one undefined symbol. The fix is `-DSSL_get_peer_certificate=SSL_get1_peer_certificate`. Both are emitted automatically when `libssl.a` and `libcrypto.a` are present in the sysroot. A static binary carries no CA trust store, so set `SSL_CERT_FILE` to a bundle on the host that runs it. Cross-compiling is the same command with `--arch`; `muslkit add -a aarch64 openssl-libs-static` and `muslkit zigcc -a aarch64` line up. ## Trust Packages come over HTTPS from the mirror and are unpacked as-is. muslkit checks the size recorded in the index but does **not** verify Alpine's RSA signatures — apk's checksum field covers the package's control segment, not the file, so a real check means implementing apk's signature format. Treat a sysroot as build input, not as a trust root. If that matters for your use, pin a mirror you run. ## Install ```bash nimble install ``` or build in place with `nim c -d:ssl -o:muslkit src/muslkit.nim`. Requires `tar` on PATH (an `.apk` is concatenated gzip streams, which GNU tar reads) and, for the `zigcc` helper, `zig`. ## Library ```nim import muslkit let remote = initRemote(branch = "edge") let idx = remote.fetchIndex() for pkg in idx.resolve(["openssl-libs-static"]): echo pkg.name, " ", pkg.version, " ", remote.fetchPackage(pkg) ``` Modules: `muslkit/index` (APKINDEX parsing, provides and dependency resolution), `muslkit/repo` (mirror, cache, download, unpack), `muslkit/sysroot` (manifest, static-lib discovery), `muslkit/flags` (nim/cc/ pkg-config flag emission). ## Tests ```bash nimble test ``` The suite is offline — index parsing, resolution through `so:`/`pkg:` provides, manifest round-trips and flag emission all run against fixtures.