Recovering an ancient project sent me back down the "which build tool should I be using?" rabbit hole. Getting a script to grave dig 57 inconsistently styled K&R C files (!) really stresses the build cycle, more than writing new code.

First approximation: No one's happy with any build tool, with good reason. Then I discovered Ninja. It's an assembly language for builds, advertised as a back end for higher level tools, but many people script Ninja themselves.

For me, 15 lines of Ruby code plus some heredoc boilerplate spawned a 138 line build.ninja file. Back in the day, this computer algebra system used to take an hour to build. Make still needs a frustrating number of seconds. Ninja on all my cores is a correct fraction of a second.

Ninja is exceptionally fast, and handles parallelism extraordinarily well. It scales; they use it for Google Chrome. Various tools such as CMake can target Ninja. It is unique for its design goals.

Most importantly, looking at Ninja code is not a "Just kill me now!" experience.

https://ninja-build.org/

That's funny, I wrote basically the same thing here a few hours ago. I "replaced" GNU Make with Python + Ninja and it's way better.

https://news.ycombinator.com/item?id=32303096

And my build is a lot bigger, with ~1000 lines of Python generating ~9000 lines of Ninja. I will probably write a blog post about it at some point, but it supports

    - build variants      
      - dbg, opt, asan, ubsan
      - code coverage with HTML output
      - uftrace instrumentation
      - malloc and tracing
      - clang and gcc (because clang coverage is better, ubsan is different, etc.)
    - test and benchmark binaries

I'd love to see your ninja files, to see how you handled such things.

Rather than complicating my build.ninja files, I handle build variants in my script. Easy enough to output a new variant, probably faster to use, and certainly easier for others to understand.

People are more likely to adopt ninja as we did if they see it first as the easiest way to manage a small project. Why bother with CMake or other tools, if one can script in one's favorite language? I'm sick of working with bad build description languages; ninja is going straight to the bare metal.

Sure you can check it out here: https://github.com/oilshell/oil

    $ wc -l NINJA* */NINJA*
       64 NINJA_config.py
      ...
      260 cpp/NINJA-steps.sh
      361 cpp/NINJA_subgraph.py
      305 mycpp/NINJA-steps.sh
      605 mycpp/NINJA_subgraph.py
     1615 total
I borrowed the little Python library that Ninja itself uses to bootstrap its Ninja files.

There are a few missing things like some textual code generation, but overall it should make sense.

It's structured a bit like a lightweight Bazel -- each directory has a NINJA_subgraph.py file that specifies what to build. And then the "actions" are shell scripts in NINJA-steps.sh.

At the top of one file it shows the directory structure for variants, which is basically

    _bin/$compiler-$variant/foo_test
and

    _build/obj/$compiler-$variant/foo_test.o

The variants control the compile and link flags: https://github.com/oilshell/oil/blob/master/cpp/NINJA-steps....

Overall this is the best build system I've used :) My pet peeve is having to 'make clean' when changing the variant, and this avoids that, making everything available at once.

I'm sure it's reinventing some of the 120K lines of CMakeLists.txt that comes with CMake, but this way I don't have to learn and debug a wonky shell-ish language!

One downside of the pattern is that you probably don't want to invoke shell on Windows (which doesn't affect my project). I find that very useful though, so I'm not sure what would replace it for Windows projects. (I guess batch files, but I don't think they're powerful enough)