CMake/Basics

From Sidvind
Jump to: navigation, search

CMake is a cross-platform build system. Like most other build system CMake generates Makefiles for *nix based systems but may also generate other project files like KDevelop and Microsoft Visual Studio. I will focus on replacing custom makefiles with CMake.

Below is a very simple makefile which only builds a some c++ source files and links them together. The files have the rather standard *nix directory layout where the source is placed in the src directory and headers in the include directory. The application also relies on an external library named libquux.

Code: Makefile to replace

  1. VPATH=src
  2. OBJS=main.o fred.o barney.o wilma.o
  3.  
  4. all: $(OBJS)
  5.         g++ $(OBJS) -lquux -o FooBar
  6.  
  7. %.o : %.cpp
  8.         g++ -Iinclude $< -o $@

The first step to use CMake is to create a file called CMakeLists.txt in the root directory. This file starts with the project command which specifies the name of the project. This is both a reference to this project and the name of the target created, that is the executable in this case.

Code: Simple CMakeLists.txt (which is just as bad as the Makefile)

  1. PROJECT(FooBar)
  2.  
  3. INCLUDE_DIRECTORIES(include)
  4. ADD_EXECUTABLE(FooBar src/main.cpp src/fred.cpp src/barney.cpp src/wilma.cpp)
  5. TARGET_LINK_LIBRARIES(FooBar quux)

Most of this should be pretty self-explainable. The include_directories command specifies a list of directories which contains headers. The add_executable command creates an executable file from the supplied source files. There isn't a replacement for the makefile VPATH variable but there is other ways to overcome this limitation. Lastly, the target_link_library specifies a set of libraries which must be linked with the application. If one of the libraries is a reference to another project managed by CMake it will build this project before the current one. More about this later.

To build this using CMake you should first create a build directory. While out-of-source builds is the preferred way but it is not necessary. After deciding for a directory to use for the build you issue the command "cmake path/to/CMakeLists.txt", for instance "cmake ..". This will generate the makefiles needed. Assuming everything went well you can just issue make to build everything.

This is a quite straight-forward translation of the makefile but it is not really that much better. For instance the compilation will fail if libquux is not available on the target system. To resolve this issue it is better to let CMake look for the library:

Code: Slightly better CMakeLists.txt

  1. PROJECT(FooBar)
  2.  
  3. MESSAGE( STATUS "Looking for quux")
  4.  
  5. FIND_LIBRARY( QUUX_LIBRARY quux
  6.        /usr/lib64
  7.        /usr/lib
  8.        /usr/local/lib64
  9.        /usr/local/lib
  10.        /sw/lib
  11.        /opt/local/lib
  12.        DOC "The Quux library")
  13.  
  14. IF ( ${QUUX_LIBRARY} )
  15.        MESSAGE( STATUS "Looking for quux - found")
  16. ELSE ( ${QUUX_LIBRARY} )
  17.        MESSAGE( FATAL_ERROR "Looking for quux - not found")
  18. ENDIF ( ${QUUX_LIBRARY} )
  19.  
  20. INCLUDE_DIRECTORIES(include)
  21. ADD_EXECUTABLE(FooBar src/main.cpp)
  22. TARGET_LINK_LIBRARIES(FooBar ${QUUX_LIBRARY})

The find_library command will look for the library quux in the specified directories and set the variable QUUX_LIBRARY if found.