Somehow 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.)<p>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)<p>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! <a href="https://steveire.wordpress.com/2017/11/05/embracing-modern-cmake/" rel="nofollow">https://steveire.wordpress.com/2017/11/05/embracing-modern-c...</a><p>[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."
The 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:<p><pre><code> 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()
</code></pre>
This is all before you even start thinking about your own project.
It’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.
The problem with modern cmake is that it <i>cannot</i> 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.<p>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.
What I find a big shortcoming from CMake is that it does not have support for building for multiple architectures at once.<p><a href="https://cmake.org/pipermail/cmake-developers/2014-September/022929.html" rel="nofollow">https://cmake.org/pipermail/cmake-developers/2014-September/...</a><p>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."
This 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.<p>An introduction would be example driven, starting with a very short but complete example:<p><pre><code> cmake_minimum_required(VERSION 3.1)
project(FooAndBar)
add_executable(Foo foo.cpp)
add_executable(Bar bar.cpp)
</code></pre>
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).<p>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.<p>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.<p>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.
I could also recommend Craig Scott's recent CMake book: "Professional CMake": <a href="https://crascit.com/professional-cmake/" rel="nofollow">https://crascit.com/professional-cmake/</a><p>IMHO it's the best available CMake book available right now. I especially liked the recommendations at the end of every chapter.
I 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.
CMake 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
I 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.<p>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!
One of my problems with "modern" CMake is the same as my problem with "modern" C++:<p>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.<p>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.<p>IMO it would be better for CMake to make a clean break, and have CMake 4 <i>only</i> support "modern" CMake.<p>(edit: And, as I've posted elsewhere, switch to a more robust scripting language.)
There 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.