92 comments

[ 4.2 ms ] story [ 179 ms ] thread
The fundamental problem is that

- These people are replacing Make, while still using Make

- They're not clear on what problems of Make they're solving, specifically. And they have never read the manual, and don't know how to use Make

For 99% of the projects out there, some Makefiles are what you actually want. It isn't perfect, and has many well-known warts, but CMake is not a step forward.

It's been a very long time since I dove down this rabbit hole, but last I did, I found that CMake is definitely the least-bad build system for C++. At least for large projects that span numerous teams.
I disagree… cmake is very clear about what problem it’s trying to solve… build portability. If you need something to build on windows Mac and a variety of unixen cmake works much better than make. The trouble is that a ) you probably don’t need that and b) cmake is contagious. Soon every library and its grandmother demands cmake. Cmake is also less orthogonal than make is…. Make is endlessly customizable to your work flow. Cmake is too opinionated.
Well I see a lot of people that doesn't write that portable CMake anyway, like they use compiler options specific for GCC.
That's because CMake's design and practical realities discourage portability, despite what the docs say. Almost any nontrivial project will need the non-portable target_add_*() calls eventually, so you may as well use them from the start and implement an (almost inherently faulty) compiler/platform switch if you want to target multiple, say to set sane optimization levels.
CMake don't have constructions like "I don't know which C++ compiler is selected, but turn on all warnings for it" and such. So, you need to write compiler-specific options by hands. Many people knows only gcc and/or clang.

CMake declare that it shields developer from knowing nuances of build systems and toolchains, but does it very badly.

Why would I not need/want my builds to work on all platforms if there's nothing platform specific in the code?
I've had to use CMake in a bunch of work projects, but never have I needed them to be portable. They've always been targeted only at Linux. CMake's biggest claimed feature is one that, to me, is utterly useless: I don't care about building on Mac or Windows.
Me neither.. but cmake is infectious. You end up using it because you need libraries that use it
CMake sucks significantly less than autotools for typical use cases, that’s how it “won.”
There are too many different environments for any build system to cover them all well while still being straightforward. There will never be a "good" one that everybody uses, although you can often find a more streamlined one for you to use on your own projects or develop enough expertise in one of the big general ones that its weirdness becomes invisible.

And so yeah, CMake sucks, just like all the other general purpose ones.

But the criticisms in this article are very superficial. I was expecting more technical and insightful.

I dislike the re-computation of local config process in auto-* tools immensely and had hoped cmake and the X11 pre-written local config stuff would work but .. it turns out it works less well than you'd want.

I still find the bsd make (bmake for some people) and gnu make "fork" highly counter-productive.

It's a side of the GNU model which irks me: they take things which had a well understood pattern, perceive a problem with it, write a tool which MOSTLY occupies the same ground.. and then name it into the command-space to collide with the thing it's almost-but-not-entirely compatible with.

At least cmake didn't do that.

Obviously this person isn't using AI to help them code CMAKE yet.

All the issues I had a year ago using CMAKE just went away with Microsoft CoPilot.

On my end, all the issues I had 10 years ago using CMake just went away when I actually learned how to use CMake :)
I was dreading making changes to Cmake config and asked ChatGPT how to do what I needed and instantly had an answer, got it configured and moved on.
I bought this book on autotools a few years ago which demystified it a bunch.

https://www.amazon.com/Autotools-Practioners-Autoconf-Automa...

Basically all of the decisions are based on decades of trying to support ever more features, backwards compatibility, many different hackers trying to keep it working for their own projects / companies, etc.

It is possible to use autotools nowadays without losing your mind. There is a "safe" path where things just work. I prefer it to CMake, but both are unwieldy beasts.

> It is possible to use autotools nowadays without losing your mind.

Only by punting the problems downstream.

"Oh, cross-compiling? Not my problem, ..."

GNU programs are the worst. Most of them you can't even build as a developer just by cloning their git repo and doing configure and make. When they ship a GNU program (e.g. GNU BIson or Make or whatever), there is a step that is done to produce the building version and that's what goes into the "official tarball" (now there is an antedeluvial practice right there).

To build as a deverloper working on the program, you have to run some "make boostrap" idiocy, which needs the correct version of AutoConf and AutoMake and whatevernot. Of course, every GNU program you boostrap wants different versions of these things, determined by what upstream is using.

Oh, git bisect to go backwards a few years? Different tools were used then; re-bootstrap with that ...

