Linux Format

Use CMake like a pro

Mihalis Tsoukalos teaches you about the CMake project, its configurat­ion files and how to visualise project dependenci­es using Graphviz.

- Our expert Mihalis Tsoukalos is a UNIX administra­tor, a programmer, a DBA and a mathematic­ian who enjoys writing technical articles. He’s also the author of Go Systems Programmin­g.

Mihalis Tsoukalos teaches you about CMake, its configurat­ion files and how to visualise project dependenci­es using Graphviz.

Acornersto­ne of the build process is CMake, an open source project largely supported by Kitware. If you want to build and compile code like a pro then you’ve get to get in the know! Here, we’re going to show you how to use CMake for compiling, linking and installing software on Linux and UNIX machines. We’ll then use the Graphviz output from CMake to visualise the dependenci­es of a CMake project. Remember that if you have a properly setup CMake configurat­ion file, cmake will do most of the boring work for you. However, it should be noted that you should use the GNU

make utility to process a CMake project. You’ll most likely install CMake using your usual package manager, which will make the whole process much simpler for you. You might also want to install some extra packages to make your life easier in the long run – on an Ubuntu Linux, you can do that by executing the following command: $ sudo apt-get install cmake cmake-data cmake-doc cmakeextra­s Then, you can find out which version of CMake you have by running this command: $ cmake --version cmake version 3.10.1 CMake suite maintained and supported by Kitware (kitware. com/cmake).

Should you wish to look at the numerous options supported by cmake, you can execute the cmake --help command. After this brief introducti­on, we’re now ready to start working and building projects with CMake.

MakeBasic

The simplest project you can have is one with a single source file. So, imagine that you have a C file called hw.c, which contains the C code of the famous HelloWorld program, and that you want to manage it using CMake.

The name of the CMake file that holds the configurat­ion of that naive project will be CMakeLists.txt, which is the default configurat­ion file for all CMake projects. The contents of that simplistic and naive CMakeLists.txt file are the following: cmake_minimum_required(VERSION 3.0) PROJECT( LXF ) add_executable(LXF hw.c)

The first line defines the minimum CMake version required for this project, the second line specifies the name of the project and the third line specifies the files involved ( hw.c) in the creation of the executable file as well as the filename of the executable file ( LXF).

Please note that it’s considered good practice to have a directory named build inside the root directory of your project in order to have a cleaner root directory. Additional­ly, because cmake doesn’t provide a command for cleaning up,

you’ll just need to delete the build directory when you want to clean up your project.

After having a syntactica­lly correct CMake file, you’ll need to execute the cmake command with a single parameter, which will be the path to the root directory of your project. This will automatica­lly generate some additional files including a Makefile that will be used by the make utility. So, the required steps are as follows: $ cd hw $ ls -l total 12 drwxr-xr-x 2 mtsouk mtsouk 4096 Dec 30 21:45 build -rw-r--r-- 1 mtsouk mtsouk 78 Dec 30 21:45 CMakeLists.txt -rw-r--r-- 1 mtsouk mtsouk 94 Dec 30 19:47 hw.c $ mkdir build $ cd build $ cmake ..

The last command will create lots of output that can be seen in the screenshot ( left). Executing the make command afterwards will create a executable file called LXF in the root directory of your CMake project. If you don’t want to manually create the build directory you can execute cmake -H. -Bbuild from the root directory of the project.

Finally, if cmake can’t find a CMakeLists.txt file in the specified directory, you’ll see the following error message: $ cmake /tmp CMake Error: The source directory “/tmp” appear to contain CMakeLists.txt. Specify --help for usage, or press the help button on the CMake GUI.

As the CMake file shown here is relatively straightfo­rward, we won’t deal with it any further. However, if you’re familiar with Makefiles then it would be very interestin­g to have a quick look at the generated Makefile.

The next section will present the CMake configurat­ion of a more realistic project with multiple source files written in C++.

Starting C++

This C++ project will have three source files that are needed for creating the final product, which will be an executable file. To avoid overcompli­cating matters, the C++ code of this project will be fairly simplistic. A CMake project can also create a shared library or a static library – the general idea behind processing such projects with cmake is the same as in creating an executable file.

The steps and the commands for creating the structure of a new CMake project called ‘simple’ are the following: $ mkdir simple $ cd simple $ touch CMakeLists.txt $ mkdir build $ mkdir myLibrary $ mkdir myLibrary/include $ mkdir myApplicat­ion $ touch myApplicat­ion/main.cpp $ touch myLibrary/include/aClass.h $ touch myLibrary/aClass.cpp

The first thing that you see in this project is that although there are multiple directorie­s, there’s only one

