Monday, December 16, 2013

CMake - basic tutorial

This is a short tutorial about CMake with a practical example. CMake is a tool to generate build files but does not compile! So, if you use Linux, CMake creates Makefile which make tool uses it to actually build your C++ application. The advantage of CMake over the standard make, is writing a CMake script is relatively easy comparing to a Makefile script. Another advantage is, CMake can generate build files for other platforms, so if you want to build your application for another platform like MS Windows, CMake does that for you just by telling which platform you want to build for.

Unfortunately a lot of examples found on the internet is based on one simple Hello World file, which doesn't represent the real power of CMake and also doesn't represent a realistic directory structure of real projects.

Ok, below we see how a typical project folder looks like:
Project_folder
             |__ src
             |       |__ main.cpp
             |       |__ xxx.cpp
             |       |__ yyy.cpp
             |       |__ zzz.cpp  
             |__ include
             |__ libs
             |__ build
             |__ CMakeLists.txt
  
Now, we want to tell CMake that in the folder 'src' there is the source files, in 'include' there is the include files (in case of C/C++) and in the 'libs' we have the libraries. The build folder will contain the build files that CMake generates.
CMakeLists.txt is the script CMake will read to know how to build the project.
So, how would our CMakeLists.txt look like?
Below we have an example of CMakeLists.txt:



#------------------------------------
# Minimum CMake version required.

cmake_minimum_required(VERSION 2.6)


#------------------------------------
# Not necessary, but recommended, projectname:

project(MyBoostTest)

#------------------------------------
# The version number.
set (Tutorial_VERSION_MAJOR 1)
set (Tutorial_VERSION_MINOR 0)

set (CMAKE_CXX_FLAGS "-g -Wall")

#------------------------------------

# Declare var names for source path
#------------------------------------
set (INC ${PROJECT_SOURCE_DIR}/include)
set (SRC ${PROJECT_SOURCE_DIR}/src)
set (LIBS ${PROJECT_SOURCE_DIR}/libs)

#------------------------------------

# Add source files to SRCS variable
#------------------------------------
list(APPEND SRCS ${SRC}/main.cpp
${SRC}/xxx.cpp ${SRC}/yyy.cpp ${SRC}/zzz.cpp)
#------------------------------------

# Tell CMake where the include files are
#------------------------------------
include_directories(${INC})
#------------------------------------

# is the same as include_directories
# in this case, we have no real lib files
#------------------------------------
link_directories(${LIBS})
#------------------------------------


# name the executable 'MAIN' and tell
# CMake which files are used
#------------------------------------
add_executable(MAIN ${SRCS})
#------------------------------------

# Tell CMake what libraries to link
# with. For example the BOOST's regex

# but it could also a library in the libs folder,
# which can be built with:
# add_library(mylib ${LIBS}/lib_x)
#------------------------------------
target_link_libraries(MAIN boost_regex)
#------------------------------------


 
If we run CMake in the same directory as where the above CMakeLists.txt resides, a bunch of files and folder will be created in that same directory. This will clutter up our project folder, to prevent that we tell CMake to put the generated build files in the build folder:

cmake -Bbuild -H.
If everything went well, we'll see the build folder with the generated build files. If we than move to the build folder, we can run the following command to compile the sources (assuming this is a C++ project on a Linux machine with the 'make' tool):
make .
If your sourcecode is successfully compiled, you'll see the MAIN executable in the build folder.

So, it's quite easy, you just need to tell CMake where the source files and libraries are, what to build and CMake is doing the ugly work for you.
We also use just one CMakeLists.txt, normally you should have CMakeLists.txt in every sourcecode folder, but for the sake of simplicity, we use only 1 CMakeLists.txt. I'll punt another CMake example next time with multiple CMakeLists.txt. 

No comments:

Post a Comment

NSNotification example