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-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."
hmm, I think on the contrary that the documentation actually does a good job of helping you making your first CMake file : https://cmake.org/cmake/help/v3.12/manual/cmake-buildsystem.... - then you ddelve deeper when what's provided here doesn't cut it anymore because of less common requirements.
It's even available as man pages !
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.It's not like you can use features from the newer version anyway, if you seriously want to support the older version. And if the same line of code has two different meanings in two versions, you want the old meaning (as you would get without target_version(<new version>)) because presumably you wrote your CMakeLists assuming that behaviour.
Edit: If I had read TFA before I posted I would've seen that's where the quoted code comes from. As the first thing that it teaches you to put in your CMakeLists.txt that is a pretty unfortunate failure IMO. If an old version of CMake has a behaviour you don't want (such as "wrong linking behavior on macOS" quoted in the linked article) then bite the bullet and use a newer minimum version of CMake. You could do this on only the cases it would cause a problem (e.g. just on MacOS, or just when a cache variable is set) but do so unconditionally of the version, so if someone tries to use an old version of CMake in that configuration they'll get a hard error. That's what you want!
I hope this is all abstracted enough so one day cmake can become saner to read and write. For now you just have to carry this otherwise useless syntax knowledge with you, or switch to meson or waf. Most IDEs seem to prefer cmake though, especially with the new cmake server mode it might be here to stay.
And a big thanks to all the saints who want to make cmake understandable for the rest of us.
More than "proper", or simply "nice looking syntax" the thing I like from CMake is that a single file makes my project compile in several versions of Linux and Windows using a variety of compilers.
Any suitable replacement system should also do this.
Despite CMake's attrocious syntax, the underlying compilation model has always worked more or less as I expected. I can't say that about most of the alternatives I have tried. I was frequently left confused and frustrated by my build systems until I found CMake.
I've sometimes wondered if CMake would benefit from getting an additional / replacement scripting language. While retaining the same underlying object model and other code, that is.
My only fear would be that it would be a first step in morphing into Bazel, which I find unbearably complicated.
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.
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.
Just `pip install cmake` and then you can require version 3.12 and don't have to worry about ancient Ubuntu packages or whatever.
> 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
... uh ? they ship fully static binaries that work all the way back to centos 5 and other 10+ year old linux distros
Am I the only one that can’t grok cmake docs?
Edit: spelling fixes
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.h...
I’m not proud of it, but it works.
It used to be the only chance you had to learn it was a book you could buy.
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."
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.
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.
That's exactly what MacOS fat binaries are. Single binary contains sections for multiple architectures.
Some CMakefiles have many and gratuitous dependencies but that's the fault of those authors.
I prefer software that uses mature 3rd party libs over NIH driven rewrites. Please also keep in mind that CMake is available for many platforms sone with fading user base like AIX, HPUX, or Solaris. Using a well tested event library like libuv helps to keep those supported.
apt-get -y install subversion git make gcc g++ subversion emacs git-gui zip gksu synaptic gdb valgrind
I'm pretty sure that not all of these are actually required. You do need gcc and g++, I'm sure, but I expect Valgrind and GDB are strictly optional... app-crypt/rhash
>=app-arch/libarchive-3.0.0:=
>=dev-libs/expat-2.0.1
>=dev-libs/libuv-1.10.0:=
>=net-misc/curl-7.21.5[ssl]
sys-libs/zlib
virtual/pkgconfig
emacs? ( virtual/emacs )
system-jsoncpp? ( >=dev-libs/jsoncpp-0.6.0_rc2:0= )
of which most have dependencies as well which is honestly ridiculous for a build system.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.
curl libarchive shared-mime-info jsoncpp libuv rhash
and you can always download a prebuilt static binary from their website: https://cmake.org/files/v3.12/cmake-3.12.1-Linux-x86_64.tar....
In 2018, the age-old problem of the build system remains entirely unsolved.
CMake is terrible, but so are all the others.
I believe the CS community as a whole has gravely under-estimated how hard the build system problem actually is.
We're only starting to recognize this.
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.
IMHO it's the best available CMake book available right now. I especially liked the recommendations at the end of every chapter.
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!
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.
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.)
- 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)
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.