It's just insanity and AutoTools is at the heart of it.

I have found standard distros on relatively recent versions don't have issues with configure / make / make install, or at least issues I can solve fairly easily with googles
With the release materials you won't see problems on mainstream distros doing configure && make && make install.

I'm talking about cloning the program's git repo and working with that.

GNU programs don't include the generated configure script in their repos; you have to boostrap that first, and you need all the AutoCruft, in the correct versions which that git baseline of the program wants.

It's completely insane. It should be that to create a release of gnu-whatever-1.2.3 you just create a tarball directly out of git using the 1.2.3 version tag. That is the release. But that's not how it works; a release that doesn't require AutoTools has to be specially prepared.

Sometimes I have cheated to build a GNU program from sources. I would find the closest matching release tarball and unpack it over the cloned git repo, then run ./configure and all that. Carefully git-reset any differences and so on.

You seem to have a lot of experience with some hairy stuff. Mine consists of creating some open source C projects using autotools, and also cloning / building perhaps 7 projects I frequently use on Ubuntu and popOS which I have not struggled with. But totally believe that autotools hell is widespread.

My total nightmare experience has been with CMake, with a project that mixed C and C++. IIRC it had to do with trying to get something to work on LLVM / macOS which it wasn't originally supported for.

To be clear, I'm dead set against CMake. I would never voluntarily agree with that being introduced anywhere for any purpose. The concept is bad and the implementation is atrocious. In no uncertain terms, CMake is harmful garbage.
I'm curious: do you mind being a bit more specific? Feel free to send an email (easily discoverable from Git commits I make and end up on Github; same handle here and there).

(FD: CMake developer) I certainly understand a lot of the gripes that people have had, but the amount of tribal knowledge for obscure platform behaviors encoded in CMake is…vast. I am certainly in the "things need to improve" camp, but I don't think burning all the bridges that have been built is the way to go either.

While what you said is true, for outsiders it misses the 'why' (which I'm sure you are aware of!).

The idea with autotools is that the generated configure script (and other assorted files) is supposed to be forwards and backwards compatible with different systems. It's not perfect, but the behaviour is mostly locked down at the time it is built, based on the particular set of macros it is generated with.

There are definitely aspects of this which don't work (it's nearly impossible to test, getting specific versions of autotools is presumably a PITA, and the make-in-bash-in-m4 language is deeply cursed), but the overall design does make some things better.

For example, if your project needs a specific version of cmake, your users will have to figure out how to install it, but if your project requires a specific version of autotools, only your developers need to install it.

