CMake Notes

This a post on some of my notes with using CMake. Specifically, I am using CMake with Clion, an IDE from JetBrains.

This post covers the following topics

  1. Intro to CMAKE basics
  2. How to debug CMAKE errors
  3. How to create a new subdirectory with source files in CMake
  4. How to tell the CMake to find the headers in a separate include directory
  5. How to build a library out of header and source files
  6. How to link a library to an executable
  7. How to change CMAKE’s C or C++ compiler
  8. How to add compiler flags to CMAKE
  9. How to get debugger to be able to debug header files
  10. How to add files recursively in the sub directories to a variable
  11. How to get CMake to support std c++11
  12. How to copy over a file from source to build/bin directory

CLion has good support with cmake, which is the default build system for C++ project. I have configured to start with it.

The first thing I am trying to do is to figure out how to do a “out-of-source” build for easy management of source code.

The first thing to know about CMake is that most of the configuration information (the most important parts) is in “CMakeLists.txt“. It sets up variables such as build directories, source directories and everything.

CLion by default, would build the files in a directory called ” cmake-build-debug/”. This essentially the build directory for out-of-source build. This directory would contain all the generated Makefiles for Clion and the binary executable.

The command executed is essentially the following

cmake –build /path-to-project/cmake-build-debug –target projectName — -j 8

How to DEBUG CMake errors 

This is the most important technique, given there will always be issues that can’t be resolved easily by looking at CMakeLists.txt. Always go to the generated Makefile, run

Makefile VERBOSE = 1

to print out all the commands. With the command, you can figure out what is wrong, weather it is missing include files? or linking issues. Generally, you will need to have some knowledge of Makefile. But this is a solid approach to deal with errors.

How to create a new subdirectory with source files in CMake

If you just want to access the source files, using the

file(GLOB SOURCES “src/*.cpp”) 

Create a new subdirectory, add the following command in the parent directory CMakeList.txt

The documentation on file(Glob)

FILE

https://cmake.org/cmake/help/v3.0/command/file.html

FILE (GLOB, var, expression)

GLOB will generate a list of all files that match the globbing expressions and store it into the variable. Globbing expressions are similar to regular expressions, but much simpler. If RELATIVE flag is specified for an expression, the results will be returned as a relative path to the given path. (We do not recommend using GLOB to collect a list of source files from your source tree. If no CMakeLists.txt file changes when a source is added or removed then the generated build system cannot know when to ask CMake to regenerate.)

How to tell the CMake to find the headers in a separate include directory

In the top level directory’s CMakeLists.txt file, put in the following command to add the directory to header search path.

include_directories(./include/)

For directory layout like the following

project

–src

— include

Now all the source files in src can reference header files in include with the following

include

if you have even more subdirectories un include

project

–src

— include

—-header_dir

include <header_dir/header.h>

In order to get CLion to work, you need to reload the changes, and the IDE would be able to locate the header files. The following link has some quick examples on specifying header search path

https://www.jetbrains.com/help/clion/2016.1/quick-cmake-tutorial.html

References

(A super good hello world quick intro to CMake, but doesn’t go into the subdirectories part)

http://derekmolloy.ie/hello-world-introductions-to-cmake/

https://tuannguyen68.gitbooks.io/learning-cmake-a-beginner-s-guide/content/chap1/chap1.html (short basics intro on a few builtin variables)

How to build a library out of header and source files

Sometimes you want to wrap a bunch of files into a library that can be referenced in other parts of the project. For example, if you want to set up a test folder that needs to reference source codes, then it is possible to pack the source header files and source files into a library.

# build a front end library used for unit testing
file(GLOB LIB_SOURCE_FILES src*.cpp)
file(GLOB HEADER_FILES include/*.h)

add_library(source_lib ${HEADER_FILES} ${LIB_SOURCE_FILES})

What this command would do is that it would invoke

/usr/bin/ar qc lib/libsource_lib.a  xxx.o yyy.o

if you do

man ar

you can find that ar is a utility that create and maintain libraries. -q (quickly) -c(create archive)

How to link a library to an executable 

There are two phases to generate an executable file. First you go through compilation, which generates the machine code (several object files potentially). However, in order to run the program, there is also a second phase, linking, which  creates a single executable file from multiple object files.

http://www.cprogramming.com/compilingandlinking.html (a good quick intro)

In order for CMake to work, you need to specify 1) executable, 2) the library to link it with

For example, here we show you how to set up unit tests using Google Unit Test and project source code (compiled into library using the snippet from above)

# build a source code library used for unit testing
file(GLOB LIB_SOURCE_FILES src*.cpp)
file(GLOB HEADER_FILES include/*.h)

add_library(source_lib ${HEADER_FILES} ${LIB_SOURCE_FILES})

# build Google Unit Test as a library 
set(GTEST_SOURCE ./test/gtest/gtest-all.cc)
set(GTEST_HEADER ./test/gtest/gtest.h)
add_library(gtest ${GTEST_HEADER} ${GTEST_SOURCE})

# build the final unit_test executable using 
# the source file test.cpp and the two libraries
set(TEST_SOURCE_FILES ./test/test.cpp)
add_executable(unit_test ${TEST_SOURCE_FILES})
target_link_libraries(unit_test gtest)
target_link_libraries(unit_test graphitlib)

How to change CMAKE’s C or C++ compiler 

SET(CMAKE_C_COMPILER /path/to/c/compiler)
SET(CMAKE_CXX_COMPILER /path/to/cpp/compiler)

How to add compiler flags to CMAKE

For example

set(CMAKE_CXX_FLAGS “-fopnemp”)

How to get debugger to be able to debug header files

Make sure to include the header files in the sources too.

How to add files recursively in the sub directories to a variable 

file(GLOB_RECURSE HEADER_FILES include/*.h)

How to get CMake to support std c++11

You need at least CMake 3.1,

cmake_minimum_required(VERSION 3.1)

 

How to copy over a file from source to build/bin directory

This is useful when you want to use a python script to wrap around the binaries you generate.

A few requirements are that you might want to make sure the copy in the build/bin directory is always up to date with the file in source directory.

To do that you can use the following command (input is the file in source, output would be the file in build/bin

configure_file(input output COPYONLY)

 

 

Advertisements
This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s