CMake a gentle introduction

Reading Time: 2 minutes

CMake is a useful tool for auto generating Makefiles for your project. Not only that you can also create extensions which look for specific libraries. This is similar to what a configure script would do but it’s a lot more simpler to use and modify.

In this small tutorial I’ll walk you through a sample project which can be found here. First let’s take a look at the directory structure of this project.

Here we’ve our

  • toplevel CMakeLists.txt
  • A common directory for common include(s)
  • configuration directory which controls the build time variables which can be checked in code as macros.
  • a sub-project named vector

First we’ll analyze the toplevel CMakeLists.txt.

  • We begin with a minimum cmake version required and immediately after that the project’s name and it’s version in MAJOR.MINOR format.
  • We want to use C++11 for this project so set that and make sure this standard is required and available.
  • You’ll see some multi line comments as well which tell you a bit more about this file.
  • next we setup a couple of variables which are defined / controlled from the configure_file provided.
  • at the end there are a couple of include directories for all project and sub-projects.
  • finally we add our sub-project into it.

Note that a sub-project will itself has it’s own CMakeLists.txt and other dependencies.

cmake_minimum_required(VERSION 3.10)
project(cplusplus VERSION 1.1)
#CMAKE defines <PROJECT_NAME>_VERSION_MAJOR and <PROJECT_NAME>_VERSION_MINOR
#[[ behind the scenes based on the values we give in the project() macro
and this is a multiline comment. See how it begins and ends ]]

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

#[[ We're going to use a config_file which is a way to create a header file
generated from cmake and it's placed in the project's binary directory. The
idea is that we define the values in cmake or during build time and those
values will be defined in the header file which is generated in the project's
binary directory.

The following configure_file will take a look at the config directory's
cplusplus.config.in file and generate cplusplusconfig.h. We added the options
@ONLY to restrict variable substituion only for the types @VAR@ defined in the
config.in file and also set the newline style to be UNIX ]]

configure_file(./config/cplusplus.config.in cplusplusconfig.h @ONLY
		NEWLINE_STYLE UNIX)
#[[ options for this cmake file are same as in the config.in please see
that file on how these variables work]]

if(NOT DEFINED DEBUG_OUTPUT)
	set(DEBUG_OUTPUT 0)
endif()

if(NOT DEFINED COMPILE_VERSION)
	set(COMPILE_VERSION "undefined")
endif()
include_directories("./common/include")
include_directories("${PROJECT_BINARY_DIR}")


add_subdirectory("./vector")
 

Building

  • Create a directory, say build and change into it.
  • You can then configure cmake along with the defines as
    • `cmake ../ -DCOMPILE_VERSION=”xxx.yyy”

This will generate the Makefilesand you can then do a make which would generate the executables in their respective project directories.

In our case we’ve one sub-project called vector thus the executables would be created within that directory.

Leave a Reply