txt file. Additional­ly, main.cpp apart from the central C++ CMakeLists. file that’s named and contains the main() function of the project, there are two additional files: one C++ source file ( aClass.cpp) and one header file ( aClass.h). In these two files you’ll find the implementa­tion of a C++ class that’s used in main.cpp.

The contents of the main CMakeLists.txt, which can be found in the root directory of the project, can be seen in the screenshot ( below). Note that you could have used multiple

CMakeLists.txt files instead, but for such a relatively simple project that approach wouldn’t be necessary. Many new and interestin­g things can be seen in this

CMakeLists.txt file. First, notice that the CMAKE_BINARY_ DIR variable in combinatio­n with the EXECUTABLE_

OUTPUT_PATH variable specify the directory where the executable file of the project is going to be placed.

Then, SOURCES specifies the two C++ source files of the project. Additional­ly, include_directorie­s() tells CMake where to find aClass.h. After that, add_executable() specifies that the final product will be named simple and that it’ll be based on the value of the SOURCES variable.

The last line of CMakeLists.txt tells CMake that the generated binary file will be installed on the bin directory of the installati­on directory.

It’s now time to try to use CMakeLists.txt. As you already know, you’ll first need to execute the cmake command before continuing with the make command: $ ls -l $ cmake -H. -Bbuild $ cd build $ make If there’s an error in the CMake configurat­ion file, you’ll see error messages that will look similar to the following: CMake Error at CMakeLists.txt:7 (INSTALL): INSTALL called with unknown mode DESTINATIO­N The cause of the first error message is an unknown variable in CMakeLists.txt, which was corrected in the CMakeLists.txt version that you have: CMake Warning (dev) in CMakeLists.txt:

No cmake_minimum_required command is present. A line of code such as cmake_minimum_required(VERSION 3.10)

should be added at the top of the file. The version specified may be lower

if you wish to support older CMake versions for this project. For more

informatio­n run “cmake --help-policy CMP0000”. This warning is for project developers. Use -Wno-dev to suppress it.

The second message is a warning message telling you that you should define the minimum cmake version required for this project. As you can see, both messages are very clear.

The screenshot ( below) shows the output you’ll get when processing the CMakeLists.txt file with cmake.

CMake variables

The executable file of CMake supports a range of variables that can help you change various things on a CMake project without the need to alter CMakeLists.txt. The most useful variable is CMAKE_INSTALL_PREFIX, which helps you define the installati­on path of your project. The default value of CMAKE_ INSTALL_PREFIX is /usr/local on all UNIX machines. When testing a project, a good candidate for the installati­on directory would be the /tmp directory. The CMAKE_BUILD_TYPE option variable specifies the build type that will be built. The valid values for the CMAKE_BUILD_TYPE variable are Debug, Release, RelWithDeb­Info and MinSizeRel. The Debug value turns on the debug flags on the generated files. However, when creating the final version of a project, you’ll need to use the Release value for CMAKE_BUILD_TYPE.

Finally, there’s CMAKE_<LANG>_FLAGS. You should replace <LANG> with the string that’s related to the programmin­g language of your choice – this is for defining the compiler flags which will be used. For C, the value of <LANG> should be C whereas for C++ the value of <LANG> should be CXX. Therefore, for a C++ project, this option variable should be CMAKE_CXX_FLAGS. For the full list of the available option variables you can visit https://cmake.org/cmake/help/v3.0/manual/cmakevaria­bles.7.html.

Compile and install

In this section you’ll learn how to compile and install the simple CMake project, using the make command.

So, in order to compile the project, after successful­ly running cmake, you’ll need to execute the make command from the build directory of the C++ project. Should you wish to compile your project with the debug flags turned on, you should use the CMAKE_BUILD_TYPE variable from the command line, as follows: $ rm -rf build $ make build $ cd build $ cmake .. -DCMAKE_BUILD_TYPE=Debug $ make

The use of the objdump(1) command will verify that the generated executable file contains debugging informatio­n: $ objdump --syms bin/simple | grep debug 0000000000­000000 l d .debug_aranges 0000000000­000000 .debug_aranges 0000000000­000000 l d .debug_info 0000000000­000000 .debug_info 0000000000­000000 l d .debug_abbrev 0000000000­000000 .debug_abbrev 0000000000­000000 l d .debug_line 0000000000­000000 .debug_line

0000000000­000000 l d .debug_str 0000000000­000000 .debug_str

To install the binary file of the simple project to the bin directory of the default location, which is /usr/local, you’ll need to execute the make install command. However, because putting files in the /usr/local directory requires root privileges, you’ll most likely receive an error message when executing make install that you can overcome by executing

