Programming Workshop 2 (CSCI 1061U)
Faculty of Science, Ontario Tech University
CMake
CMake is a cross-platform family of tools for building, testing, and maintaining large software systems. This tutorial is designed to serve as a starting point for using CMake to build c/c++ programs. You can find more information about CMake at https://cmake.org.
*The following tutorial borrows heavily from the official CMake guide available here.
Source files are available here.
Lets consider a simple program that comprises three files.
main.cpp
util.cpp
util.h
We want to create an executable Example1
.
We will begin by creating a CMakeLists.txt
that will
include the script needed to complete the above task. Lines that start
with `#** are comments.
CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
# project name
project(Example1)
add_executable(Example1 main.cpp util.cpp)
At this point the directory structure looks as follows:
[... using-cmake] $ tree example1
example1
└── src
├── CMakeLists.txt
├── main.cpp
├── util.cpp
└── util.h
Now let’s create a sub-folder build
. We will use this
sub-folder to setup the build environment using the cmake
command.
[... using-cmake] $ mkdir build
[... using-cmake] $ tree example1
example1
├── build
└── src
├── CMakeLists.txt
├── main.cpp
├── util.cpp
└── util.h
Note we have kept the build
outside of the the
src
folder. This is intentional. Once we are done with
cmake
, the build
folder will consists of
platform-specific build instructions. These instructions are only valid
for this machine.
[... using-cmake] $ cd example1/build
[... using-cmake/example1/build] $ cmake ../src
Note that we issued the cmake
command in
build
folder, and we passed it the path of the
src
folder, which is ../src
. Recall that file
CMakeLists.txt
alongwith the source files sit in the
src
folder.
The cmake
command will create the platform-specific
build environment. I am running these programs on unix-like system.
Consequently, cmake
creates a Makefile.
[... using-cmake/example1/build] $ tree ../../example1
../../example1
├── build
│ ├── CMakeCache.txt
│ ├── CMakeFiles
│ │ ├── 3.23.1
│ │ │ ├── CMakeCCompiler.cmake
│ │ │ ├── CMakeCXXCompiler.cmake
│ │ │ ├── CMakeDetermineCompilerABI_C.bin
│ │ │ ├── CMakeDetermineCompilerABI_CXX.bin
│ │ │ ├── CMakeSystem.cmake
│ │ │ ├── CompilerIdC
│ │ │ │ ├── CMakeCCompilerId.c
│ │ │ │ ├── CMakeCCompilerId.o
│ │ │ │ └── tmp
│ │ │ └── CompilerIdCXX
│ │ │ ├── CMakeCXXCompilerId.cpp
│ │ │ ├── CMakeCXXCompilerId.o
│ │ │ └── tmp
│ │ ├── CMakeDirectoryInformation.cmake
│ │ ├── CMakeError.log
│ │ ├── CMakeOutput.log
│ │ ├── CMakeTmp
│ │ ├── Makefile.cmake
│ │ ├── Makefile2
│ │ ├── TargetDirectories.txt
│ │ ├── cmake.check_cache
│ │ ├── prog.dir
│ │ │ ├── DependInfo.cmake
│ │ │ ├── build.make
│ │ │ ├── cmake_clean.cmake
│ │ │ ├── compiler_depend.make
│ │ │ ├── compiler_depend.ts
│ │ │ ├── depend.make
│ │ │ ├── flags.make
│ │ │ ├── link.txt
│ │ │ └── progress.make
│ │ └── progress.marks
│ ├── Makefile
│ └── cmake_install.cmake
└── src
├── CMakeLists.txt
├── main.cpp
├── util.cpp
└── util.h
cmake
vs ccmake
In this example, we have used cmake
to generated the
platform specific build environment. cmake
is smart enough
to get the usual items (needed to setup the build environment)
correctly, including include paths, library paths, compilers, etc.
Sometimes, however, you wish to override these defaults. You can do so
by using ccmake
command instead. It will present a gui like
interface to allow you to change the various values, e.g., compilers,
etc.
CMake
supports a number of platform-specific build
environments. What that means is given a single source folder with a
CMakeLists.txt file, CMake is able to generate makefiles for unix-like
systems, visual studio project files for windows, and XCode project
files for OSX. Check out CMake documentation for an up-to-date list of
supported packages.
Luckily, you don’t have to worry too much about contents on the
build
folder. Let’s use make
to build the
executable.
[... using-cmake/example1/build] $ make
[ 33%] Building CXX object CMakeFiles/prog.dir/main.cpp.o
[ 66%] Building CXX object CMakeFiles/prog.dir/util.cpp.o
[100%] Linking CXX executable prog
[100%] Built target prog
[... using-cmake/example1/build] $ ./prog
sum = 83
smallest = 34
largest = 1
Source files are available here.
Lets consider a simple program that comprises three files.
main.cpp
util.cpp
util.h
We want to create an executable Example2
. However, this
time we want to set the version number at build time, plus we want to
use the C++11 standard.
Let’s use the following CMakeLists.txt file
CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
# project name
project(Example2 VERSION 1.0)
add_executable(Example2 main.cpp util.cpp)
# This is a header file will pass the version number to
# the program.
configure_file(Example2_Config.h.in Example2_Config.h)
# Example2_Config.h header will will be created in the
# build directory (and not the source directory). Note that
# the build directory is not included in the include-files-paths
# by default. Therefore, we include the build directory path
# in the include-files-paths.
target_include_directories(Example2 PUBLIC ${PROJECT_BINARY_DIR})
# specify the c++ standard
set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED True)
We will also create a Example2_Config.h.in
file to push
the version information in the `CMakeLists.txt** file to the
program.
Example2_Config.h.in
#define Example2_VERSION_MAJOR @Example2_VERSION_MAJOR@
#define Example2_VERSION_MINOR @Example2_VERSION_MINOR@
Create a build
folder and issue cmake
command in this folder as seen below.
[... using-cmake/example2/src] $ mkdir ../build
[... using-cmake/example2/src] $ cd ../build
[... using-cmake/example2/build] $ cmake
I am using unix-like environment, so I will issue make
command in the build
folder to create the executable.
[... using-cmake/example2/build] $ make
[... using-cmake/example2/build] $ ./Example2
version = 1.0
sum = 83
smallest = 34
largest = 1
Now change the version information in the CMakeLists.txt
file and redo steps 2 and 3. See if your program spits out the newer
version.
This is taken from CMake tutorial at https://cmake.org/cmake/help/latest/guide/tutorial/Adding%20a%20Library.html.
The source code used is available here.
We assume the following folder structure:
[... using-cmake/example3] $ tree src
src
├── CMakeLists.txt (1)
├── Example3_Config.h.in
├── mylib
│ ├── CMakeLists.txt (2)
│ ├── mylib.cpp
│ └── mylib.h
└── prog
├── CMakeLists.txt (3)
└── main.cpp
The build is controlled by three CMakeLists.txt files.
CMakeLists.txt (1)
# This CMakeLists.txt file lives in the main folder
cmake_minimum_required(VERSION 3.10)
project(Example3)
# This defines a switch that we can pass to cmake at invocation time.
# mylib library will only built if this switch is ON
option(USE_MYLIB "Use mylib functions" ON)
# We will use Example3_Config.h to let our program know if USE_MYLIB
# is defined. This way the program can be built to use mylib when
# it is available.
configure_file(Example3_Config.h.in Example3_Config.h)
if(USE_MYLIB)
# Includes subfolder that contains the library
add_subdirectory(mylib)
endif()
# Includes subfolder that contains the program files that will use the library add_subdirectory(prog**
CMakeLists.txt (2)
# This CMakeLists.txt file lives in the subfolder containing the program files
cmake_minimum_required(VERSION 3.10)
add_executable(Example3 main.cpp)
if(USE_MYLIB)
target_link_libraries(Example3 mylib)
target_include_directories(Example3 PUBLIC "${PROJECT_SOURCE_DIR}/mylib")
endif()
# We need this since Example3_Config.h is copied into the built folder target_include_directories(Example3 PUBLIC "${PROJECT_BINARY_DIR}**)
CMakeLists.txt (3)
# This CMakeLists.txt file lives in subfolder containing the library
cmake_minimum_required(VERSION 3.10)
add_library(mylib mylib.cpp)
You can control the USE_MYLIB
cmake option via command
line by using
[... using-cmake/example3/build] $ cmake -DUSE_MYLIB=OFF
Alternately, you can invoke ccmake
and it will provide
an ncurses-like gui where you can turn on or off the various options.
Try it out.
[... using-cmake/example3/build] $ ccmake