MRC/Tutorials/Cmake

From Control Systems Technology Group
Jump to navigation Jump to search

So, we compiled a source file into a binary in another directory, while linking against the *emc-framework* library. Imagine that by the end of the course you will use more libraries, and every time you need to remember the g++ command. That's quite a nuisance! Fortunately, there are tools that will help you out. In this course, we will use [CMake](https://en.wikipedia.org/wiki/CMake). All you have to do is create a file in the root (~/mrc/my_project) of you project that can be read by CMake, called *CMakeLists.txt*. In it, you specify the instructions that are needed to compile the project. Create a file called CMakeLists.txt (e.g. gedit CMakeLists.txt) with this text:

cmake_minimum_required(VERSION 2.8)

project(my_project)

add_executable(example src/example.cpp)

This file is probably quite understandable at first sight: it specifies the minimum required version of CMake to read the file, the name of your project, and states that an executable called *example* should be created from the source file *src/example.cpp*. Now, how should we use this thing? As was already said, CMake does not directly call the compiler. Instead, it generates *Makefiles* which can be used by the Linux-dependent *Make* tool. These *Makefiles*, or more generically called *build files*, are created in a seperate folder, often called *build*. Go to the root of your project (cd ~/mrc/my_project), create a build directory and go inside:

mkdir build

cd build

Now, to generate the build files, we only have to call CMake and refer to the directory in which the CMakeLists file is we just created:

cmake ..

(remember .. stands for 'one directory up') Have a look inside the build directory: CMake generated a lot of files, one of which is a Makefile. Now while 'being' in the build directory, call Make:

make

You will see that the compiler is called (as if we started g++ ourselves). Oh whoops...

Again the *undefined reference* error. But this makes sense: we did not specify yet that we need to use the emc-framework library.

Doing so in CMake is easy. Edit the CMakeLists.txt file, and add below the *add_executable* statement:

target_link_libraries(example emc-framework)

Now run cmake and make again:

cd build

cmake ..

make

Success! However, the binary is also created in the directory where you called make, i.e. in the build directory. It would be nice to have it in the bin directory we created earlier. Well, we can. Just add the following line to your CMakeList.txt:

set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

This sets the CMake variable EXECUTABLE_OUTPUT_PATH to be the bin directory in your project directory. The ${...} simply returns the value of the variable inside.

The CMake variable PROJECT_SOURCE_DIR is set by CMake and refers to the directory in which your CMakeLists.txt is placed (the name is somewhat confusing...).

Try to run `cmake ..` and `make` again. You should see the executable appear in your bin directory.


By the way, you only need to run the cmake command if you change your *CMakeLists.txt*. Once you start programming, i.e, editing your source files, you can simply go to the build directory and run make.


You might be thinking: this still is a lot of hassle. The g++ command wasn't that bad, and now I need an extra directory, some extra commands, understand CMake, etc. Indeed, for the small example above CMake is a bit overkill. However, once your project grows and source files are added, more libraries are used, etc, you will see that it is quite handy to have your project set-up defined in one simple file. Furthermore, you won't have to tell your teammates what command to run if you add a file or library, as you can simply update the CMakeLists.txt. Also, CMake is a widely used language, and supported by many Integrated Development Environments (IDE), which can be thought of as really smart programming editors that not only provide editing, but also support compiling and even runnning and debugging your program. Having a CMakeLists.txt is having a project definition that can be used by many IDEs to 'understand' what is going on in your project.