sudo make install instead. Should you wish to install the project in a different directory where you have enough permission­s, which in this case will be /tmp, you should use CMAKE_INSTALL_

PREFIX and execute cmake as follows: $ cd build $ cmake .. -DCMAKE_INSTALL_PREFIX=/tmp Then, you can use make install to install the binary executable on /tmp. The result of the preceding command can be seen by looking at the contents of the /tmp directory: $ make install [100%] Built target simple Install the project... -- Install configurat­ion: “” -- Up-to-date: /tmp/bin/simple $ ls -l /tmp/bin/ total 12 -rwxr-xr-x 1 mtsouk mtsouk 11120 Jan 1 20:57 simple

If you want to test the results of any make command, you can execute make with the -n command line option. This prints the commands that will be executed without actually executing them!

CTest and CPack

CTest is a tool for testing that comes with CMake and can be invoked with the ctest binary. The CTest tool can operate in two modes. In the first mode, you should use CMake to create and run the tests for CTest. In the other mode, CTest takes charge and runs as a script in order to run the testing process.

CPack is a cross-platform software packaging tool that comes with CMake. CPack uses the CPackConfi­g.cmake file and is called by the cpack binary. As CMake comes with a CPack module, you can use CPack from a CMake configurat­ion file by including the INCLUDE(CPack) line in CMakeCache.txt. Finally, you can debug CPack by calling the cpack executable cpack --debug --verbose .

CMake and Graphviz

Graphviz is a collection of tools for generating impressive and useful directed or undirected graph layouts that uses its own language called dot. CMake can generate dot code that visualises the dependenci­es of the targets of a CMake project with the help of the --graphviz command line option.

Given a CMake project, which in this case it would be the simple project created earlier in this tutorial, you can create a visualisat­ion of its dependenci­es as follows: $ cd build $ cmake .. --graphviz=simple.dot

The screenshot ( topleft) shows the output of the previous command as well the three generated dot files, which are all pretty simple as the CMake project is also straightfo­rward. The simple.dot file shows all the dependenci­es in the project whereas the simple.dot.simple file shows the dependenci­es for a particular target – so if you have only one target these two files will be exactly the same! Finally, the simple.dot. simple.dependers file shows the targets that depend on a particular target. Because this CMake project has only one target, simple.dot.simple.dependers is the same as simple. dot.simple. More interestin­g projects will generate more complex Graphviz files and therefore more interestin­g graphical output. You can generate a PNG file named simple. png from a dot file called simple.dot by executing the dot -Tpng -osimple.png simple.dot command.

The good thing is that by adding some extra configurat­ion code in your CMakeCache.txt file, you can instructCM­aketo automatica­lly generate the project dependenci­es using Graphviz. The screenshot ( above) shows the final version of the CMakeCache.txt file.

The CMakeGraph­VizOptions.cmake file is related to the Graphviz output of CMake and enables you to customise the Graphviz output. You can obtain the full list of the options supported in CMakeGraph­VizOptions.cmake, which is pretty big, by executing the cmake --help-module CMakeGraph­VizOptions command.

Remember, you’ll only be able to recognise the benefits that you can obtain from CMake if you start using it in your projects on a regular basis So what are you waiting for?

 ??  ??
 ??  ??
 ??  ?? The output that’s generated by the cmake command when dealing with a simple CMakeCache.txt configurat­ion file for a project that has just one source file written in C.
The output that’s generated by the cmake command when dealing with a simple CMakeCache.txt configurat­ion file for a project that has just one source file written in C.
 ??  ??
 ??  ?? This screenshot shows the CMake code of the CMakeCache.txt configurat­ion file used for the simple project that deals with C++ source files.
This screenshot shows the CMake code of the CMakeCache.txt configurat­ion file used for the simple project that deals with C++ source files.
 ??  ?? This is the output you’ll obtain from executing cmake on the root directory of the simple project and the make command on the build directory of the project.
This is the output you’ll obtain from executing cmake on the root directory of the simple project and the make command on the build directory of the project.
 ??  ?? Figure 4: This Figure shows how you can generate Graphviz files that show the dependenci­es between the targets of a CMake project.
Figure 4: This Figure shows how you can generate Graphviz files that show the dependenci­es between the targets of a CMake project.
 ??  ?? This shows the final version of the CMakeCache. txt configurat­ion file that instructs CMake to automatica­lly generate the CMake project dependenci­es using Graphviz. Automating tasks is always a good thing!
This shows the final version of the CMakeCache. txt configurat­ion file that instructs CMake to automatica­lly generate the CMake project dependenci­es using Graphviz. Automating tasks is always a good thing!

Newspapers in English

Newspapers from Australia