CMake 细节学习----助力构建大型C++项目

1,122 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第19天,点击查看活动详情。你可以简单浏览一下目录,有需要的阅读,写文章不易,阅读之前请给我点个赞吧~

一、why CMake?

对于跨平台项目,如果不使用 CMake ,在不同平台将需要使用不同的build工具,不同的构建命令,最后生成二进制可执行文件

WindowsMacLinux
构建工具Visual StudioXcodeMakefile
构建命令msbuildxcodebuildmake
最终生成二进制可执行文件

一旦需要更改源文件,我们要同时修改不同平台下的构建文件,很繁琐。

使用CMake的话,他们可以使用同一份 CMakeList.txt 根据环境生成不同的构建工具,然后我们再使用对应平台下的构建命令,就可以完成构建,生成同一份二进制文件。

此时,一旦需要更改源文件,我们只需要修改 CMakeList.txt ,后续过程不变,简化的不同平台的构建过程。

二、CMake 语法特性

前面我们通过直接灌输,模仿学习了很多CMake的实例,对于一些细节我们把握的还不是十分准确,这里我们来一起看一下细节。

1. 基本语法格式:指令(参数1 参数2 ...)

参数需要使用括号 参数之间使用空格或者分号分开

2. 指令是大小写无关的

3. 参数和变量是大小相关的

4. 变量使用${}方式取值

注意:但是在IF控制语句中直接使用变量名字

三、重要指令

1. cmake_minimum_required

指定CMake的最小版本要求

# 设置cmake最小版本号
cmake_minimum_required (VERSION 2.8)

2. project

指定工程名称

# 设置项目名称
project (learncmake)

3. set

显示的定义变量

# 设置 SRC 为 hello.cpp world.cpp 这两个文件
set(SRC hello.cpp world.cpp)

我们需要深入理解 cmake targets,你将遇到两种 targets

(1)executables
(2)libraries 下面通过4、5来深入理解一下他们

4. add_library

生成库文件

add_library(<name> [STATIC | SHARED | MODULE]
            [EXCLUDE_FROM_ALL]
            [<source>...])

有许多种 library 都可以使用这个命令,我们给定一个<name>,运行它将生成一个由源码<source>生成的叫做 <name> library target 。

实际生成的文件名,根据原生平台生成例如lib<name>.a 或者 <name>.lib

具体的你还可以指定这些库的类型,默认是 STATIC 的;MODULE 在 Windows 上是更常见的,它可以生成 .dll 和 .lib 跨平台编译的时候不要使用

STATIC(静态库) | SHARED(动态库) | MODULE

例子

# 将 SRC 也就是上面的hello.cpp world.cpp生成共享库
add_library(hello SHARED ${SRC})

5. add_executable

生成可执行文件

add_executable(<name> [WIN32] [MACOSX_BUNDLE]
               [EXCLUDE_FROM_ALL]
               [source1] [source2 ...])

运行它的时候,由一些c++程序 [source1] 生成一个可执行程序( an executable target called <name> )。

根据不同的平台可能生成 <name>.exe 或者 <name>

例子

# 编译main.cpp生成可执行文件main
add_executable(main main.cpp)

6.target_link_libraries

为 target 添加需要链接的共享库

# 将 hello 动态库文件链接到可执行文件 main
target_link_libraries(main hello)

target_link_libraries的对象必须是可执行文件或者库

7. add_subdirectory

向当前工程添加存放源文件的子目录

# 添加src子目录,src中需要有一个CMakeLists.txt
add_subdirectory(src)

添加子目录,子目录需要有一个CMakeLists.txt

8.aux_source_directory

发现一个目录下所有的源代码文件,并将列表存储在一个变量中,这个指令临时被用来自动构建源文件列表。

语法:aux_source_directory(dir VARIABLE)

# 定义SRC变量,其值为当前目录下所有的源代码文件
aux_source_directory(. SRC)
# 编译SRC变量所代表的源代码文件,生成main可执行文件
add_executable(main ${SRC})

9. add_compile_options

添加编译参数

add_compile_options(-Wall -std=c++11 -o2)

10. include_directories

向工程添加多个特定的头文件搜索路径

include_directories(./include)

11. link_directories

向工程添加多个特定的库文件搜索路径

link_directories(./lib)

尽量忘记下面这几个

所以这几个我放到了最后,功力不行的时候,他们容易制造混乱,大神说的,具体的大家也都再品品吧。

add_compile_options
include_directories
link_directories
link_libraries

三、CMake 常用变量

1. CMAKE_C_FLAGS

gcc编译选戏那个

2. CMAKE_CXX_FLAGS

g++编译选项

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -O3")

3. CMAKE_BUILD_TYPE

编译类型Debug Release

# 发布时需要选择 Debug
set(CMAKE_BUILD_TYPE Debug)
# 发布时需要选择 Release
set(CMAKE_BUILD_TYPE Release)

4. CMAKE_BINARY_DIR

5. PROJECT_BINARY_DIR

6. PROJECTNAME_BINARY_DIR

构建路径

所在位置4、5、6 这三个变量指代的内容是一致的
如果在源文件目录构建指的就是工程顶级目录
如果是在源文件外构建,也就是我们通常构建的build目录(out-of-source编译)指的是工程编译发生的目录,这里也就是build目录

7. PROJECT_SOURCE_DIR

源码文件路径

8. EXECUTABLE_OUTPUT_PATH

可执行文件输出的存放路径

9. LBRARY_OUTPUT_PATH

库文件输出的存放路径

也可以自定义设置静态库文件的输出路径

set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)