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.