CMake/Examples

From KitwarePublic
Jump to: navigation, search

Welcome to the CMake Wiki Examples! These short snippets which show you how to perform many common CMake procedures. Please see [1] for the verbose documentation.

Please add examples as you find common procedures which are not explained here!

Basics

Set a CMake variable

SET(VARIABLE VALUE)

View a CMake variable

MESSAGE("CMAKE_BINARY_DIR: ${CMAKE_BINARY_DIR}")

View a system variable

MESSAGE("$ENV{PATH}")

Check operating system

 IF(WIN32)
   ...do something...
 ELSE(WIN32)
   ...do something else...
 ENDIF(WIN32)

Check operating system

IF(CMAKE_SYSTEM_NAME STREQUAL Linux)

Check if environment variable is set

Test if an environment variable is defined, bail out if it is not

Normally, operating system environment variables are referenced with syntax like $ENV{FOO_HOME}, and CMake variables are referenced as ${FOO_VAR}, but to make the DEFINED command work with environment variables you drop the $.

IF(DEFINED ENV{FOO_HOME})
  message("...using Foo found in $ENV{FOO_HOME}")
ELSE()
  message("FOO_HOME is not defined.  You must tell CMake where to find Foo")
  # exit early 
  return()
ENDIF()

The mailing list has some alternative proposals for how to accomplish this

Lists

Check if a list contains a value

list(FIND VTK_MODULES_ENABLED "vtkFiltersParallel" HasMyModule)
 
IF(HasMyModule EQUAL -1)
  message(FATAL_ERROR "You must build VTK with more modules.")
ENDIF()

Outputs

Message

MESSAGE("Hello world")

Output a Variable

message("VTK Using Boost? ${VTK_USE_BOOST}")

Error

MESSAGE(FATAL_ERROR "An error occured.")

Conditional Statement (if)

There are two allowable syntaxes:

if(something)
 do something
else(something) # the argument must match the if(...)
 do something else
endif(something) # the argument must match the if(...)

The following is also allowed. It is easier to read (because "else(the same thing)" doesn't really make sense if you read it like c++, for example), but it is also easier to confuse yourself with nested ifs.

if(something)
 do something
else()
 do something else
endif()

Example:

if (!VTK_USE_BOOST)
  MESSAGE(SEND_ERROR "VTK must be built with VTK_USE_BOOST=ON.")
endif ()

Logical Operators

These operators work exactly as you would expect.

AND

if(A AND B)

OR

if(A OR B)

NOT

if(NOT A)

Compound

if(NOT(A AND B))

Finding Packages

Most of the time large packages will have their Find[PackageName].cmake file included in the cmake distribution. If that is the case, all you must do it:

FIND_PACKAGE(Eigen3)

Specifying where to look for .cmake files

If you place your FindXYZ.cmake and UseXYZ.cmake files in the same directory as your main CMakeLists.txt file, you can tell CMake to try to use them first before looking at system paths by doing:

set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/" ${CMAKE_MODULE_PATH})

Checking if a package was found

Most of the time the [PackageName]_FOUND variable is defined. You can use it like this:

FIND_PACKAGE(Eigen3)
if(EIGEN3_FOUND)
 ... do something ...
endif(EIGEN3_FOUND)

Suppress warnings

Sometimes you may want to optionally include a package. You can suppress the warning about the package not being found with:

FIND_PACKAGE(Eigen3 QUIET)

Fix Mininum Version Error/Warning

cmake_minimum_required(VERSION 2.6.0 FATAL_ERROR)


Look in the directory that the CMakeLists.txt file is for header and implementation files

INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR})

or

INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})

Set Link Directories

If a library you are using does not have a [LibraryName].cmake, you can do

find_library(OPENSSL_LIB ssl $ENV{OPENSSL_LIB_PATH})

This will check the environment for a variable named OPENSSL_LIB_PATH. If it exists, you can then use

target_link_libraries(mytarget ${OPENSSL_LIB})

If it does not, it can be set through the CMake GUI.

Set Include Directories

This command adds a path to the include directories, you do NOT have to do the 'export' style ``keep everything that is here and add this one syntax.

INCLUDE_DIRECTORIES(/some/directory)

View the directories that are set

get_property(inc_dirs DIRECTORY PROPERTY INCLUDE_DIRECTORIES)
message("inc_dirs = ${inc_dirs}")

Automate configure and generate

Note 'cmake' instead of 'ccmake' (ccmake is curses cmake (curses is the terminal gui))

cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=/usr/mylocation ../

Compiler options

Set a cmake flag

ccmake ../../src/boost -DCMAKE_IS_EXPERIMENTAL=YES_I_KNOW

Set a cpp flag/preprocessor definition

SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__WXGTK__")

Force g++

Ocassionally you will come across files with the extension .c that actually contain c++ code. CMake treats the file based on its extension. If you want to override this behavior (in this case, compile .c files with your c++ compiler), do the following:

set(MySources main.c anotherFile.c)
add_executable(SpinRecognize ${MySource})
set_source_files_properties(${MySources} PROPERTIES LANGUAGE CXX)

