Step 06 · Driving the toolchain
driver.cpp owns the boring-but-critical job of turning an IR string into an executable on disk.
The pipeline as commands
$ /opt/homebrew/opt/llvm/bin/llc -O0 -filetype=obj -o /tmp/minilangc-obj-XXX.o /tmp/minilangc-ir-YYY.ll
$ /opt/homebrew/opt/llvm/bin/clang -O0 -o a.out /tmp/minilangc-obj-XXX.o
That's the whole compiler. llc lowers IR → object file (handles
instruction selection, register allocation, scheduling, emission). clang
acts as the linker driver — it knows how to invoke the system linker
(ld64 on macOS) with the right libc paths so printf resolves.
-O<N> is forwarded to both; -v echoes the commands so users can
re-run them. Both tools are looked up via ${LLVM_BIN_DIR} (settable
via CMake -DLLVM_BIN_DIR=...) so the lab works on other people's
machines.
Process management
We use popen (read end) for capturing combined stdout+stderr. This
is good enough for our purposes:
- Tools rarely produce large output on success.
- On failure, we want all the diagnostic chatter.
- No need to handle stdin (we pass IR via a file).
For production:
- Use
posix_spawn+ pipes to capture stderr separately. - Stream to user terminal in
-vmode rather than buffer. - Handle signals properly (Ctrl-C should kill the child).
Temp file hygiene
mkstemp("/tmp/minilangc-{tag}-XXXXXX") then rename to add the right
extension. We don't clean up because:
- On success the user doesn't care.
- On failure the user wants to inspect the IR.
A real driver would offer --save-temps (gcc) or --keep-tmp-files.
The current behaviour matches --save-temps, which is fine for an
educational tool.
Why clang instead of ld directly
Calling ld directly requires knowing the platform-specific runtime
glue: crt1.o, libSystem.B.dylib, the right SDK path. clang -o figures
all that out by querying the macOS SDK. It's slower (one extra exec)
but vastly more portable.
Testing the e2e pipeline
Tests in test_suite.cpp call
toolchainAvailable() and skip e2e tests gracefully if llc isn't
present. This keeps CI green even on machines without LLVM installed.