9 ms·
Modern CMake short tutorial and best practice
- gravypod 8y agoWhile CMake is verbose I don't think it's terrible. The complexity of building a simple flat source project vs a multi-stage build project scales very well. One thing that amazed me was how simple it is to script up the creation of generated libraries. For school I had to generate a build step that would allow me to embed Duktap and link to a library called Glad. Both needed to be generated with a python script. Doing this was dead simple [1]. I didn't have to do anything crazy to locate the path to python, the source folders I want to output into, etc. CMake has magic for that. Granted I spent just as much time reading the really horrible docs to find out how to use these magic features as it took me to complete the assignment. I think like many amazing technologies it's blocked by a steep learning curve and a long long history of worse ways of doing things. Every time you google for how to do something you'll get an answer from a different part of the project's lifespan. [1] - https://github.com/gravypod/solid-snake/blob/master/CMakeLists.txt#L22-L41 https://github.com/gravypod/solid-snake/blob/master/CMakeLis...
- therealjumbo 8y agoThis is a great introduction to CMake for a single project/repo. You could add a section on installing the project. Although that probably isn't required for the student projects. What I'm still searching for is a nice way to build multiple repos, which have dependencies on each other, in a cross platform way, that's distribution friendly. What I mean by distribution friendly is: you shouldn't be bundling your dependencies. But it's nice to compile your own dependencies and link to that for debugging. So I want something that easily allows the upstream developers to download, compile and debug their dependencies, but doesn't do that when distributions (Debian, Fedora) go to compile and release your code. And it'd be nice if this was part of the CMake, so new dev's don't need to run some bash script to get setup, or follow a long list of instructions in a document to download, compile and install said dependencies. I'd also like to keep my existing CMake as horrible as it is at times, I'm not sure if switching to Meson is really worth the effort. Especially since I'm still stuck with C/C++ anyways.
- pfultz2 8y agoDaniel Pfeffier’s effective cmake talks about how to do that. Setup each project standalone and get the dependencies with find_package. Then create a superprojects thats add each dependency with add_subdirectory and override find_package to be a no-op for dependencies added with add_subdirectory, since the “imported” target is already part of the build: https://m.youtube.com/watch?v=bsXLMQ6WgIk https://m.youtube.com/watch?v=bsXLMQ6WgIk Now, overriding a builtin function is not the best idea so in boost cmake modules we have a bcm_ignore_package function which will setup find_package to ignore the package : http://bcm.readthedocs.io/en/latest/src/BCMIgnorePackage.html#bcm-ignore-package http://bcm.readthedocs.io/en/latest/src/BCMIgnorePackage.htm...
- therealjumbo 8y agoJust watched that video, long but awesome. I'm not sure on how exactly his strategy is supposed to go, but it sounds like the superproject is another repo. I don't really want that. What I'm thinking right now is to use the same overall idea, but instead of a superproject, I use the same repo, and use: https://cmake.org/cmake/help/latest/module/ExternalProject.html https://cmake.org/cmake/help/latest/module/ExternalProject.h... But put that behind a flag, that defaults to off, so it doesn't interfere with the distributions. And it supports patching so I can patch whatever dependency's CMake, in the event that they don't (yet?) support the same strategy so it can work transitively without having to boil the ocean. Granted, you would need to write patch files, for basically all your deps initially because nobody else is doing it that way. For reference, I'm trying to help convert an existing open source project from autotools to cmake, but at work I'm the resident cmake expert, and we have multiple products, which effectively are built as different 'distributions' (not always Linux based) so I've been searching for a good way to do this for a while, even though I just started contributing to OSS.
- slavik81 8y agoI was working on this topic a few years ago and one of the things I noticed was that a lot of software patterns that work on the source code level can also be applied at the library or project level. What you're describing is basically Dependency Injection and the super-project is a Container. It seemed like such a good idea, but I quit working on large software projects about the time I thought of it, so I never got a chance to actually try it outside of toy projects. I'm glad to hear that somebody else independently discovered and pursued the idea. If anyone has written about how adopting this approach has worked out for them, I'd love to read it.
- waynecochran 8y agoMake is horrible because it does not handle spaces in paths Putting spaces in pathnames is idiotic to begin with. I have written Perl scripts that are 3x more complicated just to deal with spaces in pathnames. You might as well blame Make for not handling UTF-32 characters in pathnames -- I mean, someone might want to put a GREEK CAPITAL REVERSED DOTTED LUNATE SIGMA SYMBOL (U+03FF) in their path -- Make would suck if it didn't allow this. You missed the most egregious problem with Make -- the fact that commands must begin with a friggin' TAB! No other whitespace will do. Think of every manual writer who has to somehow convey that the whitespace you (don't) see is a TAB.
- tom_ 8y agoThe baffling thing about this opinion, at least to me, is that it's actually difficult not to handle spaces. Once you've got your path-with-a-space past the well-known issues involved with handling these in your average shell and/or make - which are stupid issues, but it's probably too late to do anything worthwhile about them by now - what's the problem? What are you going to do with paths that makes handling spaces so hard? This applies equally to Unicode characters. (Which I'd actually expect Make to handle OK. I doubt it uses UTF-32... presumably it's just char stars internally, like most Unix tools, so I'd have thought it would handle UTF-8 just fine. UTF-8 is a bit inefficient, but extremely well-designed in this respect.)
- nikofeyn 8y ago> Putting spaces in pathnames is idiotic to begin with. it’s only idiotic in the sense of tools not working with them properly. spaces are allowed in paths and filenames in most filesystems, and so tools written to handle paths and filenames should handle spaces. spaces carry no special path information, so it’s a little weird they are ignored by many tools. it would be crazy to think of tools not handling a “b” or something. and i agree with the tabs thing. although, it was pointed out to me that in a newish version of make, you can override this behavior with a flag. i doubt it works well though because of makefile compatibility issues.
- berti 8y ago> it’s only idiotic in the sense of tools not working with them properly. It's idiotic because it's annoying for things like tab completion (technically another tooling issue I suppose... but why bother going against the grain for little/no benefit).
- ddavis 8y agoI think it’s recommended to avoid set(...) in modern/best practice cmake because it’s global. Use the target_* functions.
- therealjumbo 8y agoThe author does discuss this in a footnote: https://codingnest.com/basic-cmake/#fn4 https://codingnest.com/basic-cmake/#fn4 In this case, I think I agree. Otherwise ya, try to avoid set. Except for CACHE variables, I think.
- striking 8y agoIf you liked this piece, please also consider reading https://pabloariasal.github.io/2018/02/19/its-time-to-do-cmake-right/ https://pabloariasal.github.io/2018/02/19/its-time-to-do-cma..., which is a modern (2018) guide to what you should and should not do in CMake. It's very enlightening.
- wheels 8y agoIt still boggles my mind that CMake was the thing that won for the next generation of build systems. Its syntax is probably even worse than bash (except that it didn't have decades of compatibility to blame that on), making it the single worst language I've ever written code in. I struggle to understand how one could sit down to create a language and come up with something that bad. There was apparently at one point effort to replace its frontend with Lua, but that sadly never took off. (I, like everyone else, still hold my nose and use it, but man ... like ... bwa?)
- weberc2 8y agoI absolutely agree. This is the number one reason I don't do any serious development in C or C++. Here are some grievances that come to mind: * Pretty much everything is a string * One giant namespace with no notion of imports * No sane dependency management; just uses whatever is laying around the system * IIRC source files have to be listed in the CMake file individually (or at least that's what I recall to be the best practice) * Everything is a one-off function. [Seriously, CMake comes with functions for Qt projects][0] and other popular libraries. * It's supposedly cross-platform, but you need to take care if you want it to generate sane, usable VS solution files. IIRC, it would create a VS project for every subdirectory or source file by default. * I forget whether CMake itself is slow as hell or if it just generates super slow Makefiles, but in either case, it is painful [0]: https://cmake.org/cmake/help/v3.0/prop_tgt/AUTOMOC.html https://cmake.org/cmake/help/v3.0/prop_tgt/AUTOMOC.html
- tom_ 8y agoListing source files individually is what you're supposed to do, because not all build tools support globbing for files. To support this properly, cmake would need to re-run on every build to regenerate the files list... well, it's probably doable, with some work, but I expect there's just not the demand, I expect because most people are like me and would prefer to list their source files out by hand so they know where they stand. The Visual Studio projects it creates, at least for my projects, have a VS project per target. That's just how Visual Studio works. You do tend to end up with a lot of projects in one solution this way, which is something most people don't do when setting projects up by hand - but with CMake picking up the strain there's no reason not to. (It's also very convenient for running tests in the debugger. One target per test, select it as the startup project, and off you go.) As for makefiles, I haven't noticed CMake's being noticeably slower than any others I've seen, though I'm sure it's possible. They are rather larger than most Makefiles. (If you're able to switch to Ninja, that comes recommended.)
- Koshkin 8y agoWhile I appreciate the need for DSLs, in many cases I feel like I'd rather use an API. At least, an API imposes no constraints on the features of the language itself. (So, imagine a DOM for VS solutions and projects; writing your own script would be a breeze...)
- Sir_Cmpwn 8y agoHonestly CMake is just as bad as it's predecessors. Today I use meson, which isn't perfect but is far better than CMake.
- AlexMax 8y agoHow does meson's find_library compare to CMake when it comes to finding libraries on Windows? That, and the very nice GUI tool that comes with it are my two killer features of CMake.
- Sir_Cmpwn 8y agoI don't use Windows and don't care about Windows, you'll have to see for yourself.
- AlexMax 8y agoThought so. If you're primarily a *NIX user, there are a bunch of reasonable build system alternatives out there, but if "supporting Windows" is even a little bit of a priority, I have found CMake to be far and away the least painful way to build multi-platform software on Windows, especially if you're a novice. Until Meson even approaches being as easy to use on Windows, I feel like it's going to continue to be second fiddle.
- Sir_Cmpwn 8y agoIt may be second fiddle for people who care about Windows, but thankfully they seem to be few and far between these days. There's no reason to support Windows when they won't even pretend to care about standards compliance. Although even then, having to draw the ignorant masses of Windows devs out of their GUIs would be quite a task.
- jcelerier 8y ago> There's no reason to support Windows when they won't even pretend to care about standards compliance. There's a lot of standards that windows support and linux does not though, for instance a lot of protocols used in multimedia works, art installations... A simple thing such as sharing a video buffer in the GPU between two processes is trivial in Windows or macOS and a damn pain on current desktop linux (dunno in wayland). And I say that as a hardcore linux user.
- gkya 8y agoI'd suggest everyone to check out bmake. It has a very nice standard library of makefiles with which often your makefile can be a couple lines long, one of which just includes the relevant library.
- izacus 8y agoIt's it fully compatible with CMake and will consume thousands of CMake built C/C++ libraries out there?
- armitron 8y agoCMake is absolutely terrible if not destructive for non-trivial projects that require frequent build system updates and restructuring (especially those tied to cross-compilation). GNU Make might have its share of issues but compared to CMake, it's dead simple and I've never once in 20 years of programming encountered a build issue I could not debug. CMake has had me throw up my hands and give up in despair far too many times. It boggles the mind that people continue to use such a rotten tool. Probably because it looks attractive, superficially, but if one examines it in more detail any possible justifications for using it should completely fall apart.
- ridiculous_fish 8y agoHow do you use create a portable non-trivial project with make? How do you do discover what libraries, headers, functions, etc. are available?
- mcguire 8y agoThat's what the autotools are for. Yes, they're horrible. The problem is horrible and the autotools are worse. But they work.
- ridiculous_fish 8y agoAutotools do work, but what autotools user can sneer at cmake? So I guess OP is using something else, which is why I asked.
- tom_ 8y agoIt's indeed worth noting that cmake only supports one toolchain at a time, so it's currently not possible to build for the host while cross-compiling. This is a complete showstopper for certain types of eminently sensible build process, so if you've got one of those then you should look elsewhere. In other respects, my experience has been exactly the opposite of yours. Right down to the supposed superficial attractiveness of CMake ("LOL", that's all I can say - shit's a fucking disaster zone at first glance!) that turns into horror on closer examination. (Since in my view, it actually mostly makes the right decisions internally - you just need to get past the spitefully bad scripting language.)
- dewyatt 8y agoThe generator expression used here isn't necessary: add_test(NAME plain-run COMMAND $<TARGET_FILE:vector-test>) You can just use: add_test(NAME plain-run COMMAND vector-test) Since the <COMMAND> is an executable target.
- dewyatt 8y agoI also found this to be a decent reference (mostly the videos): https://gist.github.com/mbinna/c61dbb39bca0e4fb7d1f73b0d66a4fd1 https://gist.github.com/mbinna/c61dbb39bca0e4fb7d1f73b0d66a4... Also, some of the Kitware projects on GitHub.