Cmake常见用法。
概述
完整的Cmake工程一般如下图。
基础命令:
- cmake_minimum_required:cmake最小版本号
- project:工程名、版本
- 单行注释:#
- 多行注释:#[[]]
- 打印:message
- 定义变量:set、option
- 指定子构建目录:add_subdirectory,子目录必须包含CMakeLists.txt
- 变量引用:${VARIABLE_NAME}
- 条件分支:if()-else if()-else()-endif()
- 其他:PROJECT_NAME、PROJECT_SOURCE_DIR、循环分支…
总结:
- 变量使用${}方式取值,但是在IF控制语句中是直接使用变量名
- 指令(参数1 参数2…),其中指令不区分大小写
基础操作
一共八个步骤:
- 设置编译选项:
set(CMAKE_CXX_FLAGS "-std=c++11 $CMAKE_CXX_FLAGS")
- 指定构建配置:
option
&configure_file
,定义符号区分代码逻辑 - 指定头文件:
include_directories(./)
- 生成静态库: 先导入源文件
aux_source_directory
,然后add_libraries
- 生成动态库: 同上
- 指定外部lib库:
link_directories()
,target_link_libraries(${PROJECT_NAME} #文件)
- 生成可执行目标文件:
add_executable(${PROJECT_NAME} main.cpp)
- 指定文件存放目录:
set(# 设置变量)
或者install指令项目实战
main.cpp
#include <iostream>
#include "out_include_pow.h"
#include "self_static_add.h"
#include "self_static_sub.h"
#include "self_dynamic_div.h"
#include "self_dynamic_mul.h"
int main(int, char**) {
std::cout << "out: pow(5,2) is " << out_pow(5, 2) << std::endl;
std::cout << "self_static: add(5, 2) is " << self_static_add(5, 2) << std::endl;
std::cout << "self_static: sub(5, 2) is " << self_static_sub(5, 2) << std::endl;
std::cout << "self_dynamic: div(5, 2) is " << self_dynamic_div(5, 2) << std::endl;
std::cout << "self_dynamic: mul(5, 2) is " << self_dynamic_mul(5, 2) << std::endl;
return 0;
}
主项目CMakeLists:
cmake_minimum_required(VERSION 3.0.0)
project(CMAKE_NEW_TEST VERSION 0.1.0)
set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}") #编译选项
include_directories(./out_include
./self_static/self_static_add/include
./self_static/self_static_sub/include
./self_dynamic/self_dynamic_div/include
./self_dynamic/self_dynamic_mul/include)
#add_subdirectory(out_src)
##[[
add_subdirectory(self_static)
add_subdirectory(self_dynamic)
link_directories(./out_static ./out_dynamic)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) #在build中执行,相对路径就是相对build。复杂过程使用install
add_executable(${PROJECT_NAME} main.cpp)
option(USE_MY_STATIC_OUT "option" ON) # 如果变量定义过,则不处理;如果未定义过,则设置默认值
option(TEST_CMAKE_DEFINE_OFF_EFFECT "comment" OFF)
set(TEST_VARIABLE_VALUE 0)
configure_file (
"${PROJECT_SOURCE_DIR}/config/config.h.in"
"${PROJECT_SOURCE_DIR}/config/config_my89757.h"
)
message("!!!!!!!!!!!!:" ${USE_MY_STATIC_OUT} "-----------"${CMAKE_INSTALL_PREFIX})
if(${USE_MY_STATIC_OUT} STREQUAL "ON")
target_link_libraries(${PROJECT_NAME} out_static
self_static_lib
self_dynamic_dll)
else()
target_link_libraries(${PROJECT_NAME} out_dynamic self_static_lib self_dynamic_dll)
endif()
#]]
config.in
#ifndef CONFIG_H
#define CONFIG_H
#cmakedefine USE_MY_STATIC_OUT
#cmakedefine TEST_CMAKE_DEFINE_OFF_EFFECT
#define TEST_VARIABLE_NAME ${TEST_VARIABLE_VALUE}
#endif
动态库CMakeLists:
include_directories(${PROJECT_SOURCE_DIR}/out_include)
aux_source_directory(. SRC_FILES)
MESSAGE("-----------------------------------")
SET(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/out_dynamic)
add_library(out_dynamic SHARED ${SRC_FILES})
设置全局属性:
aux_source_directory(${PROJECT_SOURCE_DIR}/self_dynamic/self_dynamic_div/src
all_src_files)
set_property(GLOBAL PROPERTY SELF_DYNAMIC_DIV_INNER ${all_src_files})
add_subdirectory(self_dynamic_div)
add_subdirectory(self_dynamic_mul/src)
get_property(SELF_DYNAMIC_DIV GLOBAL PROPERTY "SELF_DYNAMIC_DIV_INNER")
get_property(SELF_DYNAMIC_MUL GLOBAL PROPERTY "SELF_DYNAMIC_MUL_INNER")
include_directories(${PROJECT_SOURCE_DIR}/self_dynamic/comm)
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
add_library(self_dynamic_dll SHARED ${SELF_DYNAMIC_DIV} ${SELF_DYNAMIC_MUL})
1、指定 cmake 的最小版本
cmake_minimum_required(VERSION 3.4.1)
2、设置项目名称,它会引入两个变量 demo_BINARY_DIR 和 demo_SOURCE_DIR,同时,cmake 自动定义了两个等价
的变量 PROJECT_BINARY_DIR 和 PROJECT_SOURCE_DIR。
project(demo)
3、设置编译类型,add_library 默认生成是静态库
add_executable(demo demo.cpp) # 生成可执行文件
add_library(common STATIC util.cpp) # 生成静态库
add_library(common SHARED util.cpp) # 生成动态库或共享库
以上命令将生成:
在 Linux 下是:
demo
libcommon.a
libcommon.so
在 Windows 下是:
demo.exe
common.lib
common.dll
4、明确指定包含哪些源文件
add_library(demo demo.cpp test.cpp util.cpp)
5、设置变量
5.1 set 直接设置变量的值
set(SRC_LIST main.cpp test.cpp)
add_executable(demo ${SRC_LIST})
set(ROOT_DIR ${CMAKE_SOURCE_DIR}) #CMAKE_SOURCE_DIR默认为当前cmakelist.txt目录
5.2 set追加设置变量的值
set(SRC_LIST main.cpp)
set(SRC_LIST ${SRC_LIST} test.cpp)
add_executable(demo ${SRC_LIST})
5.3 list追加或者删除变量的值
set(SRC_LIST main.cpp)
list(APPEND SRC_LIST test.cpp)
list(REMOVE_ITEM SRC_LIST main.cpp)
add_executable(demo ${SRC_LIST})
6、搜索文件
6.1 搜索当前目录下的所有.cpp文件,并命名为SRC_LIST,它会查找目录下的.c,.cpp ,.mm,.cc 等等C/C++语言后缀的文件名
aux_source_directory(. SRC_LIST)
add_library(demo ${SRC_LIST})
6.2 自定义搜索规则
aux_source_directory(. SRC_LIST)
aux_source_directory(protocol SRC_PROTOCOL_LIST)
add_library(demo ${SRC_LIST} ${SRC_PROTOCOL_LIST})
或者
file(GLOB SRC_LIST "*.cpp" "protocol/*.cpp")
add_library(demo ${SRC_LIST})
# 或者
file(GLOB SRC_LIST "*.cpp")
file(GLOB SRC_PROTOCOL_LIST "protocol/*.cpp")
add_library(demo ${SRC_LIST} ${SRC_PROTOCOL_LIST})
# 或者
file(GLOB_RECURSE SRC_LIST "*.cpp") #递归搜索
FILE(GLOB SRC_PROTOCOL RELATIVE "protocol" "*.cpp") # 相对protocol目录下搜索
add_library(demo ${SRC_LIST} ${SRC_PROTOCOL_LIST})
7、设置包含的目录,头文件目录
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/include
)
Linux 下还可以通过如下方式设置包含的目录
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I${CMAKE_CURRENT_SOURCE_DIR}")
8、设置链接库搜索目录
link_directories(
${CMAKE_CURRENT_SOURCE_DIR}/libs
)
Linux 下还可以通过如下方式设置包含的目录
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_CURRENT_SOURCE_DIR}/libs")
9、设置 target 需要链接的库
9.1 指定链接动态库或静态库
target_link_libraries(demo libface.a) # 链接libface.a
target_link_libraries(demo libface.so) # 链接libface.so
9.2 指定全路径
target_link_libraries(demo ${CMAKE_CURRENT_SOURCE_DIR}/libs/libface.a)
target_link_libraries(demo ${CMAKE_CURRENT_SOURCE_DIR}/libs/libface.so)
9.3 指定链接多个库
target_link_libraries(demo
${CMAKE_CURRENT_SOURCE_DIR}/libs/libface.a
boost_system.a
boost_thread
pthread)
10、打印信息
message(${PROJECT_SOURCE_DIR})
message("build with debug mode")
message(WARNING "this is warnning message")
message(FATAL_ERROR "this build has many error") # FATAL_ERROR 会导致编译失败
11.包含其它 cmake 文件
include(./common.cmake) # 指定包含文件的全路径
include(def) # 在搜索路径中搜索def.cmake文件
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) # 设置include的搜索路径
12、条件控制
12.1 if…elseif…else…endif
逻辑判断和比较:
if (expression):expression 不为空(0,N,NO,OFF,FALSE,NOTFOUND)时为真
if (not exp):与上面相反
if (var1 AND var2)
if (var1 OR var2)
if (COMMAND cmd):如果 cmd 确实是命令并可调用为真
if (EXISTS dir) if (EXISTS file):如果目录或文件存在为真
if (file1 IS_NEWER_THAN file2):当 file1 比 file2 新,或 file1/file2 中有一个不存在时为真,文件名需使用全路径
if (IS_DIRECTORY dir):当 dir 是目录时为真
if (DEFINED var):如果变量被定义为真
if (var MATCHES regex):给定的变量或者字符串能够匹配正则表达式 regex 时为真,此处 var 可以用 var 名,也可以用 ${var}
if (string MATCHES regex)
数字比较:
if (variable LESS number):LESS 小于
if (string LESS number)
if (variable GREATER number):GREATER 大于
if (string GREATER number)
if (variable EQUAL number):EQUAL 等于
if (string EQUAL number)
字母表顺序比较:
if (variable STRLESS string)
if (string STRLESS string)
if (variable STRGREATER string)
if (string STRGREATER string)
if (variable STREQUAL string)
if (string STREQUAL string)
12.2 while…endwhile
12.3 foreach…endforeach
foreach(i RANGE 1 9 2)
message(${i})
endforeach(i)
# 输出:13579
13、常用变量
13.1 预定义变量
PROJECT_SOURCE_DIR:工程的根目录
PROJECT_BINARY_DIR:运行 cmake 命令的目录,通常是 ${PROJECT_SOURCE_DIR}/build
PROJECT_NAME:返回通过 project 命令定义的项目名称
CMAKE_CURRENT_SOURCE_DIR:当前处理的 CMakeLists.txt 所在的路径
CMAKE_CURRENT_BINARY_DIR:target 编译目录
CMAKE_CURRENT_LIST_DIR:CMakeLists.txt 的完整路径
CMAKE_CURRENT_LIST_LINE:当前所在的行
CMAKE_MODULE_PATH:定义自己的 cmake 模块所在的路径,SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake),然后可以用INCLUDE命令来调用自己的模块
EXECUTABLE_OUTPUT_PATH:重新定义目标二进制可执行文件的存放位置
LIBRARY_OUTPUT_PATH:重新定义目标链接库文件的存放位置
13.2 环境变量
$ENV{Name}
set(ENV{Name} value) # 这里没有“$”符号
13.3 系统信息
CMAKE_MAJOR_VERSION:cmake 主版本号,比如 3.4.1 中的 3
CMAKE_MINOR_VERSION:cmake 次版本号,比如 3.4.1 中的 4
CMAKE_PATCH_VERSION:cmake 补丁等级,比如 3.4.1 中的 1
CMAKE_SYSTEM:系统名称,比如 Linux-2.6.22
CMAKE_SYSTEM_NAME:不包含版本的系统名,比如 Linux
CMAKE_SYSTEM_VERSION:系统版本,比如 2.6.22
CMAKE_SYSTEM_PROCESSOR:处理器名称,比如 i686
UNIX:在所有的类 UNIX 平台下该值为 TRUE,包括 OS X 和 cygwin
WIN32:在所有的 win32 平台下该值为 TRUE,包括 cygwin
14、主要开关选项
BUILD_SHARED_LIBS:这个开关用来控制默认的库编译方式,如果不进行设置,使用 add_library 又没有指定库类型的情况下,默认编译生成的库都是静态库。如果 set(BUILD_SHARED_LIBS ON) 后,默认生成的为动态库
CMAKE_C_FLAGS:设置 C 编译选项,也可以通过指令 add_definitions() 添加
CMAKE_CXX_FLAGS:设置 C++ 编译选项,也可以通过指令 add_definitions() 添加
add_definitions(-DENABLE_DEBUG -DABC) # 参数之间用空格分隔