Azazel
A build configuration layer for Zig. You describe your modules in CUE. CUE
type-checks them and fills in defaults. A shell script turns the result into a
Zig source file. build.zig walks that file and produces the compile graph.
Source: <https://github.com/godofecht/azazel>
The problem
A build.zig starts as twenty lines and ends as four hundred. Module wiring,
optimization modes, link edges and install rules all live in imperative code,
mixed with real logic. Adding a library means editing that code. Answering
"what does this project build, and how" means reading it.
Azazel splits the description from the execution.
project.cue holds the description. It is data, so a schema can validate it.
A typo in a kind, a wrong type on a field, an unrecognised option: these are
rejected by cue before any Zig runs, with a message pointing at the line.
build.zig holds the execution. It is a fixed loop, about forty lines, and it
does not change when your project does.
The generated file in between is Zig source, so there is no parser and no JSON at build time. The module list is a compile-time constant.
The surface is deliberately small. Four fields per module. No compiler flags,
no include paths, no platform triples, no linker options. #Module is a
closed CUE definition, so there is no escape hatch either:
$ cue export -e build
app.flags: field not allowed:
./project.cue:8:2
If you need something outside those four fields, build.zig is still an
ordinary build.zig and you can add it there.