26 ms·
An Introduction to Modern CMake
- superkuh 8y agoThe problem with modern cmake is that it cannot run on older systems. So if you want to use it you end up either static compiling an incredibly hard and tedious depedency tree or have to use some just released OS. What I want out of a make system isn't bleeding edge features. I want to be able to use it for more than 3 years.
- ridiculous_fish 8y agoWhat systems does modern CMake not support?
- jhasse 8y agoAndroid NDK supports CMake 3.6 only for example.
- josteink 8y agoIf so, that sounds like a lacking of the Android NDK and not the other way around.
- jhasse 8y agoSure, doesn't change anything for me.
- gjasny 8y agoThere are two different things: CMake support within the NDK (by Google) and NDK support in CMake. The later is usually easy to use and supports many NDK revisions. See: https://cmake.org/cmake/help/v3.7/manual/cmake-toolchains.7.html#cross-compiling-for-android https://cmake.org/cmake/help/v3.7/manual/cmake-toolchains.7....
- pjmlp 8y agoThere are plans to eventually update cmake support. https://android.googlesource.com/platform/ndk/+/master/docs/Roadmap.md#unify-cmake-ndk-support-implementations https://android.googlesource.com/platform/ndk/+/master/docs/... But I guess you already know how slowly things in the NDK progress anyway.
- j1elo 8y agoWell, the first page touches briefly on this: > You should at least install it locally. It's easy (1-2 lines in many cases), and you'll find that 5 minutes of work will save you hundreds of lines and hours of CMakeLists.txt writing I agree that it's cumbersome wanting to use tools that are not readily available in most commonly used systems. On the other hand, wanting to keep support for old systems that you may only hypothetically want to use shouldn't be limiting your choice of tools (or better versions of a tool). Achieving an easy and straightforward means of installing should be a goal for the tool itself, as it is the case for latest versions of CMake (assuming that phrase about 1-2 lines is true). I agree that 3 years, or even 5, is an acceptable amount of time to keep using the same version of a tool. I'm currently at CMake 3.5, the one that comes with Ubuntu 16.04
- josefx 8y agoI have a 3 something version running on OpenSuSE 11.2 (that thing is ancient) . Spend maybe a day disabling various features to make it compile. Still didn't run into anything that needed cmake to support encryption.
- IshKebab 8y agoA nice tip is that you can install a very recent CMake from pip with most systems. Just `pip install cmake` and then you can require version 3.12 and don't have to worry about ancient Ubuntu packages or whatever.
- superkuh 8y agoOn systems were you don't need to do this (new enough) it'll work. On systems where you need to do this it will break things. And because it's pip, it'll be incredibly hard to figure out what broke and how to fix it.
- geofft 8y agoIn general you can avoid pip breaking things by doing so inside a virtualenv. The following should work on at least the last few years' worth of OSes: $ virtualenv /tmp/ve $ /tmp/ve/bin/pip install -U pip setuptools $ /tmp/ve/bin/pip install cmake $ /tmp/ve/bin/cmake ... $ rm -rf /tmp/ve On some OSes (e.g. Debian and derivatives) you'll need to install virtualenv itself from the OS first, but that won't break things because it's from the OS. On sufficiently old OSes, you may need to set PIP_INDEX_URL=https://pypi.org/simple/ https://pypi.org/simple/ and PIP_TRUSTED_HOST="pypi.org files.pythonhosted.org" to disable certificate verification. (I'm not sure of a good way to work around this problem. In theory, Python 3 would solve it, but those same old OSes have an old enough Python 3 that the latest version of setuptools fails, and I can't figure out how to install an old enough setuptools.) Also - if you need to unbreak your system Python, in general it suffices to ensure that /usr/local/lib and ~/.local/lib have no pythonX.Y directories with anything in them. (Empty directories are fine.) At my last job where we needed to give non-sysadmins root access on certain machines, I added a Nagios check to /usr/local/lib/python*, which was remarkably effective at catching problems before they turned inexplicable.
- nwmcsween 8y agoThe problem with modern cmake is the huge amount of dependencies it requires.
- AlotOfReading 8y agoThe only required dependency to build CMake is libuv. Are you talking about something else?
- jcelerier 8y ago> The problem with modern cmake is that it cannot run on older systems. ... uh ? they ship fully static binaries that work all the way back to centos 5 and other 10+ year old linux distros https://cmake.org/download/ https://cmake.org/download/
- tux1968 8y agoThe recommended compatibility boilerplate for new projects is tedious. There must be a way to include this knowledge in cmake itself rather than requiring every "properly" configured project to get this right: cmake_minimum_required(VERSION 3.1) if(${CMAKE_VERSION} VERSION_LESS 3.12) cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) else() cmake_policy(VERSION 3.12) endif() This is all before you even start thinking about your own project.
- baby 8y agoThis syntax is also uber ugly. I can’t understand why C still hasn’t a proper build system that is either using convention over configuration (like Go or Rust) or something like cmake but with a proper syntax (maybe something in pyhon?)
- bendmorris 8y agoScons (https://scons.org/ https://scons.org/) is one alternative. The configurations (and Scons itself) are Python.
- electricslpnsld 8y agoScons has soooo many problems. You still can't pass in positional linker flags without completely hacking how it calls the linker. :(
- blattimwind 8y agoConfiguration-by-full-language-by-default is IME a relatively big red flag for things like this. Much rather have a limited configuration language, possibly with the option of going full bore if needed. Case in point, qbs is much more workable. Declarative-glue-predefined-stuff-together most of the way, JavaScript capability if needed.
- wirrbel 8y agoI liked scons but it is what I would consider a legacy project that I would not introduce in new software or actively switch to. If you like scons check out meson, which feels similar I think.
- mr337 8y agoThis is quite welcoming. I have tried to digest cmake docs and get so lost. Am I the only one that can’t grok cmake docs? Edit: spelling fixes
- tonetheman 8y agoYeah cmake docs suck. I dig the concept but figuring out how to use it is/was painful. I have not looked in a while. It used to be the only chance you had to learn it was a book you could buy.
- lilott8 8y agoThe only way I've been able to make any sense of CMake docs is in conjunction with examples -- searching on Github/enormous open source projects using it (e.g. LLVM). Just reading CMake docs to understand how to use directive x almost always leads to failure.
- mr337 8y agoYup agree, I’m like I know this X project compiles file, let me Look at their cmake file....copy pasta. I’m not proud of it, but it works.
- twic 8y agoI found the function-level documentation baffling until i carefully read through the 'buildsystem' documentation, which lays out the fundamental model of how cmake works: https://cmake.org/cmake/help/v3.12/manual/cmake-buildsystem.7.html https://cmake.org/cmake/help/v3.12/manual/cmake-buildsystem.... Its not handholdingly simple, but it is precise and fairly complete, so you have a chance of understanding what is actually going on. All of the tutorials i've seen are just cookbooks with no explanation of how anything works, and mostly describe out-of-date or just plain bad approaches. The rash of "modern cmake" stuff avoids the latter, but really assumes you already know cmake. So that page of documentation was really crucial for me. The 'language' documentation is also helpful: https://cmake.org/cmake/help/v3.12/manual/cmake-language.7.html https://cmake.org/cmake/help/v3.12/manual/cmake-language.7.h...
- 8y ago
- nwmcsween 8y agoPlease don't use cmake, the dependency chain it pulls in on a bare machine is massive.
- nerdponx 8y agoWhat's wrong with dependencies?
- gumby 8y agoEvery dependency increases the fragility of your program. What if you update the dependency and it breaks your program? What if you have two programs dependent on the same library -- but different versions? This just scratches at the surface of the problem. Sometimes the risk is worth it: you need some complex functionality not worth writing yourself. In that case it's a good thing. But understand that it's a tradeoff.
- hugofirth 8y agoThis is a very dangerous argument for anything but the most domain specific or simple logic. Every time I roll something non trivial rather than using the widely testing and "battle hardened" alternative that increases the fragility of my program. There are times when it makes sense, but those are the special cases, and carry a cost which should be considered.
- jcelerier 8y ago> you need some complex functionality not worth writing yourself. well, CMake supports downloading stuff from the internet - git repositories, etc. If you want to be able to download from https:// https:// addresses I sure hope that you won't reimplement it yourself.
- nwmcsween 8y agocmake actually has an issue where a dependency it has depends on cmake, worlds of fun.
- tom_ 8y ago
- gjasny 8y agoI could also recommend Craig Scott's recent CMake book: "Professional CMake": https://crascit.com/professional-cmake/ https://crascit.com/professional-cmake/ IMHO it's the best available CMake book available right now. I especially liked the recommendations at the end of every chapter.
- kevinoid 8y agoThere are some good recommendations in here! Does anyone know of a way to check for, or enforce, these recommendations? The only CMake linters I could find seem to focus on whitespace and naming issues.
- MrQuincle 8y agoWhat I find a big shortcoming from CMake is that it does not have support for building for multiple architectures at once. https://cmake.org/pipermail/cmake-developers/2014-September/022929.html https://cmake.org/pipermail/cmake-developers/2014-September/... Quote: "The fundamental problem with supporting multiple architectures is that pretty much all of CMake is designed to support one architecture at a time. Modules/*, CMakeCache.txt, etc. are all built around only finding, using, and building one artifact per library (OS X universal binaries work with multiple architectures because they are still only one file). I think even your "toolchain scope" approach would end up being used in practice to wrap the entire CMakeLists.txt file."
- simonask 8y agoCMake replaces `configure` scripts. It would be difficult to imagine what multi-architecture support in a single build directory / command-line invocation would look like. Instead, what we do is to wrap calls to CMake in a script that makes choices about build directories, which flavours to build by default, which mobile SDKs exist, etc. When producing a release, we notably don't use this, because we are precisely interested in building for each architecture in parallel on different machines.
- MrQuincle 8y agoYes, for cross-compiling to targets with different configurations we also evoke CMake with lots of options. However, that you have to wrap calls to CMake in your scripts is quite ugly. Are those scripts cross-platform for starters? As soon as you start to write code to use CMake, this seem to defeat the purpose of a build generator.
- amrox 8y agoOpenCV includes a python script to build a framework for iOS. I agree, it’s not great.
- vetinari 8y ago> It would be difficult to imagine what multi-architecture support in a single build directory / command-line invocation would look like That's exactly what MacOS fat binaries are. Single binary contains sections for multiple architectures.
- codedokode 8y agoI used CMake and I liked that it can produce NMake files, which can be used for building with Windows SDK (not bloated Visual Studio, SDK contains just headers and compiler) on Windows XP. And generally it is much easier to use than manually write Makefiles or use Autotools with weird unintuitive syntax. As I remember, they use `dnl` keyword (download?) for comments!
- ur-whale 8y agoYou like CMake in much the same way people like Visual Basic: it has lots and lots of features and therefore people find it useful. But, just like VB isn't a good solution for an embedded language, it doesn't mean cmake is a good solution to the general problem of building large codebases.
- codedokode 8y agoNo, I like CMake because it is better than writing Makefiles manually or using autotools.
- ahartmetz 8y agoSomehow I'm never happy with CMake guides. The official book is ridiculously outdated among other things, the official documentation is complete and current but provides no guidance, and none of the blog-documentation about it gives a complete picture. Some of it is bad advice. This one doesn't talk about the dependency graph, something I consider very important in a build system. It is also missing a lot of other stuff. (Fair enough, it's provided for free.) I wrote the CMake training material for KDAB (www.kdab.com) while I worked there. In my biased opinion it's the best CMake guide around, especially after it was extended and polished by coworkers :). I tried to mix explaining the "inner logic" of a build system, and CMake in particular, with examples, resulting in something I'm reasonably happy with. The main difficulty was ordering the topics to avoid too many forward-references while also not starting with a lot of not-obviously-interesting groundwork [1]. (I don't work there anymore btw, so the interest I have is getting my work used) This intro to modern CMake should be good because Steve is a major CMake contributor and good at explaining. The presentation even contains a dependency graph! https://steveire.wordpress.com/2017/11/05/embracing-modern-cmake/ https://steveire.wordpress.com/2017/11/05/embracing-modern-c... [1] Aside: I figured that "There are two types of bad software documentation: math textbooks and cooking recipes. The former does not explain why you are doing things and other helpful context, the latter won't help you if you need to do something differently, which is almost always."
- cbHXBY1D 8y agoThe official documentation is sub-par. Want to know the difference between include_directories and target_include_directories? Well, good luck going through docs with no examples and then parsing through several year old stackoverflow posts.
- ahartmetz 8y agoThat is what I mean with "no guidance". In this case, you have a common best practices question that you have to figure out by diffing the two pieces of documentation yourself. The information is usually there.
- jcelerier 8y ago
- Sir_Cmpwn 8y agoI think the best advice I can give to someone learning about cmake is to use meson instead. I once had dozens of codebases using cmake, and have since moved most of them to meson and start most new new projects with meson.
- overgard 8y agoIt’s better than every other build system, but god I wish they had just used a preexisting language for it. The syntax for CMake just feels so janky and weird, and it’s another set of things I have to remember and (eventually) forget. It’s not like it has these amazing language concepts nothing else can do; and if they’re worried about size or dependencies something like Lua would add like no overhead and be super simple to link.
- ur-whale 8y agoCouldn't agree more. Any system that designs its own DSL should be suspect: designing languages is bloody hard, and anyone who think he can cobble his own to solve a problem as hard as build systems is doomed to produce something like cmake.
- whyever 8y agoIt's kind of a historical accident. Originally, CMake was supposed to be just a list of commands (CMakeLists.txt). Of course, it was heavily extended to what we have now.
- rutthenut 8y agoDo understand that things change over time, from simple beginnings to complex offspring. But I agree with many commenters here; it is frustrating and a ball-ache to have to learn yet another syntax to manage build dependencies and instructions. On that, I also detest how YAML, Python and so on make space indentation a core aspect of how the files are interpreted and processed. That idea stinks. imvho.
- whyever 8y ago> it is frustrating and a ball-ache to have to learn yet another syntax to manage build dependencies and instructions. Oh, I agree as well. I was just providing context.
- DoofusOfDeath 8y ago
- ur-whale 8y agoCMake is the perl of build systems: useful and feature-fat but one of the worse DSL syntax I've had to grapple with, barely better than that of a Makefile
- khazhoux 8y agoCan anyone with experience with Bazel, Buck, or Pants chime in?
- DoofusOfDeath 8y agoI've had to fight through Bazel somewhat when working with Tensorflow. My impression was that it probably suits Google's internal needs very well, but it's really complicated compared to CMake. I'm not sure that for most developers the learning curve would be worthwhile.
- Game_Ender 8y agoThey are quite different, speaking of Bazel it’s designed to be an all inclusive build system for any language at essentially infinite scale. Which means it: - Has nice Python based DSL - Strongly encourages 100% explicit dependency specification - Has built in caching (local and remote) - Built in test result caching - a fully featured build graph query language - Built in distributed execution support (for any build step) - All work scales by part of tree you are building not it’s absolute size - Support for fetching external source code and binary deps - Has first class support for executing and testing containers - Has first class support for code gen (ie you can build a compiler use it to generate code, then build its output,and everything works, no hacks in one build system) The downsides: - Works best if you all your code is built with Bazel, which makes deps hard - Support for Python is weak, Ruby non existent, and Node is beta quality - Has essentially zero convention, everything must be explicitly configured (ie explicitly describing go deps) - Has a memory hungry local java daemon - Has a more overhead than ninja (but is more accurate because of hashing and isolation)
- ecnahc515 8y agoOne downside I found: it makes heavy use of symlinking which doesn't always play well with other tools (in particular: Go tools) and I found made things particularly annoying when I used Bazel from inside docker and outside docker (the symlinks left don't match what's on my host).
- quietbritishjim 8y agoThis is really not an introduction to CMake. It is more like a collection of the author's opinions about CMake, barely categorised into sections and some quite contentious. An introduction would be example driven, starting with a very short but complete example: cmake_minimum_required(VERSION 3.1) project(FooAndBar) add_executable(Foo foo.cpp) add_executable(Bar bar.cpp) It would explain projects and targets (noting the different meaning of “project” to some IDEs including Visual Studio: project<->solution and target<->project). Then you would progressively build from there. Start by adding a dependency such as protobuf to show find_package() and target_link_libraries(), showing both the new protobuf::libprotobuf target dependency and the old-style ${Protobuf_INCLUDE_DIRS} and ${Protobuf_LIBRARIES} variables. Then make some shared code between your two executables into your own library, discussing shared vs static. I would not even mention variables until after this point (even though ${Protobuf_INCLUDE_DIRS} already is a variable). In other words, an introduction should be top-down and pedagogical. This is the exact opposite of that: picking through a CMakeLists.txt from the bottom up, one line at a time, before you even know what the point of it is. Perhaps I misread the title: I read it as “introduction to CMake [but using modern techniques]”, but maybe it’s “introduction to the modern bits of CMake [assuming you already know the old stuff of CMake]”. But even that could be example driven, admittedly with more effort: start with an old crusty CMakeLists.txt with plenty of bad habits and make it better one step at a time. Or have lots of little CMakeLists.txt with one bad habit at a time, and fix each of those. I am not convinced by some of the recommendations it makes either, although I think there will always be some disagreement about some of these things. I have already given my view on the “cmake_policy” atrocity (which is the very first thing in “Introduction to the basics”!) in another comment here. And in the examples there are workarounds for old versions of CMake that don’t have targets for e.g. find_package(boost) by creating interface targets using the old _LIBRARIES and _INCLUDE_DIR variables. These are very neat but not very accessible to CMake beginners. It would be much simpler to put up with using the old variables, or commit to increasing your minimum supported CMake and forget them entirely.
- DoofusOfDeath 8y agoOne of my problems with "modern" CMake is the same as my problem with "modern" C++: Their proponents argue for using certain new language features to get things done. But because of backwards-compatibility concerns, the system still supports the old, quasi-deprecated constructs for doing those same things. And so you end up with an overly complicated language that seems to have multiple, reasonable ways to do the same thing. And codebases containing a mix of the two, even for newly written code. IMO it would be better for CMake to make a clean break, and have CMake 4 only support "modern" CMake. (edit: And, as I've posted elsewhere, switch to a more robust scripting language.)