Once you stray out of that niche, anyone is better suited if they just automate all the boilerplate generation and compiler checks.
And that's what CMake does.
Boilerplate code and "compiler checks" are strongly negative anti-patterns. Maybe the worst in programming. That cmake makes it easy to do these awful things just shows how evil it is!
People: write simple, portable code!
That isn't always how it works in practice, though. It's useful for your build system (or meta-build system) to be able to check for, say, C++17 support, and cause the build to fail early if this is missing.
Similarly, you can use a tool like CMake to detect libraries. If a library is missing, you might want the build (or, rather the 'configure' stage) to instantly fail, or you might want to build with certain features removed to cope with the library being missing. CMake supports both, as does autotools.
I agree with everyone who says CMake's scripting language is atrocious and that it's often miserable to work with, [0][1] but that's because CMake specifically is terrible. The problem it's solving is a legitimate one.
An example: you can write a desktop application with two different platform-specific front-ends, and have CMake compile the appropriate one given the target platform. This is nicer than relying on the two platform-specific build systems directly.
The gp enriquto had a rigid stance on so-called "optional" libraries. If the library is not there, the build should fail and that's it.
I don't know if my previous reply to him explaining the benefits of building even with missing libraries was satisfactory: https://news.ycombinator.com/item?id=25913562
that does not work as soon as your users are on both windows and a unix-like platform and you are making a non-trivial app (for instance, an app with networking, audio, and video support).
A simple example: how do you share a GPU texture handle across multiple processes portably with a single code that works across windows / mac / linux's graphics APIs ?
How do you memory map a file, or spawn a subprocess simply and portably? Every way that I've seen it done that doesn't hand the logic off to the build system is an unmaintainable error prone mess.
CMake eliminates boilerplate code and compiler checks. They do not exist, at all. With CMake you state that you have a C++11/14/17/20 project, it builds N static/shared libs and M executables, you set dependencies, and you're done.
They do exist in Makefile projects because Makefiles only define the DAG for the build, and don't perform any sanity check at all. So if you have to include dependencies or use specific compilers then you have to manually check each and every single thing yourself, because Makefiles do not handle that at all.
Think about it: why did the entire industry adopted makefile generators such as CMake instead of just using a standard tool like make, which just works and is ubiquitous?
And no, relying on tools and a layer of abstraction to eliminate all janitorial work is not evil or awful. Checking if a lib you depend on already exists in the system is not evil or superfluous. Checking if the compiler you're using supports a specific version of C++ is not evil or superfluous. Do you expect things to just work when you aren't even aware of which compiler you're going to use? Do you want to spend time looking at weird compiler error dumps just because your build machine happens to have a different version of, say, Boost installed?
The main problem of cmake is that some people seem totally oblivious to the problem domain, and what/how much work it takes to get stuff to work reliably given very basic usecases such as... Upgrading a version of a compiler, such as VS. Think about it: How exactly do you think simple, portable code is done? Do you expect code to compile on different platforms by magic?
It is both evil and superfluous. It is evil because you should be writing portable code and do not depend on compiler specificities. It is superfluous because if you do not check, the compilation will still fail, which is precisely the expected behaviour.
> How exactly do you think simple, portable code is done?
By writing it carefully and testing it on different systems. You test with -Wall -Wextra -Werror -pedantic on all systems but you distribute the Makefile without these compiler flags.
> Do you expect code to compile on different platforms by magic?
No, of course. At first you will have a few linuxisms or macOS-isms, that you will gradually remove through a few rounds of multi-platform testing (which is free and easy to do nowadays).