Per-target

set_target_properties(myexe_target
                                PROPERTIES COMPILE_FLAGS "-Wall")

Set the default build type

SET(CMAKE_BUILD_TYPE Debug CACHE STRING "default to debug" FORCE)

Custom variable

Here is a list of supported variable types: http://www.cmake.org/cmake/help/cmake2.6docs.html#command:set

String

SET(BUILD_PARAVIEW_PLUGIN ON CACHE STRING "Build Paraview plugin?" FORCE)

Bool

SET(DAI_WITH_BP ON CACHE BOOL "Belief Propagation" FORCE)

Comparison

if(DAI_WITH_BP EQUALS ON)
 #do something
endif(DAI_WITH_BP EQUALS ON)

This is equivalent to

if(DAI_WITH_BP)
 #do something
endif(DAI_WITH_BP)

Linking to specific libraries

ITK

Add the path to your environment:

export ITK_DIR=/home/doriad/bin/ITK

Then in the CMakeLists.txt use:

FIND_PACKAGE(ITK REQUIRED)
INCLUDE(${ITK_USE_FILE})
 
ADD_EXECUTABLE(CastImageFilter CastImageFilter.cxx)
TARGET_LINK_LIBRARIES(CastImageFilter
vtkHybrid
ITKIO ITKBasicFilters ITKCommon
)

VXL

Add the path to your environment:

export VXLBIN="/home/doriad/bin/vxl"

Then in the CMakeLists.txt use:

FIND_PACKAGE(VXL REQUIRED)
INCLUDE(${VXL_CMAKE_DIR}/UseVXL.cmake)

VTK

Add the path to your environment:

export VTK_DIR="/home/doriad/bin/VTK"

Then in the CMakeLists.txt use:

FIND_PACKAGE(VTK REQUIRED)
INCLUDE(${VTK_USE_FILE})

Boost

Lets assume we built boost with ./bjam --prefix=/home/doriad/bin install

Then for CMake to find Boost, all you need is to add to your .bashrc:

export BOOST_ROOT="/home/doriad/bin"

Then in the CMakeLists.txt use:

SET(Boost_USE_MULTITHREAD ON) #set a flag
FIND_PACKAGE(Boost)
INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES} ${Boost_INCLUDE_DIRS})
LINK_DIRECTORIES(${LINK_DIRECTORIES} ${Boost_LIBRARY_DIRS})

OpenCV

Add to the environment:

export OpenCV_DIR=/home/doriad/bin/OpenCV

Then in the CMakeLists.txt use:

FIND_PACKAGE(OpenCV REQUIRED )
INCLUDE_DIRECTORIES( ${OPENCV_INCLUDE_DIR} )
 
ADD_EXECUTABLE(Scalar Scalar.cxx)
TARGET_LINK_LIBRARIES(Scalar ${OpenCV_LIBS})

Get Help Using a Library

cmake --help-module FindBoost

Add new libraries to CMake

/usr/share/cmake/Modules/FindOpenGL.cmake|

Dependency Graph

ccmake ../src/Program/ --graphviz=test.graph 
dotty test.graph

CTest

Run a specific test by number

e.g. Test 622

ctest -I 622,622

Run a range of tests

e.g. Test 622 to 625

ctest -I 622,625

Run a test by name

ctest -R "itkTransformPoint*"|

Show verbose output of a test

ctest -V -R "itkTransformPoint*"|

Create a Test

cmake_minimum_required(VERSION 2.6)
 
project(simple)
ENABLE_TESTING()
 
add_executable(simple simple.cpp)
add_test(SimpleTest simple)

Link to a library

ADD_EXECUTABLE(ColoredLines ColoredLines.cpp)
TARGET_LINK_LIBRARIES(ColoredLines vtkHybrid)


Create a library

add_library(MatlabLibrary ./MatlabDll/LidarK.cpp)

Installing executables

Once your project is built, you can use the 'install' make target to copy the executables to the directory specified by CMAKE_INSTALL_PREFIX.

add_executable(test test.cxx)
install(TARGETS test RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX})

If you get an error like:

error while loading shared libraries: I get
libwx_gtk2u_core-2.9.so.1: cannot open shared object file: No such file or directory

you should add:

SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)

to your CMakeLists.txt file.

Utilities

Add non-compiled files to a project

This allows files that are not compiled to be added to a project (Qt Creator, for example) while keeping them logically separated from files that are compiled (in the normal add_executable command):

add_custom_target(MyProjectSources SOURCES
MyProject.h
)

Recursively add subdirectories to INCLUDE_DIRECTORIES

MACRO(HEADER_DIRECTORIES return_list)
    FILE(GLOB_RECURSE new_list *.h)
    SET(dir_list "")
    FOREACH(file_path ${new_list})
        GET_FILENAME_COMPONENT(dir_path ${file_path} PATH)
        SET(dir_list ${dir_list} ${dir_path})
    ENDFOREACH()
    LIST(REMOVE_DUPLICATES dir_list)
    SET(${return_list} ${dir_list})
ENDMACRO()