When you find yourself manually listing the .h files that a c/c++ file includes, learn how to generate .d files (it is in the manual, but stack overflow has some better patterns).
Then, figure out how to use make to automatically generate the list of source files required to build each binary. At this point, your makefile will have surpassed the usability of cmake in my opinion.
Soon after that, you’ll think you need recursive make to deal with vendored dependencies. Instead, read “recursive make considered harmful”.
At that point, you’ll start to hit rough edges, but you’ll be well beyond a “small project”.
Next on my make reading list is the BSD ports system.
I’ve heard bazel is a decent make replacement, but I haven’t used it.
Ninja doesn’t aspire to be one, and cmake/autotools are the reason I decided to go with raw make in the first place.
I love how that's one of the things the author listed in their post :)
However, it quickly turns into a morass the moment you want to do something outside of it.
I tried, and I gave up. I ended up coding something similar to make, in python. I just funneled some of my commands to the shell module.
So, for me, its much worse than just “omg which tool, so many!” because the most used tool is also, in my personal opinion, terrible.