Monday, January 14, 2013

A Simple Cmake Tutorial

There are many Cmake tutorials available on internet. Still I had to struggle a bit to get exactly the things that I wanted. So I believe that the tutorial given below will be useful for a beginner who is looking for a quick and simple introduction into how cmake works. So, here we go !!

We are looking into the aspect of building static libraries in this example. I have the following directory structure for my package:

Utilities
  |------------ CMakeLists.txt
  |------------ /include
  |                    |------------ memalloc.h
  |------------ /lib
  |                    |------------ libmemalloc.a
  |------------ /src
                       |-------------- /memalloc
                                              |-------- CMakeLists.txt
                                              |--------- memalloc.cpp

The main folder 'Utilities' has three folders, namely, include, lib and src. The include contains all header files at one place. 'lib' should contain the static library 'libmemalloc.a' once it is built and the 'src' folder contains another folder named 'memalloc' that contains the file 'memalloc.cpp' that is needed for building the static library.

For this case, I need two 'CMakeLists.txt' one inside the main folder 'Utilities' and one inside the 'memalloc' folder within 'src' folder. Infact, all folders that would potentially produce an output such as a library or an executable should contain on 'CMakeLists.txt' file inside it.

The 'CMakeLists.txt' file within the main folder looks something as shown below:


#Specify the version being used
cmake_minimum_required(VERSION 2.8)

#Name your project here
project(UTIL)

# compiler
SET(CMAKE_CXX_COMPILER "g++")

# cpp flags
SET(CMAKE_CXX_FLAGS "-g -Wall")

# various project names
# go on adding multiple names for different projects
SET(PROJECT_NAMES "memalloc")

foreach(PROJECT_NAME ${PROJECT_NAMES})

  # add sub-directories
  add_subdirectory("${CMAKE_SOURCE_DIR}/src/${PROJECT_NAME}"
    "${CMAKE_CURRENT_BINARY_DIR}/out/${PROJECT_NAME}")

endforeach(PROJECT_NAME ${PROJECT_NAMES})

   -----------------------------------
For every project, there is a corresponding folder inside the 'src' folder. The content of the 'CMakeLists.txt' file inside the 'memalloc' folder is given below:


#include headers from this folder
include_directories(${UTIL_SOURCE_DIR}/include)

# source files
set(MEMALLOC_SOURCES "memalloc.cpp")

# Build Library
add_library(memalloc STATIC ${MEMALLOC_SOURCES})

# install directory
install(TARGETS memalloc 
  ARCHIVE DESTINATION "${UTIL_SOURCE_DIR}/lib" )

--------------------------------------------


Now execute the following commands inside the 'Utilities' folder:

$ mkdir build
$ cd build

$ cmake ../
-- The C compiler identification is GNU
-- The CXX compiler identification is GNU
-- Check for working C compiler: /usr/bin/gcc
-- Check for working C compiler: /usr/bin/gcc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/swagat/TCS/Programs/utilities/build

$ make
Scanning dependencies of target memalloc
[100%] Building CXX object out/memalloc/CMakeFiles/memalloc.dir/memalloc.cpp.o
Linking CXX static library libmemalloc.a
[100%] Built target memalloc

$ make install
[100%] Built target memalloc
Install the project...
-- Install configuration: ""
-- Installing: /home/swg/utilities/lib/libmemalloc.a

------------------------------

If you want to build libraries within a given folder, then your CMakeLists.txt file should contain the following lines:



set(MVG_SOURCE "mvg.cpp")
# Build Library
add_library(mvg STATIC ${MVG_SOURCE})
set_target_properties(mvg PROPERTIES ARCHIVE_OUTPUT_DIRECTORY
  ${CMAKE_SOURCE_DIR}/lib)   

The library will be built within the lib folder under the root directory. Hence, you do not have use make install command as you did above. Make install command should be used for putting the files at a different location within your system. 

-----------------------------------

In order to build binary inside a specific directory instead of the default location, use the following statements:


add_executable(testmvg ${MVG_TEST_SRC})
target_link_libraries(testmvg ${GLIBS} ${MVG_LIB} ${MEM_LIB} )           
set_target_properties(testmvg PROPERTIES RUNTIME_OUTPUT_DIRECTORY
  ${CMAKE_SOURCE_DIR}/bin)  

--------------------------------