(FWIW autotools is on my 'never again' list of technologies; it's incredibly cursed)

As long as your policies are set correctly (not that this is particularly easy), your project will only need a version of CMake or newer, not a specific version.
Yeah, they are quite good at compatibility. In practice there may often be an upper version limit if you happen to use any features which eventually get deprecated or removed.
The reason for the recent stability is that the Autotools have been essentially unmaintained for the past 15 years. When there were steady releases back in the early 2000s, we experienced regular incompatibilities and breakage. Today, there are occasional releases again, but the tools have painted themselves into a corner--it's almost impossible to make any change of note without breaking things.
Before I started writing software, my main experience with build systems was trying to build a program I wanted that wasn't inside apt. When you're in that position, autotools is much nicer. The paradigm of downloading a release tarball with configure script (which has a --help!), so the end user just needs to do the old ./configure && make && sudo make install

is really nice. I found it much easier to tell autotools how to find a library. Autotools made it intuitive to figure out what options were available (configure --help), and I never ran into trouble with my cmake version being too old.

But as a developer in c++ land, I much prefer cmake. It integrates very nicely with nearly all other c++ libraries out there. I think modern cmake targets do a nice job of encapsulating how to consume a dependency. And Cmake isn't restricted to only POSIX like platforms.

So I suppose it depends on who the target audience is.

I very much prefer the autotools to CMake, but I'm 100% sure that's because I'm extremely familiar with them, and not so much with CMake.

For personal projects, the tool that that I can use fluently beats other tools every time. But when working in a team, that equation is different.

I'm a cmake advocate, but I agree with almost all of these criticisms. They are spot on, if perhaps overhyped (silly syntax is accurate, but not a critical problem).

But cmake has one overwhelming quality that overrides these: it won. Worse is better[1]. A united ecosystem behind a flawed tool is a hundred times better than a fractured ecosystem of utopian tools.

cmake has significantly improved over the last decade and continues to slowly chip away at its most pressing criticisms. Today it is 60% of what I want in a toolchain element. One day it will be 90% of what I want. And when that day comes I will be very happy with its ubiquity.

[1]: https://www.jwz.org/doc/worse-is-better.html

Given blaze and it's descendants have all the megacorp mind share, in which industry/environments is cmake king?
The C++ industry/environment

The latest Jetbrains survey has cmake usage at 57%, Bazel 3%, and Meson 2% [1]

Cmake isn't competing with Bazel and Meson, Bazel and Meson are interesting and worth talking about, but as a percentage of developer share they're irrelevant. Cmake is competing with legacy, the 33% of developers who still interact Make and VS Projects

[1]: https://www.jetbrains.com/lp/devecosystem-2022/cpp/

Sure, I also don't know anyone who uses jetbrains at work. I've only programmed in C and C++ for 20 years professionally, and I've never used CMake.

I'm just in a very specific bubble, so I was curious what the others were.

I guess I wouldn't think of cmake as a bubble, it's a part of the ocean the bubbles float in. Blaze/Bazel are a bubble, the only place they see a lot of use are Google-involved projects.

Facebook, MS, Bloomberg, are heavy into CMake. Bloomberg notably so, and MS built vcpkg which is basically a CMake package distribution system. Netflix is mostly a Java/Scala house, and what C/C++ they do have sort of uses a "whatever" approach to build systems (variously, make, cmake, bazel, bash scripts, *gradle*).

"Where is CMake used" is a difficult question. Everywhere.

Yes, I'm trying to state openly that I am in a bubble :P

> Facebook [&c] are heavily into CMake

As an employee, I can tell you this is not accurate re: C++ dev at FB. I'm sure someone somewhere is using it heavily, but largely we use buck, our build system.

I've also never worked at a place that used CMake, but I do see it used a fair amount in OSS.

I'm not allergic to CMake. It seems fine. Ugly and a bit baroque, but it's hardly the only tool like that.

Everyone is entitled to their opinion, and I respect the one in the blog post. Here is mine:

Half of the post complains about syntax. In my opinion, that's irrelevant. If the `if() else() endif()` syntax is too hard to understand, good luck with modern software engineering, because you'll have to deal with many languages.

The "dealing with more complex projects" section actually shows a very simple project. IMO CMake should be just fine for that complexity, which encompasses most projects out there. If your project is too complex for CMake (and that happens, I don't deny it), then you are an exception, not the rule.

This said, the example creating a lib (lib/) and using it in a binary (exec/) in the very same project seems wrong (edit: I mean that the blog snippet seems wrong. Trying to have both lib/ and exec/ together is totally normal). I agree that `if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)` looks ugly, but I wouldn't blame CMake for that: I would refactor the CMakeLists instead, because it just seems wrong :).

"Weird function definitions" -> most of the time, functions are a coding smell to me. I always managed to not use them (or maybe I used one or two? I don't remember) and that's all fine. Projects that define a ton of functions get unreadable extremely quickly.

Admittedly, the syntax for installing the target is a bit weird. I wouldn't say it's impossible to get right, though. Usually it's similar to most of your other projects (so you essentially have to get it right once, then copy-paste), and it has to be done once per project. It's not that big of a deal.

Meson is cool, but I have seen messy Meson projects, like I have seen messy CMake projects. I wouldn't say Meson is that much better than CMake. And autotools is not that bad when done right.

> This said, the example creating a lib (lib/) and using it in a binary (exec/) in the very same project seems wrong.

Not only is this a bog standard thing to do, it's really really easy with cmake.

> refactor the CMakeLists

Precisely. This is a totally normal organization just done incredibly badly.

That's exactly what I meant. The example in the blog seems wrong. Of course having both a binary and a library in the same CMake project is totally normal. Let me try to edit my post :)
> Half of the post complains about syntax.

FWIW, a lot of complaining about syntax only looks like complaints about "syntax" to someone who already understands the tool. The problem with cmake is that it's underlying execution model is a huge frothing mess.

Is that all-caps thing a variable name or a string or a special token being passed to the function to make it do something special? What's the difference between a target and a rule again? What's the difference between a property and a variable again? When do I need to manually expand list elements and when don't I? How does All That Wrapping work when I just want to pass one -fno-this-bad-warning flag?!

To someone who knows cmake, all that fury sounds like someone complaining about mechanics. Cmake allows you to do all that stuff, just maybe with funny "syntax", so what's the problem?

The problem is that even those of us who have to use it professionally, regularly, Just Can't Understand The Thing at anything more than a superficial level, despite knowing all our other tools with depth and grace. That's the sign of a bad tool.

I respectfully disagree. I could say the same about any programming language.

What is this `if (...)` function? Where is it defined? Why are some functions already there, while others I need to write myself? How does memory work when I just want to run computations with data? What is the difference between a primitive type and an object again? What the hell is an anonymous function?

I don't think it's that hard to learn the basics with CMake, and it's completely worth it when we have to use it professionally.

People have a mental model of programming languages, and a better language won’t make you question it all that much, most things should be somewhat understandable even by just knowing another language in the same paradigm.

Cmake is its own universe of random conventions duck taped together, and is famously hated. It is a great tool in that cross-platform building of C/C++ programs is a very hard problem and it is the de facto choice for that since it can solve it, but that doesn’t make criticism of its abstractions/language less true. It really is terrible.

I'm not a cmake guy, but seeing this:

> If the `if() else() endif()` syntax is too hard to understand, good luck with modern software engineering, because you'll have to deal with many languages.

Coupled with:

> "Weird function definitions" -> most of the time, functions are a coding smell to me. I always managed to not use them (or maybe I used one or two? I don't remember) and that's all fine. Projects that define a ton of functions get unreadable extremely quickly.

is weird. If you can't handle a lot of functions, you'll struggle with many languages. If a lot of functions is a code smell, then the problem is with the language.

> If a lot of functions is a code smell, then the problem is with the language.

Let me kindly disagree :). You do not use a build system to write a complex program, you use it to call a compiler.

You could run your compiler manually, but it doesn't scale. You could write a shell/python/lua/etc script that scales better, but nobody else will know it (and chances are that nobody will want to learn about it).

By using a build system (autotools, cmake, meson, gradle, ...), you agree to use a standardized API to call your compiler. It doesn't really matter what API it is; what matters is that it is standardized: once you know it, you can build all the projects that use it.

Now it is true that CMake projects are often a mess. Either because it's used incorrectly, or because it's doing a lot of magic with custom functions (and therefore it looks more like a custom shell script than a CMake project).

Do I mean that CMake is perfect? Certainly not. But it doesn't suck either. And I see a whole lot of criticism coming from people who write messy CMakeLists. For a criticism to be constructive, it has to be informed.

Yeah, cmake sucks. But it sucks once, then you get used to the cmake standard for your company and dependencies. And it sucks a lot less than anything else.

And cmake is the backbone of a lot of other build systems, being so popular. So it makes most Cpp projects straightforward to integrate.

I pull my hair out at this stuff too, but no more than any other tool required for configuring a workspace.

With the full caveat the CMake has to solve a design space that has a lot of legacy it still just makes a lot of unintuitive choices. I have to go look up the command line for generating vs building every single time I use it, and I've been using it for many years at this point.

Rust benefits a bunch from second mover advantage here but cargo is just soooo good in comparison. Sane defaults, descriptive commands and stuff like cross compilation that can be hell-on-earth with CMake/etc I find actually easier in cargo + cc crate + build.rs for small/medium libraries.

I have to go look up all kinds of things whether I'm using Rust, Cpp, or python.

The package manifest for rust projects isn't as straightforward as some imply, but yeah, better than cmake!

However the comparison isn't totally fair. When building a cmake project, it's muscle memory to go `cmake ..` out of source, then do it again and tab complete to choose the build options. That's 99% of the work I have to do when pulling dependencies.

If you want a turnkey package build, just use vcpkg for Cpp. And guess what, it'll sit right on top of cmake.

What TFA is talking about is a 5% or less workflow: making a new package from scratch when you don't have internet connectivity or don't have a bespoke cmakelists.txt to reference. Makes for a nice blog post, but that's not a common dev workflow.

If you are doing FOSS, the suckage will spread to everyone downstream of you.
CMake works fine if you keep things as simple as possible which often means going against best practices. For instance, this is my template for a C project using SDL, keeping all of my code and libs in their own local hierarchy:

    set(PROJECT "ProjectTemplate") #this can't have spaces
    set(CMAKE_VERBOSE_MAKEFILE ON)
    set(CMAKE_BUILD_TYPE "Debug")
    set(ARCH "x64")
    set(PROJECT_ROOT "${CMAKE_CURRENT_LIST_DIR}/project")
    set(PROJECT_SRC "${PROJECT_ROOT}/src")
    set(PROJECT_INC "${PROJECT_ROOT}/include")
    set(PROJECT_ASSETS "${PROJECT_ROOT}/assets")
    set(PROJECT_LIBS "${PROJECT_ROOT}/libs") #third party libraries
    set(SDL2_PATH "${PROJECT_LIBS}/SDL")

    project(${PROJECT} C)

    add_executable(${PROJECT} "${PROJECT_SRC}/main.c") 
    set(PROJECT_SOURCE_FILES "${PROJECT_SRC}/main.c")

    target_sources(${PROJECT} PUBLIC ${PROJECT_SOURCE_FILES})
    set(SDL2_INCLUDE_DIR "${SDL2_PATH}/include")

    target_include_directories(${PROJECT} PUBLIC ${PROJECT_INC} 
      ${SDL2_INCLUDE_DIR})

    set(SDL2_LIBRARY "${SDL2_PATH}/lib/${ARCH}")

    target_link_libraries(${PROJECT} "${SDL2_LIBRARY}/SDL2.lib" 
      "${SDL2_LIBRARY}/SDL2main.lib")
    
    file(GLOB_RECURSE PROJECT_DLLS "${SDL2_LIBRARY}/SDL2.dll")

    add_custom_command(TARGET ${PROJECT} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_DLLS}
      "$<TARGET_FILE_DIR:${PROJECT}>")

    if(EXISTS ${PROJECT_ASSETS})
      add_custom_command(TARGET ${PROJECT} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_ASSETS}
         "$<TARGET_FILE_DIR:${PROJECT}>/assets")
    endif() 
Is this the way it's supposed to be done? No. Is it setting someone's teeth on edge? Probably. Is it cross-platform compatible? No, but I don't need it to be, I just need it to build for the specific platform I'm using, which is Windows. Will it build? Yes, and that's all that matters.
I would argue that if the best practices don't work fine, maybe you are not actually following the best practices.

But I agree with the "keep things simple" (e.g. don't define custom functions), but I don't think that your snippet does that (ahem, I see `add_custom_command` there) :)

>(ahem, I see add_custom_command there) :)

