CMake: patterns and antipatterns - Part I

I've been deeply working with CMake during the last few months. It is a piece of software I am really proud and happy to work with; it is very well designed (warning: YMMV), maintained (supported) and runs in a lot of operating systems.

I figured out it would be a waste of time and knowledge not to document my findings and experience with it while my mind is still fresh, therefore I am starting this series to provide some guidelines, {anti,}patterns and -- of course -- opinionated views on how to use it well and/or avoid common annoyances [1].

Disclaimer: you will find lots of opinionated statements in this series. Although I will mostly make them explicit, I advise you to check out its official documentation if unsure.

Starting point: CMake version

CMake 2.8.12.2 is the latest release of the 2.8.x series. It is very solid and mature, and it is the last release included in Ubuntu 14.04 LTS.

CMake 3.0+ has lots of improvements and higher-level functions and modules to make things that used to be too repetitive and annoying in the 2.8.x series. On the other hand, lots of these improvements are not compatible with the 2.8.x series.

The first thing to be decided is which CMake version to use. A safe bet is to stick to 2.8.12.2; however, if there are no hard requirements, I would advise the 3.6.x sub-family. It is another family of solid and stable releases. Note: the latest released version of CMake at the time of this post is 3.8.x.

Another relevant point is that the 3.0x series documentation documentation is released with Sphinx, which makes it waaaaay more convenient to use than the older 2.8.x format.

Hello World project, and baby steps

Create the well-known hello.cpp file:

#include <iostream>

int main() {
    std::cout << "Hello world!" << std::endl;
    return 0;
}

And then a CMakeLists.txt file: 

cmake_minimum_required(VERSION 2.8.12)
project(hello)
add_executable(hello hello.cpp)

Build it as follows: 

mkdir build
cd build
cmake ..
make

You program will be called hello and will be created / placed in this build directory.

KNOL [2]: do out-of-source builds, by creating a directory for the sole purpose to store compilation artifacts, such as Makefiles, libraries and executables. You can always do a 

cmake . && make

However it is not advised (OPP [3]).

KNOL: A good function to keep in your shell is (warning: take care with the rm -rf part): 

t-cmake-clean() {
    local BUILD=$(basename $(pwd))
    cd .. && rm -rf $BUILD
    mkdir $BUILD && cd $BUILD
}

It should be run from within your build directory to regenerate it. Another common approach is to do a rm -rf * from within your build directory, which is also acceptable, however I personally prefer (OPP) the first approach.

KNOL: to introspect your binary, these are some commands you can run: 

file hello
readelf -d hello
ldd hello
objdump -p hello
LD_TRACE_LOADED_OBJECTS=1 ./hello
ldconfig

If you happen to be on SunOS / Solaris, there is also 

/usr/css/bin/dump -Lv ./hello

These are useful for (i) cross-compilation scenarios and (ii) whenever you are linking your binaries to shared libraries. They are also useful to check out the platform your binary has been compiled to.

KNOL: for debug purposes, you might want your build to be more verbose than the usual. There are two common approaches to do it.

The first one is at cmake time. 

cd build && cmake -DCMAKE_VERBOSE_MAKEFILE=ON ..
make

The second one is at compile time. 

cd build && cmake ..
make VERBOSE=1

I personally like the first one (OPP), however the second one is also OK.

KNOL: always keep an open browser tab with the documentation of the cmake version you're using. The Sphinx documentation format and, alas, the CMake documentation itself, are really good and you will be less error-prone if you RTFM. CMake (and build tools, for that matter) is not a tool to be used from the top of your head; it is really not advisable to do it (OPP).

Another resource for CMake documentation is DevDocs.

KNOL: StackOverflow is the best / fastest place where you can obtain documentation from CMake not found (or not easily found) in its Sphinx form. This is not a generic statement. Stack Overflow is good for lots of languages and tools, sure; however it sucks for lots of other resources too. My point here is that, from my prior experience™, it is an excellent place for CMake. Use the CMake tag whenever asking a new question!

The second best place to obtain information about cmake is from its official mailing list, however I don't recommend it for newbies (OPP), as it is more dense. CMake is maintained by the good folks at KitWare Inc. Keep that in mind if you intend to go to its mailing list; although it is open source project, it is backed by a company.

What's next?

There is still a lot to cover: dependencies, Find Modules, libraries, cross-compiling, basic debugging, properties, installations, and so on. This series is not intended to be a complete tutorial, so don't expect me to cover everything; it is only supposed to a priori cover / contain a collection of knols (tips) to make CMake development easier.

Contributing

I hope you found this post useful. If you spot any errors or have any suggestions to improve it, please leave a comment below or just email me privately (tbperrotta aatt gmail ddoott com) instead. This Contributing section will be included in all posts of this series, and will be removed after a few weeks. Thanks for reading, and until the next time.

Metablogging: metablogging is blogging about blogging. You might see a few metablogging snippets in this series. They will likely (though not always) disappear in the future, and it is my way of expressing out-of-topic (OOT) subjects in the middle of a post.

That said, this "will disappear" thing is probably an indirect influence from Snapchat and Instagram Stories. It is a good practice; content will not remain relevant forever, and it tends to lose relevance after a couple of days of weeks; the same thing happens with your money through inflation. When thinking about it, cleaning posts makes a lot of sense if you care about your future readers (and, heck, maybe even the future you).

Also, I really miss blogging, and this series is my way to slowly rollback to this world. Writing is a very good way of expressing thoughts and concerns. Although this thiagowfx.gitlab.io blog is still shining as it's kinda new, my old blog lives at https://thiagoperrotta.wordpress.com. I reactivated it and will now use it to post non-dev stuff.

Footnotes

[1] because most -- if not all -- software has some annoyances which we only learn how to overcome after lots of stumbling upon StackOverflow and SuperUser.
[2] KNOL: an unit of knowledge, aka pro-tip or customized koan, if you will.
[3] OPP: an opinionated statement. Yes, with a double p.

Comments

Comments powered by Disqus