- Understanding The Basics
- So what a makefile does?
- The concept of CMake
- Edit your CMakeLists.txt
- Another Example — Linking more than 1 file
- Libraries and Subdirectories
- Levels and Libraries
- Reference
- Linux build with cmake
- Running CMake for Windows / Microsoft Visual C++ (MSVC)
- Running CMake on Unix
- Running CMake from the command line
- What is the CMake cache?
- Utility Targets produced
Understanding The Basics
To illustrate what makefile does, we first create a project folder (I named it CMakeTuto here).
Then use VSCode to open the folder.
mkdir CMakeTuto
cd CMakeTuto/
code .
Note here makefile do not accept spaces. It only accept tabs.
#include
int main(){
std::cout «Hello World!\n»;
return 0;
}
Now your CMakeTuto directory should be like this:
So what a makefile does?
Use the make command to run the makefile
make command basically run the command in makefile . (that is g++ main.cpp -o out in this case. )
Now a out file should appear. Run the out file.
It should print the “Hello World!”.
The concept of CMake
CMake makes your makefile.
now we can first delete our makefile and out in the previous section.
First check our cmake version
You can also use the command cmake to check the usage.
Common usage: cmake [options]
Create a file CMakeLists.txt , leave the file blank.
Now your directory should be:
Lets create a directory build.
Note if you want to use cmake command, you need to go to the build directory (which is build ).
Now your directory should be like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
.
├── build
│ ├── CMakeCache.txt
│ ├── CMakeFiles
│ │ ├── 3.10.2
│ │ │ ├── CMakeCCompiler.cmake
│ │ │ ├── CMakeCXXCompiler.cmake
│ │ │ ├── CMakeDetermineCompilerABI_C.bin
│ │ │ ├── CMakeDetermineCompilerABI_CXX.bin
│ │ │ ├── CMakeSystem.cmake
│ │ │ ├── CompilerIdC
│ │ │ │ ├── a.out
│ │ │ │ ├── CMakeCCompilerId.c
│ │ │ │ └── tmp
│ │ │ └── CompilerIdCXX
│ │ │ ├── a.out
│ │ │ ├── CMakeCXXCompilerId.cpp
│ │ │ └── tmp
│ │ ├── cmake.check_cache
│ │ ├── CMakeDirectoryInformation.cmake
│ │ ├── CMakeOutput.log
│ │ ├── CMakeTmp
│ │ ├── feature_tests.bin
│ │ ├── feature_tests.c
│ │ ├── feature_tests.cxx
│ │ ├── Makefile2
│ │ ├── Makefile.cmake
│ │ ├── progress.marks
│ │ └── TargetDirectories.txt
│ ├── cmake_install.cmake
│ └── Makefile
├── CMakeLists.txt
└── main.cpp
8 directories, 24 files
Notice now the Makefile is generated.
If You look into that Makefile and you will see it just build what our CMakeLists.txt require.
(Note we haven’t write anything into CMakeLists.txt yet)
We won’t teach those generated files.
Edit your CMakeLists.txt
Now write into your CMakeLists.txt .
cmake_minimum_required(VERSION 3.9.0)
project(HelloWorld) #replace «HelloWorld» with your project name
add_executable(${PROJECT_NAME} main.cpp)
run the cmake command in your build folder again.
If You look into that Makefile again and you will see it just build what our CMakeLists.txt require.
Lets run the Makefile using make command.
You should see this outcome:
Scanning dependencies of target HelloWorld
[ 50%] Building CXX object CMakeFiles/HelloWorld.dir/main.cpp.o
[100%] Linking CXX executable HelloWorld
[100%] Built target HelloWorld
And now you should see a HelloWorld executable is in the build folder.
Lets run the HelloWorld executable.
Now you know the basics of cmake.
Another Example — Linking more than 1 file
.
├── adder.cpp
├── CMakeLists.txt
└── main.cpp
float add(float a, float b)
{
return a+b;
}
cmake_minimum_required(VERSION 3.9.0)
project(HelloWorld) #replace «HelloWorld» with your project name
add_executable(${PROJECT_NAME} main.cpp adder.cpp) #add the files here
//function prototype
float add(float a, float b);
#include
int main(){
std::cout add(6.9, 13.2)
return 0;
}
Build and run the program
mkdir build
cd build
cmake ..
make
./HelloWorld
Libraries and Subdirectories
Levels and Libraries
In practical situations we often put our files into a folder.
We need to put a sublevel CMakeLists.txt in each subfolder.
.
├── Adder
│ ├── adder.cpp
│ ├── adder.h
│ └── CMakeLists.txt
├── CMakeLists.txt
└── main.cpp
1 directory, 5 files
#include «adder.h»
float add(float a, float b)
{
return a+b;
}
#include
#include «Adder/adder.h»
int main(){
std::cout add(6.9, 13.2)
return 0;
}
cmake_minimum_required(VERSION 3.9.0)
project(HelloWorld) #replace «HelloWorld» with your project name
add_executable(${PROJECT_NAME} main.cpp) #build the main
add_subdirectory(Adder) #build the libraries
target_include_directories(${PROJECT_NAME} PUBLIC Adder)
#—uncomment this if your cmake version >3.13.0
#—target_link_directories(${PROJECT_NAME} PRIVATE Adder)
target_link_libraries(${PROJECT_NAME} adder) #links the libraries to core project
the sublevel Adder/CMakeLists.txt
add_library(adder adder.cpp) #build as a library in the most simplistic way possible
Build and run the program
mkdir build && cd build
cmake ..
make
./HelloWorld
Reference
Linux build with cmake
Once CMake has been installed on your system using it to build a project is easy. We will cover the process for Windows and then UNIX.
Running CMake for Windows / Microsoft Visual C++ (MSVC)
Run cmake-gui.exe, which should be in your Start menu under Program Files, there may also be a shortcut on your desktop, or if you built from source, it will be in the build directory. A GUI will appear similar to what is shown below. The top two entries are the source code and binary directories. They allow you to specify where the source code is for what you want to compile and where the resulting binaries should be placed. You should set these two values first. If the binary directory you specify does not exist, it will be created for you.
Running CMake on Unix
On most unix platforms, if the curses library is supported, cmake will build an executable called ccmake. This interface is a terminal based text application that is very similar to the windows GUI. To run ccmake, change directories into the directory where you want the binaries to be placed. This can be the same directory as the source code for what we call in-place builds (the binaries are in the same place as the source code) or it can be a new directory you create. Then run ccmake with either no arguments for an in-place-build, or with the path to the source directory on the command line. This will start the text interface that looks something like this:
If you hit the “c” key, it will configure the project. You should use that as you change values in the cache. To change values, use the arrow keys to select cache entries, and the enter key to edit them. Boolean values will toggle with the enter key. Once you have set all the values as you like, you can hit the ‘G” key to generate the makefiles and exit. You can also hit “h” for help, “q” to quit, and “t” to toggle the viewing of advanced cache entries.
Two examples of CMake usage on the Unix platform follow for a hello world project called Hello. In the first example, and in-place build is performed, i.e., the binaries are placed in the same directory as the source code.
In the second example, an out-of-place build is performed, i.e., the source code, libraries, and executables are produced in a directory separate from the source code directory(ies).
mkdir Hello-Linux cd Hello-Linux ccmake ../Hello make
Running CMake from the command line
From the command line, cmake can be run as an interactive question and answer session or as a non-interactive program. To run in interactive mode, just pass the option “-i” to cmake. This will cause cmake to ask you to enter a value for each value in the cache file for the project. The process stops when there are no longer any more questions to ask.
Using CMake to build a project in non-interactive mode is a simple process if the project does not have many options. For larger projects like VTK, using ccmake, cmake -i, or CMakeSetup is recommended. This is because as you change options in the CMakeCache.txt file, cmake may add new entries to that file. It can be difficult to know when to stop the run cmake, edit the cache file cycle without the aid of an interface.
To build with just cmake change directory into where you want the binaries to be placed. For an in-place build you then run cmake and it will produce a CMakeCache.txt file that contains build options that you can adjust using any text editor. For non in-place builds the process is the same except you run cmake and provide the path to the source code as its argument. Once you have edited the CMakeCache.txt file you rerun cmake, repeat this process until you are happy with the cache settings. The type make and your project should compile. Some projects will have install targets as well so you can type make install to install them.
When running cmake from the command line, it is possible to specify command line options to cmake that will set values in the cache. This is done with a -DVARIABLE:TYPE=VALUE syntax on the command line. This is useful for non-interactive nightly test builds.
What is the CMake cache?
The cache is best thought of as a configuration file. Indeed Unix users could consider the cache as equivalent to the set of flags passed to the configure command. The first time CMake is run, it produces a CMakeCache.txt file. This file contains things like the existence and location of native JPEG library. The entries are added in response to certain CMake commands (e.g. FIND_LIBRARY) as they are processed anywhere in CMakeLists files anywhere in the source tree. After CMake has been run, and created a CMakeCache.txt file – you may edit it. The CMake GUI, will allow you to edit the options easily, or you can edit the file directly. The main reason for editing the cache would be to give CMake the location of a native library such as JPEG, or to stop it from using a native library and use a version of the library in your source tree.
CMake will not alter an existing entry in the cache file itself. If your CMakeLists.txt files change significantly, you will need to remove the relevant entries from the cache file. If you have not already hand-edited the cache file, you could just delete it before re-running CMake.
Why do I have to edit the cache more than once for some projects?
Some projects are very complex and setting one value in the cache may cause new options to appear the next time the cache is built. For example, VTK supports the use of MPI for performing distributed computing. This requires the build process to determine where the MPI libraries and header files are and to let the user adjust their values. But MPI is only available if another option VTK_USE_PARALLEL is first turned on in VTK. So to avoid confusion for people who don’t know what MPI is, we hide those options until VTK_USE_PARALLEL is turned on. So CMake shows the VTK_USE_PARALLEL option in the cache area, if the user turns that on and rebuilds the cache, new options will appear for MPI that they can then set. The rule is to keep building the cache until it doesn’t change. For most projects this will be just once. For some complicated ones it will be twice.
Utility Targets produced
In addition to the targets and rules to build object files, libraries and executables of a project, CMake creates some additional targets and rules. For Visual Studio projects, two utility projects are automatically created: ALL_BUILD and RUN_TESTS.
- ALL_BUILD- This project depends on all of the libraries and executables in a project, and can be selected as the active project to build everything in the system. This is required because CMake allows for extra utility projects to be put in the system that you may not want run each time with the Batch build facility of the Visual Studio. In addition, the ALL_BUILD target makes it easier to select between configurations in a large project. The Microsoft Visual C++ Batch build facility requires you to select the configuration for each library or executable by hand. This can be done once for all targets using CMake’s ALL_BUILD target.
- RUN_TESTS- This project will run ctest which will run all the tests in your project, see ADD_TEST.With CMake generated makefiles, the following targets are defined: depend, rebuild_cache, edit_cache, dependlocal, install, clean, and test. To run any of these targets simply run make target in a directory with a cmake generated makefile.
- depend – This target runs cmake to generate dependencies for the source files.
- rebuild_cache – This target runs cmake on the source tree and picks up additional cache entries if they exist.
- edit_cache – This target will run ccmake or CMakeSetup for the current project
- dependlocal – This target generates dependencies for the current directory only.
- install – This target will perform a UNIX style installation of the software based on the INSTALL_TARGETS command.
- clean – This target will remove all generated files.
- test – This target will run all the tests for a project, see ADD_TEST.To see all of the targets in a makefile, run make help.