It's worth it when you're working on assets or lua scripts and want to import any changes for each rebuild.

That’s what I do as well. You can do pretty much all you need to do with add_custom_command and add_custom_target. I use it for Typescript, Java etc. and it works fine.
Sure, but do Makefiles suck relative to CMake?
They solve different problems. CMake can generate Makefiles, among others.

autocrap, oh, sorry, autotools and CMake are software confguration systems, not build systems per se.

If you know your environment Makefiles are way to go.

If you need to build your portable software on 5 different OSes (and 3 versions of each of these OSes) with 6 different compilers... Good luck with Makefiles.

I find for CMake one still needs to separate aarch64 and amd64 build configurations. =)
I didn't say, that CMake solve this problem well :-)
If anyone knows CMake and wants to get rich, I’m pretty sure Citadel is still trying to hire a build systems wizard for ~4XXk. I got the offer but balked at the thought of writing cmake every day for the next ten years
I just wish there was something to CMake what TypeScript is to JS. Fully compatible with the existing ecosystem but saner semantics.
I don't really care, I just need to learn the thing that all the projects are using and if that's Cmake then that's what I have to learn.
This. I am happier dealing with a clean autotools config than with a meson mess.

If it's clean, then I'm fine with basically everything, as long as it's not too exotic (it's annoying to have to learn one build system for one specific project).

