Platform independent builds with Cmake

2 minute read

Related:


A wide variety of programming languages are used by engineers and scientists. You can tie them all together (C, C++, C#, Cuda, Fortran, etc.) in a platform-independent and simple way using Cmake. Alternatives to Cmake include SCONS and Autotools. These programs generate Makefiles for the program. Some choose to use a manually-created Makefile alone, but I prefer the platform-independent nature of Makefile generators such as Cmake.

Basic CMake example

Let’s take a single-file C++ program, like a science/engineering researcher might use. You will probably be linking the Math library at least, and Boost for flexible command-line input of numerous parameters. You might like to turn on additional compiler warnings to help avoid common coding pitfalls. Finally, you want to allow your colleagues on a wide variety of computers and operating systems to compile easily.

To do all of the above easily, Cmake has a simple syntax. Let’s consider an example CMakeLists.txt for a C++ and Fortran project, line by line.

Minimum version

cmake_minimum_required(VERSION 3.0)

Cmake 3.0 is new enough for many small projects. New CMake projects should use at least the features of CMake 3.7 such as IN_LIST.

Distro CMake default
Ubuntu 16.04 3.5.1
Ubuntu 18.04 3.10.2

Language(s) selection

project(zakharov CXX)

Naming your project can help auto-install if you decide to someday. CXX is required to enable the hooks for the language(s) you used. The most frequently used include

tag language
C C
C# C#
CXX C++
CUDA CUDA
Fortran Fortran

Languages that aren’t built into Cmake such as Pascal can be added via custom Cmake modules.

compiler options

add_compile_options(-mtune=native -Wall -Wextra -Wpedantic -fexceptions -Warray-bounds)
-mtune=native
use specialized optimizations for your particular CPU
-Wall -Wextra -Wpedantic -Warray-bounds
turn on warnings for common programming mistakes
-fexceptions
more detailed debug info with no speed penalty–enabled by default on Clang.
add_executable(zakh zakh.cpp)
zakh
the exe file that will be created on compile, run with ./zakh.
zakh.cpp
the files making up “zakh”
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

This project requires C++11 features, so if someone has an extremely old compiler not supporting C++11 they’ll get an error.

find_package(Boost REQUIRED COMPONENTS system filesystem program_options)
include_directories(${Boost_INCLUDE_DIRS})
target_link_libraries(zakh ${Boost_LIBRARIES})

The last two Boost lines are boiler-plate. The first line reflects that I use

boost-filesystem
directory manipulation
boost-program-options
advanced command-line parsing
boost-system
typically included when using Boost.

Compiling a simple project with Cmake

It’s convenient to create a separate directory, typically bin/ under your main code directory. You can certainly use options to use a single directory for everything, but it can be cleaner to use the defaults. Let’s say your main code directory is ~/code/zakharov, then do

mkdir bin
cd bin
cmake ..
make
./zakh

Let’s say you edit the code. All you do from the bin/ directory is

make
./zakh

for almost any subsequent changes

Leave a Comment