这篇文章是站在VS角度描述CMake语法的。具体语法对应关系,参照下表。

CMake函数对应VS相关设置

VS相关设置

CMake函数

指定包含头文件目录

target_include_directories

指定链接库目录

target_link_directories

指定链接库

target_link_libraries

指定C++标准

set(CMAKE_CXX_STANDARD 11)

指定编译器版本

cmake -G “Visual Studio 12 2013”

指定平台集

cmake -G “Visual Studio 12 2013 Win64”

指定编译类型

set(CMAKE_BUILD_TYPE “Debug”)等价于g++ -g

指定预编译宏

add_definitions(-Dxxx -Dyyy ) 必须-D开头

指定解决方案名称

project(xxxx)

文件分类

source_group(“folder_name” file_list)

CMake常见​​内置变量​​

CMake内置变量

说明(路径都是全路径)

PROJECT_NAME

CMakeList.txt里设置的project_name

PROJECT_SOURCE_DIR

根CMakeLists.txt所在的路径

PROJECT_BINARY_DIR

工程的构建目录(build目录)

CMAKE_CURRENT_SOURCE_DIR

当前’CMakeLists.txt’ 所在的路径

CMAKE_CURRENT_BINARY_DIR

当前正在处理的’构建目录’

CMAKE_CURRENT_LIST_DIR

当前处理的’cmake文件’所在的目录

CMAKE_CURRENT_LIST_FILE

当前处理的’CMakeLists.txt或cmake’文件的全路径

CMAKE_CURRENT_LIST_LINE

当前处理的’CMakeLists.txt或cmake’文件的’行号’

CMAKE_PROJECT_NAME

整个项目’配置的project_name

CMAKE_LIBRARY_OUTPUT_DIRECTORY

库的存放目录(需要用户设置)

CMAKE_RUNTIME_OUTPUT_DIRECTORY

可执行文件的存放目录(需要用户设置,必须在设置可执行文件之前设置)

CMake Hellow word

project
project/main.cpp
project/CMakeLists.txt

project/build

​project/CMakeLists.txt​

#设置CMake版本要求
cmake_minimum_required(VERSION 3.10)

#设置工程名称
project(hellow)

#设置C++11标准
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED true)

#添加可执行文件
add_executable(hellow main.cpp)

执行CMake指令

#当前目录build

#-G指定编译器Vs2013以及平台工具集类型X64
cmake -G "Visual Studio 12 2013 Win64" ../

一文读懂CMake_头文件

指定Debug模式(-g)

set(CMAKE_BUILD_TYPE "Debug")

生成mymath库​​add_library​

project/mymath
project/mymath/mymath.h
project/mymath/mymath.cpp
project/mymath/CMakeLists.txt

​project/CMakeLists.txt​

#增加一个子目录到编译工程中,子目录应该包含CMakeLists.txt
add_subdirectory(mymath)

#增加头文件包含目录
target_include_directories(hellow PUBLIC
"${PROJECT_SOURCE_DIR}/mymath"
)

#链接lib
target_link_libraries(hellow PUBLIC mymath)

​project/mymath/CMakeLists.txt​

#添加lib默认是静态库,如果指定SHARED则为动态库
add_library(mymath SHARED mymath.cpp)

此时就会生成mymath库了,下面是完整的​​project/CMakeLists.txt​

#设置CMake版本要求
cmake_minimum_required(VERSION 3.10)

#设置工程名称
project(hellow)

#设置C++11标准
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED true)

#增加一个子目录到编译工程中,子目录应该包含CMakeLists.txt
add_subdirectory(mymath)

#添加可执行文件
add_executable(hellow main.cpp)

#增加头文件包含目录
target_include_directories(hellow PUBLIC
"${PROJECT_SOURCE_DIR}/mymath"
)
#链接lib
target_link_libraries(hellow PUBLIC mymath)

一文读懂CMake_子目录_02

链接第三方库

下面以链接 d://test//test.lib为例,test.lib的头文件在d://test//include//