Most of the projects I see these days are using cargo.
I spend my time in Java. More than a few times I have cursed out Maven.

But it seems like whenever I go to another compiled language I end up wishing I just had Maven. Extensible, widely adopted, builds + dependencies.

I remember autotools + make, and that didn’t do dependencies for me. CMake doesn’t look much better. NPM/Yarn/whatever is a mess too. I don’t even remember what Haskell uses. Go wasn’t bad but that was early days before dependencies were added (which was a problem in itself). I haven’t looked at it lately.

Standard repos. Standard dependencies. Standard layouts. Standard plugins. It can be a bit much, yeah it’s XML, and it’s over engineered for many projects. But I always seem to end up finding I hate Maven much less than whatever language X uses.

Autotools are a mess from a developer point of view, but are the easier system to use for the user. Building an autotools project is simple, doesn't require dependencies since the output is the configure script that is a shell script.

   ./configure --prefix /usr/local
   make -j$(nproc)
   sudo make install 
I learned these commands when I was 12 years old, at that time building a CMake project always seamed an impossible task to me, they are all different and not standard.

Anyway at work I use CMake for the fact that I don't publish my software openly thus it doesn't really matter.

Yeah, I think it's underappreciated by developers how nice autotools makes the end user experience. Before I was a developer, I had the same experience trying to build cmake project. They just never seemed to work right.
If it works, autotools is fine. I've had to wade through a bunch of autotooled projects for which it didn't work. Those scripts are no fun to debug.
I agree that Autotools is fine, but the CMake equivalent of your snippet is not that far with CMake:

    cmake --CMAKE_INSTALL_PREFIX=/usr/local -Bbuild -S.
    cmake --build build --target install --parallel $(nproc)
