CMake可通过与平台无关的CMakeList.txt来定制整个编译流程,然后根据目标用户的平台进一步生成适配该平台的Makefile来编译构建工程的。
用CMake编译时,首先执行cmake path,将会按CMakeLists.txt所指定的规则生成Makefile,其中path为CMakeLists.txt所在的路径。然后使用make命令按照生成Makefile进行编译。
cmake_minimum_required(VERSION 3.10)
#set the project name
project(Tutorial)
#add the executable
add_executable(Tutorial tutorial.cxx)
CMAKE_BINARY_DIR :binary files的主路径
CMAKE_CURRENT_BINARY_DIR: 当前编译的路径
PROJECT_BINARY_DIR: 当前工程编译的路径
Load and run CMake code from a file or module
如果是module,cmake将会在CMAKE_MODULE_PATH或Cmake module的路径下找module.cmake
设置source变量为a, b,c.cpp, 之后${source}指代a, b, c.cpp
编译该target时会将include路径下的头文件编译进去
PRIVATE: 该include只被加载到该target中;
PUBLIC: 若target为library,该include不仅会编译进该library,其他任何链接该library的 target都会加载该include;
INTERFACE: 该include可以被添加到任何链接该library的target的include directories, 但该target本身并不会被编译
编译该target时会将libaray链接进去
依赖source生成library
参数可选static, shared, 分别生成静态库libxxx.a或动态库libxxxx.so
alias: 类似于target别名,用来指代target;
add_library(project_name INTERFACE) : 当创建的library只依赖头文件时,用INTERFACE来创建无任何输出的target。
install一般在放在CMakeLists.txt的最后一个模块,编译完成后,执行make install, 可以将source copy到dest中, 其中source可以是targets, directory,或者files。
另外,如果是library a, 因为是未编译完成的target,所以,要用TARGETS模式,且用"a LIBRARY"来指代编译生成的libaray a。
若dest非绝对路径,将默认放在base install location下的dest下。the base install location是由CMAKE_INSTALL_PREFIX来控制,一般可通过"cmake .. -DCMAKE_INSTALL_PREFIX = ${CMAKE_BINARY_DIR}"来设置,或者运行"make install DESTDIR=/tmp/stage", 将会创建安装路径${DESTDIR}/${CMAKE_INSTALL_PREFIX}做为base install location.
一般有以下的编译类型:
Release: 编译时添加"-O3 -DNDEBUG" flags
Debug: "-g"
MinSizeRel: "-Os -DNDEBUG"
RelWithDebInfo: "-O2 -g -DNDEBUG"
编译类型可以通过"cmake .. -DCMAKE_BUILD_TYPE=Release"来指定。若没有指定具体的类型,可用以下方式来设置默认的编译类型。
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message("Setting build type to 'RelWithDebInfo' as none was specified.")
set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build." FORCE)
# Set the possible values of build type for cmake-gui
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release"
"MinSizeRel" "RelWithDebInfo")
endif()
CMAKE_CXX_FLAGS: c++
CMAKE_C_FLAGS: c
CMAKE_LINKER_FLAGS: linker flags
设定方式一:set
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DEX2" CACHE STRING "Set C++ Compiler Flags" FORCE)
其中,"CACHE STRING "Set C++ Compiler Flags" FORCE"用于使CMake flags可以在CMakeCache.txt中进行设置。
设定方式二:target_complie_definitions
target_compile_definitions(cmake_examples_compile_flags
PRIVATE EX3)
上述方式将在编译target时,添加-DEX3,即定义了EX3的宏。
一旦设定了编译flag,所有targets将会按设定的flag进行编译。
Boost: 要找的library name
1.46.1:要找的Boost最低版本
REQUIRED: 表示这个是必需的,如果找不到将会失败;
COMPONENTS: the list of components to find in the library
如果找到对应的package,将会创建XX_FOUND变量,可以用这个变量来检测是否找到对应的package, 用XX_INCLUDE_DIRS来指代找到的package的头文件的位置, 如: Boost_INCLUDE_DIRS。用XX_LIBRARY来指代library的位置。
if(Boost_FOUND)
message ("boost found")
include_directories(${Boost_INCLUDE_DIRS})
else()
message (FATAL_ERROR "Cannot find Boost")
endif()
CMAKE_C_COMPILER: c
CMAKE_CXX_COMPILER: C++
CMAKE_LINKER: 用于编译时链接binary
方式一:
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
# check results and add flag
if(COMPILER_SUPPORTS_CXX11)#
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
elseif(COMPILER_SUPPORTS_CXX0X)#
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
else()
message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
endif()
include(CheckCXXCompilerFlag): 告诉cmake把这个函数包含进来以使用;
cmake支持尝试用传进CHECK_CXX_COMPILER_FLAG中的任何flags进行编译,并把结果放在传进这个函数的变量中,用于判断当前环境是否支持该flags。
方式二:
set(CMAKE_CXX_STANDARD 11)
设置CMAKE_CXX_STANDARD后, CMake将会在编译时设置合适的,与设置最接近的flags,并把将其作用于所有targets。
方式三:
target_compile_features(target PUBLIC cxx_auto_type)
message("List of compile features: ${CMAKE_CXX_COMPILE_FEATURES}")
cmake自动选择合适的编译flags。
可以用${CMAKE_CXX_COMPILE_FEATURES}来列出所有的features。
添加subdir,并按subdir下的CMakeLists.txt进行编译;
当用project()创建project时,CMake将会自动为该project创建一系列的变量,这些变量将可以被其他project或主project使用。
根据ver.h.in构建生成ver.h, 其中ver.h.in可以使用cmake及CMakeLists.txt中定义的变量,如,${PROJECT_BIANARY_DIR};
if(<condition>)
message("do stuff")
elseif(<condition>)
message("do other stuff")
else()
message("do other other stuff")
endif()
set(list 1 2 bar)
foreach(var ${list} foo)
message("the val is "${var})
endforeach()
#运行结果:
the val is 1
the val is 2
the val is bar
the val is foo
functions与macros用法是类似的,但不同的是functions有自己的scope,但macros没有,因此定义在macros中的变量将会在全scope中被用到,因此,macros适合较为简短精炼的function。
function与macros另一点不同的地方是参数传递的方式,macros的参数不是设定为variables,而是间接引用,或者可理解为直接展开,因此,要注意避免;
macro(print_list my_list)
foreach(var IN LISTS my_list)
message("${var}")
endforeach()
endmacro()
set(my_list a b c d)
set(my_list_of_numbers 1 2 3 4)
print_list(my_list_of_numbers)
# prints:
# a
# b
# c
# d
protocol buffers是一种数据序列化格式,使用.proto来描述数据,可用protobuf编译器将其转化为c++的源码。
PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS AddressBook.proto)
# Add an executable
add_executable(protobuf_example
main.cpp
${PROTO_SRCS}
${PROTO_HDRS})
target_include_directories(protobuf_example
PUBLIC
${PROTOBUF_INCLUDE_DIRS}
${CMAKE_CURRENT_BINARY_DIR}
)
# link the exe against the libraries
target_link_libraries(protobuf_example
PUBLIC
${PROTOBUF_LIBRARIES}
)
在编译target时,会启动protobuf compiler。
在生成的FindProtobuf.cmake中存着各种可用的protobuf变量,如:
PROTOBUF_INCLUDE_DIRS: protobuf 头文件
PROTOBUF_LIBRARIES: protobuf library