#附加test.lib
target_link_libraries(hellow PUBLIC mymath test)
#指定lib库位置
target_link_directories(hellow PUBLIC "d:/test")
#指定lib头文件位置
target_include_directories(hellow PUBLIC
"d:/test/include"
"${PROJECT_SOURCE_DIR}/mymath"
)

下面是完整的​​project/CMakeLists.txt​

#设置CMake版本要求
cmake_minimum_required(VERSION 3.10)

#设置工程名称
project(hellow)

#设置C++11标准
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED true)

#增加一个子目录到编译工程中,子目录应该包含CMakeLists.txt
add_subdirectory(mymath)

#添加可执行文件
add_executable(hellow main.cpp)

#增加头文件包含目录
target_include_directories(hellow PUBLIC
"d:/test/include"
"${PROJECT_SOURCE_DIR}/mymath"
)
#链接lib
target_link_libraries(hellow PUBLIC mymath test)


#指定链接库的目录
target_link_directories(hellow PUBLIC "d:/test")

一文读懂CMake_CMake_03

增加预定义宏​​add_definitions​

例如:必须定义​​USE_OPEN_SSL​​才能开启openssl

#增加预定义宏,必须-D开头
add_definitions(-DUSE_OPEN_SLL)

多文包含件处理

如果目标里面包含多个文件,如果手动指定则会很麻烦。可以通过​​aux_source_directory​​扫描并获取当前目录文件。

#增加sub函数
project/sub.cpp
project/sub.h
#扫描当前目录文件,并且保存在变量all_file中
#或者使用file(GLOB all_file ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
aux_source_directory("${CMAKE_CURRENT_SOURCE_DIR}" all_file)
add_executable(hellow ${all_file})

配置项目版本号和信息

#设置项目名称和版本
project(Tutorial VERSION 1.0)

#配置头文件传递版本号给源代码
#配置宏定义,配置默认值为ON,如果想关闭 cmake -DUSE_MYMATH=OFF
#option 除了ON之外其他的都默认为OFF
option(USE_MYMATH "user mymath.lib" ON)

#传递字符串给配置文件
set(var_Key "hellow word")
#传递INT给配置文件
set(INT_Key 1)

#输入文件 输出文件
configure_file(hellow_ver.h.in hellow_ver.h)

#由于配置好的文件hellow_ver.h将被写入二进制目录
#所以我们必须将该目录添加到 include 文件的搜索路径中
target_include_directories(hellow PUBLIC
"d:/test/include"
"${PROJECT_SOURCE_DIR}/mymath"
"${PROJECT_BINARY_DIR}"
)

​hellow_ver.h.in​

//配置的项目版本号
#define hellow_VERSION_MAJOR @hellow_VERSION_MAJOR@
#define hellow_VERSION_MINOR @hellow_VERSION_MINOR@

//宏定义
#cmakedefine USE_MYMATH
//注意:${}之间的名称要与cmakedefine后的变量名一样
//变量名称和cmakeLists.txt设置的变量名称相同
#cmakedefine var_Key "@var_Key@”
#cmakedefine INT_Key @INT_Key@

运行之后生成的​​hellow_ver.h​

一文读懂CMake_子目录_04


如果想取消​​USE_MYMATH​​ 可以使用 ​​-DUSE_MYMATH=OFF​

cmake -G "Visual Studio 12 2013 Win64" ../ -DUSE_MYMATH=OFF

生成动态库or静态库

#确定mymath.lib是否使用静态库
option(MYMATH_STATIC "user mymath static lib" ON)

if(MYMATH_STATIC)
add_library(mymath STATIC mymath.cpp)
else()
add_library(mymath SHARED mymath.cpp)
endif()
cmake -G "Visual Studio 12 2013 Win64" ../ -DUSE_MYMATH=OFF

指定二进制文件或者库文件生成位置

#一定要在设置target之前设置,否则无效
#二进制文件位置
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
#库文件位置
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)

设置Target的生成目标名称