You also need "-DCMAKE_BUILD_TYPE=Release" (or some other value). Otherwise, it will use a toolchain-specific default, which often means "no optimizations and no debug symbols".
The Autotools do have dependencies: they require a functional Unix platform to run, including a shell and a fair number of common command-line tools.

This is the number one reason people use CMake. It's a single binary that runs on every platform with no external dependencies, notably including Microsoft Windows. This makes it much more portable. CMake is itself a shell.

CMake solves the problem of not crafting Makefiles manually. It's far from ideal, but it's better than the things it tried to replace. The only alternative that tried to solve the same problem around the same time is MSBuild. I'm not necessarily against MSBuild (GUI support is worlds better at least) but I think we've all seen enough XML in our lives already not to switch to that for our build system.

CMake looks confusing because of its many predefined constants/variables/methods, all in SHOUTY_CASE but once you get past that, it seems to me like it's Good Enough™.

I think Meson is better than CMake in terms of syntax but it's not as popular (yet). It doesn't fix all the criticisms this article brings up but I found it nicer to work with.

If that doesn't suit you, you may like to look into Gradle; unlike CMake and friends, it doesn't invent a new programming language for its compilation, instead repurposing the Kotlin language for making dynamic build scripts. A very powerful setup if you want that level of the customisability.

IME, almost no one needs arbitrary build DAG power. And if they get it, it gets tangled up over time. Even with CMake, I end up having to bring back "fraying" code over time to keep things sensible on the projects I maintain. Too many "what's wrong with this one exception to the rule?" cases that end up causing a mess if they're not kept under control.

I liken it to software processes and "research" code. Researchers are focused on their task at hand and things like TDD, sensible commits, releases, refactoring, not using magic numbers, etc. are all put to the wayside in the pursuit of their actual goal. "Regular" developers are very similar when it comes to their build systems and being "too creative" there is just as harmful.

FD: CMake developer

The biggest hurdle I had with cmake was the documentation. It is needlessly terse and pedantic, and lacks proper examples. However, it was wildly better than the documentation for any other build tools.
not one mention of cmake's real strength... it is cross platform and constructs project files for the build system of your choice. if you have people using visual studio, they can continue to use it as it will generate project files for the ide, if you have people on unix using make, it generates makefiles, i think it even supports obscure things like jam.

yeah, it's a real weird language, but i've been able to make it work for all sorts of weird things, from custom auto generation of documentation from comments in source to using obscure build tools to build extensions and bridges to/from proprietary software systems.

autotools solves portability across loads of unix variants with bizarre changes in their standard libraries, cmake solves portability across completely different platforms.

protip: buy the book. read it.

> it is cross platform and constructs project files for the build system of your choice. if you have people using visual studio, they can continue to use it as it will generate project files for the ide, if you have people on unix using make, it generates makefiles, i think it even supports obscure things like jam.

But these days a lot of those systems support CMake natively. E.g., Visual Studio can open CMake-based projects directly, you don't have to generate a VS project file. I'm curious as to how many people still use this capability directly; i.e., how many people use CMake to generate a platform-specific build file and then actually work with that file. I think probably the most common use for CMake is to generate a build file and then immediately build it. To probably 90% of CMake users, it would make no difference if CMake ran all the build commands itself, directly.

yeah that's a recent thing though. it supports a bunch of customized toolchains, has backwards compatibility for major VS releases over the years (being able to use older compilers can be important for large projects sometimes) and support for generating project files for a handful of IDEs. [1]

