8 ms·
CMake Part 1 – The Dark Arts
- timeinput 5y agoThis is a pretty nice article. CMake is a pretty nice tool and this is a good article for its good parts. One thing I *hate* with build systems is having to enumerate all of my files. I have a file system. It knows about the files. If I organize my code appropriately (say a lib, inc, and prog directory) the organization says how to build the source code. I often make my build system support finding all the files in directories, and enumerating them and using them for the build targets. Some times that scheme bites me when projects get very large, since it can take a while to `find` all the files, but those projects suck to enumerate all the files in too.
- ahartmetz 5y agoThe main reason why not enumerating all the files in the build system is a bad idea is that the build system won't know to rerun itself and re-scan dependencies after you added a file. If you do enumerate the files, you need to change a build system file to add an entry for the new source code file, and that tells the build system to rerun itself and re-scan dependencies. And in the grand order of things, adding a file to the build system is a triviality compared to actually writing the code in it.
- gravypod 5y agoAnd, in general, adding a source file can automatically insert a record into the build system if you follow a convention.
- lbayes 5y agoCouldn't a build system use a hash of the accumulated files as a cache key and rebuild it's internal state when that changes? I'm not seeing a big downside, but maybe I'm missing something obvious.
- kevin_thibedeau 5y ago> CMake is a pretty nice tool It's pretty powerful. It'd be pretty nice if it didn't have such a god awful DSL.
- rualca 5y agoFrankly, with the inception of modern CMake over a decade ago, the only reason anyone has to stray out of cmake's DSL happy path, comprised of all the tried and true declarative bits, is whether a) they have to do a very niche/specialized/extremely custom extension to CMake, or b) they have no idea what they are doing. More often than not, b) is the case.
- MaxBarraclough 5y agoYou and I discussed exactly this 3 months back. I won't restate my responses here, but for anyone curious: https://news.ycombinator.com/item?id=26722717 https://news.ycombinator.com/item?id=26722717
- mucholove 5y agoI use GNUstep on Linux and I generate my main GNUmakefile. They have a preamble file I use that is only generated if it does not exist and it allows me to keep all my settings. The biggest drawback is that I haven’t been able to keep private headers private so everything is public. Would only really be a problem if I was publishing a framework for others to use. I love this system. Makes it very nice to have everything organized in folders as needed and then BAM just run cd/generate/make and done. How do you differentiate which headers should go where in your script?
- yongjik 5y agoI've been burnt by that convention pretty regularly: (1) build automatically scans and adds all files in a directory (2) I write a quick script foo.py in the directory to check something (3) Boom, binary contains foo.py I try to manually enumerate all files whenever I touch a build file.
- ungamedplayer 5y agoA better solution is to a checkout of your build, then you wont have foo.py and you can be sure you haven't missed anything.
- yongjik 5y agoThat would work only if you always build after committing all your changes, which is IMHO another anti-pattern.
- ungamedplayer 5y agoEr, but OP's tars up and ship after every change? Get out of here with your antipatterns.
- wheybags 5y agoThey recently added a CONFIGURE_DEPENDS flag to file(GLOB...), which will automatically rebuild the file list when new files are added.
- humanrebar 5y ago...which comes with a cost (extra reconfiguration of the project), but it 's worth it for many projects.
- piggubiggu 5y agoGreat write-up. I learnt a lot.
- zelly 5y agoCMake is legitimately the worst software I've ever used. cargo > Bazel > autotools > "the IDE" > handwritten Makefiles >>>>>> build.sh >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> CMake
- enriquto 5y agohandwritten makefiles have a certain kind of deep, pure beauty if you are in the right mindset
- rualca 5y agoHandwritten makefiles can be the best option on the table in scenarios not involving a lot of boilerplate code or having to do any platform check at all. 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.
- enriquto 5y agoMaybe it wasn't your intention, but your comment is the most scathing critique I've ever read of cmake. 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!
- rualca 5y agoI'm not sure you understood what I've said at all. 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?
- aidenn0 5y agoTFA talks about CMake being widely used in embedded. This seems to be a difference between Europe and the US. It feels like every single embedded project I've encountered in Europe in the last decade uses CMake, and I've never seen an embedded project in the US that uses it. It's the single biggest difference I've noticed. C++ is certainly more popular in Europe, but you see plenty of C projects in Europe and plenty of C++ projects in the US.
- yakubin 5y agoWhat do embedded projects in US use instead?
- pjmlp 5y agoIt is debatable how embeddable that is, in any case, official build system for NDK is CMake (ndk-build is kept around for backwards compatibility purposes), so no one doing US projects stuffing Android in places that don't look like phones? Or GUIs on medical devices using Qt? Cause there are some, so I would expect US companies to also having a go at it.
- rualca 5y agoI wish all the CMake haters invested a fraction of their energy putting together a tool that they feel was superior to CMake, or at least a better alternatice. CMake has been around for a few decades, and perhaps a dozen alternative makefile generators and higher-level build systems already popped up, but still each and every single one of them failed miserably in gaining any traction. Why is that, given that CMake is indeed far from perfect? The truth of the matter is that CMake is, by far, the best buildsystem/makefile generator for C and C++ projects that there is right now. And this has been the case for a couple of decades. Not only does it work reliably but it is also extremely easy to setup and use in the happy path. With cmake anyone can easily create a project that includes multiple libraries and executables that consume system libraries in a matter of minutes right on their first try as a "hello world" onboarding project, and that project will work on multiple platforms and on any CICD pipeline. I would very much prefer to see a fraction of the energy wasted in hating CMake being channeled into making a cmake alternative. But for some reason, all we see is hate. Why is that?
- humanrebar 5y agoBuild systems are harder and more complicated and messier than user of build systems understand. Say a group of smart engineers start designing the perfect build systesm. Usually there is some sort of design constraint added for correctness that works for, say, 99% of projects, which seems like a good tradeoff. Until it turns out that openssl is in that other 1%. Or maybe the build system assumes everything can build from source, which maybe works for 90% of cases, forgetting that proprietary vendors often ship prebuilt binaries. Or maybe the build system is written in <actual scripting language>, which means <actual scripting language>, written in C, now needs a different build system. Also, <legacy OS> doesn't have a compatible version of <actual scripting language> available. Or maybe the build system requires a lot of boilerplate to support the typical project structure of <large organization>. Instead of having verbose build recipes in hundreds, thousands, or tens of thousands of projects, <large organization> just sticks with its legacy custom build scripts. The fact of the matter, CMake is pretty good. It lets you do basically anything you need to. It has basically no dependencies to build and use it, so it works anywhere. And it has extensibility that's actually fairly rare in build systems. Anyway, my theory is folks see the downsides of some tradeoffs CMake made (awkward basic DSL) without appreciating the upsides (available everywhere), especially because they don't realize "works on my project and box" doesn't cut it for maintaining projects in the C and C++ ecosystem. I'll be bold enough to predict that the build systems of Go and Rust will be just as complicated if they ever need to start supporting things like juggling BLAS versions.
- humanrebar 5y ago> [Modern CMake] has added to the confusion over using CMake because there are many resources on the web that refer to the legacy style of CMake. Has anyone else found this to be the case? All the resources I've seen in the last five years or so have been pretty consistent about encouraging modern CMake style, which in my mind encompasses: - declare targets and set properties - generator expressions - support the default workflow - use find_package to import targets I do see some misinformation from time to time about using commands like `include_directories` when `target_include_directories` is clearly the better style now, but I guess I don't consider "good style" and "modern CMake" to be the same thing anymore.
- jjgreen 5y ago"CMake, you say? Yeah, CMake is like smashing your face on high quality pavement. You can admire the stonework while the blood pours down your face." Pieter Hintjens, http://hintjens.com/blog:79 http://hintjens.com/blog:79
- humanrebar 5y agoThat's certainly a tweet-sized sentiment! I'll point out that the article was written "2430 days ago" and uses a CMakeLists.txt example that looks like it. The article then goes on to announce Yet Another Build System that doesn't seem to have gotten any traction.
- vyskocilm 5y agoZproject is not a build system. It's more like package.json esque thing for C. We used it on a past and it was capable to generate auto tools (or c make) build recipes, Debian or rpm packaging, ffi bindings and more. But you're right it got almost zero traction outside of zeromq.
- lbayes 5y agoThis. I'm stunned this kit was ever created with the shape it has, but even more stunned a second person agreed to use it. It completely blows my mind that this demoware has made inroads anywhere.
- lbayes 5y agoI had my first real exposure to CMake earlier this year. It demos beautifully, but quickly becomes an outrageous collection of side quests to find the secret key. What collection of hidden methods, global constants, environmental variables and insane incantations must I assemble to cross compile this software? None. The answer is, None. The best I was able to find, was get the whole artifice running on your actual workstation, then get it (and an entirely different tool chain, including IDE's?!!) up and running on each target platform, dust off your sneakers to go sit in front of another computer, fire up an IDE and find it's build button. I know it's not, but CMake somehow manages to feel like a solution created by hand wringing, cat petting, volcano living, mustachioed, cigar-smoking proprietary OS and IDE vendors. OTOH, zig cc leaves me with a single tear of joy and wonder sliding down my cheek like a framed Velvet Elvis. Update: Also, premake isn't terrible.
- mbeex 5y agoSome time ago, I - a seasoned C++ and Python developer - became part of a team, redesigning build and deployment aspects of a complete embedded code landscape, embracing a lot of developmental activities, projects, whole product lines etc.. I think most people who recommend alternatives completely underestimate the degree and extent of specific compiler, tool, library, IDE, and general native-build environment knowledge that CMake has swallowed and incorporated over its years of existence and continues to do so. Including all these quirks & particularities of the endless number of components, software artifacts and tools it handles. This is the whole reason for his success and the one thing no swift, elegant, new-paradigm new player can surpass short-, mid- or - in some cases - even long-term. Most of the time you can tell the real experience of someone judging CMake simply by his kind of troubles with it. Admittedly, the syntax is ugly and often inconsistent. Consider a list 'alist' and depending on context you can or must reference it as either alist, ${alist} or "${alist}" - terrible, true. The most complex data type is aforementioned list, often as under pain bearable nested variant. Math is cumbersome, no unicode support for string manipulations like positions, length calculations, the list is going on seemingly ad infinitum. But you can learn this rather quickly and when you write CMake code for some weeks you will become accustomed to it. In the meantime, other levels of annoyances begin to appear. For example, the allowed context of generator expressions is inconsistent, incomplete and sometimes - from a cmake writers point of use - almost artificially limited. Take add_custom_command: It allows for GE's in his DEPENDS and also COMMAND sections - but not as argument for OUTPUT. But wait, starting with CMake 3.20 it does, but: " Arguments to OUTPUT may use a restricted set of generator expressions. Target-dependent expressions are not permitted. " Unfortunately, those are often exactly what the developer is looking for. Reason here is as in many cases the deeply ingrained two-pass configure-generator nature of CMake. For any real project, state becomes quickly important. Diving through many levels of sub directories and maintaining/conveying information between the associated CMake projects becomes far from trivial in no time. And no, cache variables are not the solution. Another issue is the interaction with higher languages in CMake code. Most people start quickly with execute_process(${MY_PYTHON} ...) in order to handle more challenging topics. Problem is the lack of smooth communication of the results without workarounds like temp files, whatever else. Also, any dependency requirements not covered by the standard cases, might it affect rebuilds, reconfigures or regenerations, requires deeper knowledge of CMake's actual dependency resolution mechanisms. Often only inspecting his time-stamping bookkeeping or exploiting his trace / graphviz / file-api output will help here (neglecting source code inspection, this is rather rarely required). In principle, the task requires a fully-fledged programming language - but containing all the accumulated knowledge of CMake about his subjects. Not an advertisment, but for any beginner I can only recommend Craig's book https://crascit.com/professional-cmake/ https://crascit.com/professional-cmake/ It continously integrates changes from new versions. He is also always helpful in CMakes own discourse forum and gitlab issue tracker.