#修改输出文件的名称,默认和target同名
set_target_properties(hellow PROPERTIES OUTPUT_NAME main)

执行生成事件

​​add_custom_command​​

参数

含义

PRE_BUILD

在目标中执行任何其他规则之前运行

PRE_LINK

在编译源代码之后,链接二进制文件或库文件之前运行

POST_BUILD

在目标内所有其他规则均已执行后运行

#在VS中我们经常会执行生成后事件,例如生成后复制文件
add_custom_command(TARGET hellow POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${PROJECT_BINARY_DIR}/bin/mymath.dll ${PROJECT_SOURCE_DIR}/bin/mymath.dll)

指定项目依赖项(指定项目生成顺序)

#例如当前项目hellow依赖mymath.lib
add_dependencies(hellow mymath)

文件分类​​source_group​

通过上述生成的工程文件没有分类,并且没有包含头文件。下面我们将按照目录结构进行分类(不使用lib)。

一文读懂CMake_CMake_05


注意涉及函数​​file​​和​​source_group​

#获取当前目录下所有的头文件并进行分类
#GLOB-只索引当前目录,不包括子目录
#GLOB_RECURSE-索引当前目录以及包括子目录
file(GLOB project_header_files ${CMAKE_CURRENT_SOURCE_DIR}/*.h)

#进行头文件,只能是相同类型的文件,否则会失败
source_group("Header Files" ${project_header_files})

#获取mymath目录下的头文件和源文件并且进行分类
#获取mymath目录下所有的文件这里并没有使用aux_source_directory("${CMAKE_CURRENT_SOURCE_DIR}/mymath" maths_file)
file(GLOB math_header_files ${CMAKE_CURRENT_SOURCE_DIR}/mymath/*.h)
file(GLOB math_src_files ${CMAKE_CURRENT_SOURCE_DIR}/mymath/*.cpp)

#source_group有两种写法
#自己定义folder,名称
#source_group("mymath" FILES ${math_header_files} ${math_src_files})
#根据目录结构截取生成目录名称 files的绝对路径去掉${CMAKE_CURRENT_SOURCE_DIR},即拼成目录名称
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${math_src_files} ${math_header_files})

#最后一步也是最重要的一步,一定要添加到target里面,否则也不会展示
add_executable(hellow ${all_file} ${project_header_files} ${math_header_files} ${math_src_files})
cmake -G "Visual Studio 12 2013 Win64" ../ -DUSE_MYMATH=OFF

此时可以看到文件已经分类,层级分明了。

一文读懂CMake_头文件_06

编译工程项目(​​--build​​)

当cmake指令运行之后,如果想编译文件,在windows下我们可以使用对应的VS打开编译,在linux下我们可以使用make编译。但是我们可以统一使用CMake自己来编译​​cmake --build 目录(cmake输出位置)​

#如果在windows平台
#release版本
cmake --build . --config Release
#debug版本
cmake --build . --config Debug

#如果在linux平台
#release版本
cmake ../ -DCMAKE_BUILD_TYPE=Release
cmake --build .
#Debug版本
cmake ../ -DCMAKE_BUILD_TYPE=Debug
cmake --build .

本文参考:​​CMake 教程​​,至于​​CMake的安装和测试​​将在下一章讲解。

函数简单说明

对于CMake,可能存在两种函数:xxxxx和target_xxxx。下面以​​link_libraries​​​和​​target_link_libraries​​​来做讲解。
​​​link_libraries​​​:针对全局的,即:CMake的所有模块都会添加该库。
​​​target_link_libraries​​​:针对指定目标的,只有指定目标包含该库。
例如CMake包含连个目标​​​A​​​和​​B​​​,此时如果通过​​link_libraries(ws2_32 test)​​​包含​​ws2_32.lib​​​和​​test.lib​​​那么​​A​​​和​​B​​​都将包含这两个库。但是如果通过​​target_link_libraries(A PUBLIC ws2_32 test)​​那么此时仅仅目标A包含这两个库。