maybe you're right and the generator support will become less relevant, but when i think of cmake, i think of a build system generator that makes potential cross platform ports easier. support for generating IDE project files for multiple IDEs is a nice feature for developers as well.

[1] https://cmake.org/cmake/help/latest/manual/cmake-generators....

(comment deleted)
I agree with some other posters complaining that half of the post regards how syntax sucks. I don’t need glorious syntax in my build system. It’s a build system. I want to do the bare minimum work to get my code correct and get back to writing “real code”.

I used to work on a project that, at first glance, seemed like a perfect candidate for CMake: portable code, compiled with three different compilers (GCC, another GCC, and another GCC-ish for VxWorks) for four different platforms (x86 Linux, bare metal MIPS, FreeRTOS ARM Cortex M0, VxWorks ARM Cortex A53). It constantly felt like trying to shove a square peg into a round hole. Our developers would spend days in “CMake hell” regularly.

One issue we had was the verbosity. For us, a specific platform implied a specific architecture, a specific compiler, a specific operating system, specific auxiliary devices, etc. Having developers remember to do -DCMAKE_XXX half a dozen times for every build wasn’t realistic so we scripted it because CMake didn’t support the idea that a toolchain file wasn’t passed on the command line (that I’m aware of).

Warnings were another issue. Yes, yes, I know, you’re not supposed to declare warning flags in toolchain files. Too bad that doesn’t scale to many developers (same reason as above).

I also disliked that it generated recursive Makefiles. I could not find a way to beat this without changing the directory structure, which was for our project very important (certain portions of our code were standalone libraries only deliverable to certain customers, with different implementations for their specific platforms). This made builds SLOW. I flattened the Makefiles by hand once just for laughs and cut off 60% of our build time (a lot of the build system was networked drives mounted over NFS).

CMake isn’t that bad, though. For simple use cases, and small projects, it’s convenient. I just wouldn’t use it at scale for complex projects like above.

Deep secret of CMake: it's a line by line interpreter, so you could have worked around the toolchain issue by setting the relevant variable as one of the first line in the project.

However, you're supposed to set the toolchain on the command line and toolchain files are only intended to specify what's necessary for the toolchain. Setting defaults is considered a bad thing.

> Having developers remember to do -DCMAKE_XXX half a dozen times for every build wasn’t realistic so we scripted it because CMake didn’t support the idea that a toolchain file wasn’t passed on the command line (that I’m aware of).

You're supposed to use `-DCMAKE_TOOLCHAIN_FILE` to specify how to use a toolchain like this.

> I also disliked that it generated recursive Makefiles.

It doesn't make them in the "recursive make considered harmful" way. It is a static 3-depth graph (UI -> target graph -> target rules). Or you could use the Ninja generator.

FD: CMake developer

CMake is good enough for most purposes. Would it be better if its creators had gone with, say Lua, rather than their own DSL? Sure...and this may still happen [1].

Also, autotools does not require the GNU file structure if you pass "foreign" to AM_INIT_AUTOMAKE. In this case, all you need is your configure.ac and your Makefile.am's.

[1] https://gitlab.kitware.com/cmake/cmake/-/issues/19863

Given CMake's compatibility guarantees and Lua's…lack of it, we'd have been stuck with Lua 4.x or something (or supporting every version of Lua since then at the same time…nobody's idea of "great" IMO). If CMake had chosen an existing language when it started, it'd likely have been Python 2.x, Perl 5, or Tcl. Not sure that any of these would have been strictly better decisions in today's world than the status quo.

FD: CMake developer

What bothers me about CMake is that I don't know how to use it and I can't find anybody who actually does.

Seems like CMake configurations just kind of "happen" by trial and error, perhaps starting with a configuration copied from another project. It's not a language, it's a thing that you hack on to get the job done.

Another gripe is often when I look up "how to do X in CMake," the docs refer me to a feature that is more recent than the CMake packaged in common distros and for which there are few (no?) real world examples.

If somebody has a more constructivist approach to CMake, I'd like to try it.

IMO, the way to structure things is around the "usage requirements" model where a target declares everything needed to know how to "use" the target. Flags, libraries, includes, etc. The guide[1] goes through the basics at least; it can get a lot more complex with generator expression usage.

FD: CMake developer

[1] https://cmake.org/cmake/help/latest/guide/tutorial/index.htm...