Turning CMake into a good UNIX citizen

CMake, the software build system, describes itself as:

Welcome to CMake, the cross-platform, open-source build system. CMake is a family of tools designed to build, test and package software.

However, CMake cannot keep its promises and fails with respect to packaging1. Writing software with CMake that builds everywhere is possible but in some cases not very easy and, although CMake provides its own packaging mechanism called CPack, it can only serve as a temporary solution.

The main problem on UNIX-like systems is the amount of freedom concerning installation paths. There are no guidelines where things have to go and how the paths are set up. Yes, CMake allows you to set the installation prefix by using

cmake . -DCMAKE_INSTALL_PREFIX=/usr

however, this is not enough to cover all cases. For example, the location of a 64-bit library is /usr/lib on Debian systems and /usr/lib64 on openSUSE systems. In an autotools-based system, you would just set --libdir to the appropriate location. Not so with CMake. People write all kinds of gruesome hacks to figure this out at build time much to mental state of package maintainers. Moreover, even if one user gets this whole mess right, a thousand others won’t.

To fix this problem for my own software systems, I wrote the ConfigurePaths module which would be used like this:

include(ConfigurePaths)

configure_paths(FOO)

Simple, eh? With this call, you populated your global CMake namespace with cached path variables that mimic the system variables known from configure scripts:

# header files
install(FILES bar.h
        DESTINATION ${FOO_INCLUDEDIR})

# libraries
install(TARGETS bar
        LIBRARY DESTINATION ${FOO_LIBDIR})

# binaries
install(TARGETS baruser
        RUNTIME DESTINATION ${FOO_BINDIR})

# pkg-config
install(FILES bar.pc
        DESTINATION ${FOO_PKGCONFIGDIR})

# ...

By default, all variables are set to the configure defaults, e.g. FOO_PREFIX is /usr/local, FOO_DATADIR is FOO_PREFIX/share, and so on. The user can override the default values by CMake means, for example:

$ cmake . -DPREFIX=/opt -DLIBDIR=/usr/lib64

Rather than convincing you to use this, I really just want to encourage you to think about the whole mess. In the end, it may turn out that you have to package the software yourself.

  1. I deliberately do not bash the ugly syntax here. Or say that autotools is a much better build tool on UNIX systems. No, no, I won’t.


Discussion