Spec M37 — mc hosted on Linux (owner's need, 2026-09-04: the cloud only runs Linux)
Goal: the self-hosted compiler runs natively on Linux (x86_64 and aarch64), bootstraps there to
its own fixed point, and make check runs its portable subset on a Linux host, so development can
happen on a Linux machine with no macOS in the loop after the first published binary.
Host layer #
src/host_macos.mc/src/host_linux.mc: everything the compiler needs from the OS that differs:posix_spawnp/waitpid(musl has them), the environment (_NSGetEnvironon macOS; on Linuxmain(argc, argv, envp)— the third argument musl'scrt1.opasses — stored in a global at start),mmapflags,O_*values, the default system layer name for taught compilers (sysvssys_linux),HOST_OS/HOST_ARCHconstants, and the default target whenmc.tomlhas none (host = target).src/core.mcstays host-neutral;src/mc.mc(macOS host) andsrc/mc_linux.mc(Linux host) differ only in which host file they include. The bundle carries both hosts (<mc/host_macos>,<mc/host_linux>) and<mc/core>; a taught compiler built by a Linux-hostedmcincludes the Linux host automatically (the driver knowsHOST_OS).- Backends on a Linux host:
elf-obj/elf-obj-x86_64(native),macho/macho-exe(cross to macOS — the Mach-O writers are plain byte writers and keep working). No direct executable on Linux: the host links withld.lldthrough[linker];scripts/link-linux.sh OUT IN.owrapsld.lld+ musl sysroot for the bootstrap chain.
Cross-build and bootstrap #
- From macOS:
build/mc1 build src --config src/mc.linux-x86_64.toml(and-aarch64) producesbuild/mc-linux-x86_64/build/mc-linux-arm64(ELF, musl static,ld.lld), tested in Docker:mc-linux src/mc_linux.mc -o mc2l.oequals what the Linux fixed point produces, andmc-linux src/mc.mc -o x.o(a Mach-O object made on Linux) is byte-identical to macOSmc2.o. - On Linux:
scripts/bootstrap-linux.sh [SEED]: SEED = a Linuxmcbinary (a release assetmc-<ver>-linux-<arch>.tar.gzfetched by the script when absent, checksum verified, or a locally cross-built one); chainseed src/mc_linux.mc -> mc1l.o -> link -> mc1l -> mc2l.o -> mc2l -> mc3l.o; criterioncmp mc2l.o mc3l.o; goldentests/golden/mc2-linux-<arch>.sha256. make checkon a Linux host (HOST := $(shell uname -s)in the Makefile): runstest(link viald.lld),check-lex/ast/asm(mc1l vs mc2l),check-bundle,check-toml,check-build,check-limits,check-lang,check-conc(its runtime gains the POSIX semaphore path; the dispatch path stays macOS),check-exampleswhen sqlite3 dev files exist,check-docs,site; skips with a clear line:test-exe,check-standalone's Mach-O half,check-surface's--execases,check-desktop,bootstrap(macOS chain) — replaced bybootstrap-linux.make stage0still builds the C seed on Linux with clang (it emits Mach-O only); documented as "the seed is macOS-first; Linux bootstraps from a publishedmc".
CI and releases #
ci.ymlgains, on both Linux runners, a jobmc on linux/<arch> host: download the cross-builtmc-linux-<arch>from the macOS job, runscripts/bootstrap-linux.shand the Linuxmake checksubset natively. Required checks after merge.release.yml: thelinux-arm64andlinux-x86_64matrix entries are enabled: cross-built onmacos-15, verified on the Linux runners (the same jobs), packaged with sha256 like the macOS asset.
Docs #
docs/guide/90-linux-host.md (clone, fetch the seed, make check, what is skipped and why,
cloud workflow), docs/bootstrap.md § Linux chain, docs/ci.md, docs/build.md, CLAUDE.md.
Acceptance #
Docker linux/x86_64 and linux/arm64: bootstrap-linux.sh reaches the fixed point; the cross
proof (mc-linux src/mc.mc == macOS mc2.o) holds; Linux make check subset green; CI jobs
green on both runners; release assets for the two Linux targets produced from a tag build.