Getting started - mc is a compiler small enough to read, written in itself. It compiles a schoolbook-C language — seven types, one opaque pointer, if and loop — into AArch64 Mach-O, and it writes and signs the executable itself. Everything the core leaves out, you teach it from ordinary mc source.
One file, one program - Everything you can write without a project file. The exhaustive rules are ../reference/language.md; this page is the working tour.
A project: mc build and mc.toml - One file at a time works until you have a linker to call, libraries to name, or a compiler to teach before you can compile your program at all. mc build reads a TOML file and does the whole thing.
Teaching the compiler - The core language is deliberately small. What makes mc interesting is that the parts it leaves out are not missing — they are teachable, from ordinary mc source, in three escalating steps.
Emitting bytes: sections, opcodes, passes and backends - 30-teaching.md changed what the compiler parses. This page changes what it emits — from one raw instruction up to a complete replacement of the code generator and the object writer.
Cross-compiling - mc runs on macOS arm64 and produces binaries for macOS arm64, Linux arm64, Linux x86-64, Windows on ARM and Windows x64. Each path is a backend, a system layer and four lines of mc.toml; x86-64 adds one more file, a machine — the instruction selection behind a target-independent walker (../reference/machine.md). Nothing in the compiler's C seed knows about any of it.
Two worked examples - Everything in 30-teaching.md and 40-backends.md exists because of two programs in this repository. Neither of them changes a single line in src/ or stage0/.
How mc compiles itself - mc is written in mc. That sentence is only interesting if it can be checked, so this page describes the chain that checks it, and the rules a contributor has to follow to keep it checkable.
Footprint - How big is the smallest thing mc can produce, and how much memory does it use? The answer is a number per target, and almost none of it is the program.
mc on a Linux host - Until M37 mc was a macOS program that could target Linux. Now it is a Linux program too: the same source, the same core, the same fixed point, hosted on linux/aarch64 and linux/x86_64. This page is the whole story from a bare Linux machine to make check.
mc on a Windows host - Until M38 mc was a macOS and Linux program that could target Windows: M19 taught it to write COFF objects for windows/aarch64, M20 added windows/x86_64, and both times the objects were cross-compiled on macOS and linked and run on a CI runner. Now it is a Windows program too — the same source, the same core, the same fixed point, hosted on windows/arm64 and windows/x86_64. This page is the whole story from a bare Windows machine to make check.
A new primitive - Everything in 30-teaching.md changes what the compiler parses. This page is about the layer under it: teaching mc a value type it has never heard of — a floating-point number, a 128-bit integer, a half-float, a 256-bit vector — together with the way its literals are written, the instructions that operate on it, and the registers it travels in. None of that is in src/, and none of it needs to be.
A new architecture — from "I have an ISA" to "my image boots" - You have an instruction set mc does not know. MIPS64, maybe, or a RISC-V board, or something in a manual on your desk. This page is the path from that to a program running on it, and the short version is: you write a module, and you do not touch the compiler.
Recreating the compiler - You want a compiler for one target and nothing else: your machine, your object format, your word width, and none of the three writers, two machines and one project driver that mc carries because mc is hosted on macOS, Linux and Windows. This page is how.
Run something you do not trust - You have an .mc file from somewhere else — a bug report, a fuzzer, a student, a pull request — and you want to know what it does without giving it your machine. On Linux, one command: