cmake
Syntax
#, comment
${var}, access value defined in the variable "var"
CMake Directory Variables
CMAKE_SOURCE_DIR, the directory that contains the top-level CMakeLists.txt file
CMAKE_CURRENT_SOURCE_DIR, the directory containing the CMakeLists.txt file that is currently being processed
CMAKE_BINARY_DIR, the path to the top level of the build tree
CMAKE_CURRENT_BINARY_DIR, the path to the binary directory currently being processed
PROJECT_SOURCE_DIR, top level source directory for the current project
projectName_SOURCE_DIR, source directory for the named project
PROJECT_BINARY_DIR, top level binary directory for the current project
projectName_BINARY_DIR, binary directory for the named project
CMAKE_C_COMPILER, C compiler
CMAKE_CXX_COMPILTER, C++ compiler
CMAKE_C_FLAGS, C flags
CMAKE_CXX_FLAGS, C++ flags
EXECUTABLE_OUTPUT_PATH, output path for executable program
LIBRARY_OUTPUT_PATH, output path for libraries
CMAKE_BUILD_TYPE, figure out build type, [Debug|Release]
BUILD_SHARED_LIBS, figure out library build model, [OFF|ON]
Example 1
// main.c
#include <stdio.h>
int main()
{
printf("Hello World!\n");
return 0;
}
// CMakeLists.txt 1
cmake_minimum_required (VERSION 2.6)
project (Hello)
add_subdirectory(src)
// CMakeLists.txt 2
add_executable(Hello main.c)
cd build
cmake ..
make, generate executable file "Hello" in build/src
Example 2
// util.h
#ifndef UTIL_H
#define UTIL_H
void hello();
void world();
void disp();
#endif
// hello.c
#include <stdio.h>
#include "util.h"
void hello()
{
printf("Hello ");
}
// util.c
#include <stdio.h>
#include "util.h"
void disp()
{
hello();
world();
}
// world.c
#include <stdio.h>
#include "util.h"
void world()
{
printf("World!\n");
}
// main.c
#include <util.h>
#include "util.h"
int main()
{
disp();
return 0;
}
Using include_directories
# CMakeLists.txt 1
cmake_minimum_required(VERSION 2.6)
project(c1)
include_directories(${PROJECT_SOURCE_DIR}/include) # add before adding subdirectory
add_subdirectory (src)
add_executable(Hello main.c)
target_link_libraries(Hello mylib)
# CMakeLists.txt 2
aux_source_directory(. SRC_LIST)
add_library(mylib ${SRC_LIST})
Using target_include_directories
# CMakeLists.txt 1
cmake_minimum_required(VERSION 2.6)
project(c1)
add_subdirectory (src)
add_executable(Hello main.c)
target_include_directories (Hello PUBLIC ${PROJECT_SOURCE_DIR}/include)
target_link_libraries(Hello mylib)
# CMakeLists.txt 2
aux_source_directory(. SRC_LIST)
add_library(mylib ${SRC_LIST})
target_include_directories(mylib PUBLIC ${PROJECT_SOURCE_DIR}/include)
cd build
cmake ..
make, generate executable file "Hello" in build, generate libmylib.a in build/src
Example 3
// hello.h
#ifndef HELLO_H
#define HELLO_H
void hello();
#endif
// util.h
#ifndef UTIL_H
#define UTIL_H
void disp();
#endif
// world.h
#ifndef WORLD_H
#define WORLD_H
void world();
#endif
// main.c
#include "util.h"
int main()
{
disp();
return 0;
}
// util.c
#include <stdio.h>
#include "util.h"
#include "hello.h"
#include "world.h"
void disp()
{
hello();
world();
}
// hello.c
#include <stdio.h>
#include "hello.h"
void hello()
{
printf("Hello ");
}
// world.c
#include <stdio.h>
#include "world.h"
void world()
{
printf("World!\n");
}
# CMakeLists.txt 1
cmake_minimum_required(VERSION 2.6)
project(c3)
include_directories(${PROJECT_SOURCE_DIR}/include)
add_subdirectory (src)
# CMakeLists.txt 2
aux_source_directory(. SRC_LIST)
add_subdirectory(hello)
add_subdirectory(world)
add_executable(Hello.e ${SRC_LIST})
target_link_libraries(Hello.e hello world)
# CMakeLists.txt 3
aux_source_directory(. HELLO_LIST)
add_library(hello ${HELLO_LIST})
# CMakeLists.txt 4
aux_source_directory(. WORLD_LIST)
add_library(world ${WORLD_LIST})
cd build
cmake ..
make, generate executable file "Hello.e" in build/src, generate libhello.a in build/src/hello, generate libworld.a in build/src/world
Example 4
Code is same as above
// CMakeLists.txt 1
cmake_minimum_required(VERSION 2.6)
project(c3)
include_directories(${PROJECT_SOURCE_DIR}/include)
add_subdirectory (src)
// CMakeLists.txt 2
aux_source_directory(. SRC_LIST)
add_subdirectory(hello)
add_subdirectory(world)
add_subdirectory(util)
add_executable(Hello.e ${SRC_LIST})
target_link_libraries(Hello.e util)
// CMakeLists.txt 3
aux_source_directory(. UTIL_LIST)
add_library(util ${UTIL_LIST})
target_link_libraries(util hello world)
// CMakeLists.txt 4
aux_source_directory(. HELLO_LIST)
add_library(hello ${HELLO_LIST})
// CMakeLists.txt 5
aux_source_directory(. WORLD_LIST)
add_library(world ${WORLD_LIST})
It is like the code is organized as the following
Functions
cmake_minimum_required(VERSION major.minor), set the minimum required version of cmake
project(name, version, language), set a name, version, and enable languages for the entire project
aux_source_directory(dir, var), collects the names of all the source files in the specified directory and stores the list in the "var" provided, "var" should be unique
add_library(libName, [STATIC|SHARED|MODULE], source)
- libName, corresponds to the logical target name and must be globally unique within a project
- STATIC libraries are archives of object files
- SHARED libraries are linked dynamically and loaded at runtime
add_executable(name, source), add an executable to the project using the specified source files
add_subdirectory(dir), add a subdirectory to the build
include_directories(dir), add the given directories to those the compiler uses to search for include files, relative paths are interpreted as relative to the current source directory, affects directory scope, all targets in this CMakeList, as well as those in all subdirectories added after the point of its call
target_include_directories(target, INTERFACE|PUBLIC|PRIVATE, dir), specify include directories or targets to use when compiling a given target
set(variable, value), set a CMake, cache or environment variable to a given value
file(GLOB variable value), GLOB will generate a list of all files that match the globbing expressions and store it into the variable
file(GLOB_RECURSE variable value), traverse all the subdirectories of the matched directory and match the files
find_library(variable libName), this command is used to find a library
target_link_libraries(target libName), specify libraries or flags to use when linking a given target, cmake like to use full path of libraries
message("Code: " ${c_files}), print information
Publish
// test.c
#include "util.h"
int main()
{
disp();
return 0;
}
# CMakeLists.txt 1
# set up the minimum version of camke
cmake_minimum_required(VERSION 2.6)
# project name
project(c6)
# set up the path for compiled static libraries and dynamic library
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/build/lib)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/build/bin)
# figure out the path of header files
include_directories(${PROJECT_SOURCE_DIR}/include)
# figure out the path of compiled libries
link_directories(${PROJECT_SOURCE_DIR}/build/lib)
# add sub directories
add_subdirectory(src)
add_subdirectory(test)
# set up install directory, default is /usr/local
# set(CMAKE_INSTALL_PREFIX ${PROJECT_SOURCE_DIR}/install)
# copy readme.md and license to the install directory
file(COPY ${PROJECT_SOURCE_DIR}/README.md DESTINATION ${CMAKE_INSTALL_PREFIX})
file(COPY ${PROJECT_SOURCE_DIR}/LICENSE DESTINATION ${CMAKE_INSTALL_PREFIX})
# CMakeLists.txt 2
# recursive search *.c file and save names to a variable
file(GLOB_RECURSE c_files "*.c")
# turn off MACOSX_RPATH warning
set(CMAKE_MACOSX_RPATH 1)
# create a static library "libhelloworld.a" and a dynamic library "libhelloworld.so"
# dynamic library will be "libhelloworld.dylib" on Mac
add_library(helloworld_lib_shared SHARED ${c_files})
add_library(helloworld_lib_static STATIC ${c_files})
set_target_properties(helloworld_lib_shared PROPERTIES OUTPUT_NAME "helloworld")
set_target_properties(helloworld_lib_static PROPERTIES OUTPUT_NAME "helloworld")
set_target_properties(helloworld_lib_shared PROPERTIES VERSION 1.2 SOVERSION 1)
# create an executable program
add_executable(Hello.e main.c)
target_link_libraries(Hello.e helloworld)
# install executable program to folder "bin" in the install directory
# install dynamic library to folder "lib" in the install directory
# install static library to folder "lib" in the install directory
INSTALL(TARGETS Hello.e helloworld_lib_shared helloworld_lib_static
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)
# install header files to folder "include" in the install directory
INSTALL(DIRECTORY ${PROJECT_SOURCE_DIR}/include/ DESTINATION include)
# CMakeLists.txt 3
# recursively find *.c files
file(GLOB_RECURSE c_files *.c)
# print out a list of source files
message("test code: " ${c_files})
# create executable test program
add_executable(mytest ${c_files})
target_link_libraries(mytest helloworld)
# install executable test program to folder "bin" in the install directory
INSTALL(TARGETS mytest
RUNTIME DESTINATION bin)
cd build
cmake ..
make, generate executable files in build/src, generate libraries in build/lib
make install, install executable programs to inallPath/bin, install libraries to installPath/lib, install header files to installPath/include
General
How to collect source files with CMake without globbing?
- 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
- Use GLOB, "touch CMakeLists.txt", let cmake know new source files have been added
Install to a different directory
- cmake -DCMAKE_INSTALL_PREFIX=path ..
- make
- make install
CMake-GUI
- Where is the source code, figure out project folder
- Where to build binaries, figure out build folder
- Configure, make create variable available
- Generate, genreate makefile
Download
Reference