CMake⼯程指南-3
1.静态库(编译-链接-引⽤)
上⼀节,我们⽤⼀个简单的hello_world程序演⽰了如何使⽤cmake来构建⼀个⼆进制程序。这⼀
节,我们继续和⼤家⼀起学习,如何使⽤cmake⽣成和使⽤⼀个项⽬内部的静态库。
在最佳⼯程实践⾥,⼯程规模⼤⼀点的⼯程中,我们往往会把⼀些⽐较独⽴的功能(⽐如如⽹
络、数据库、算法,或者⼀些基础组件,redis-client, mysql-client,jsoncpp, libcurl)封装为独⽴
的库,由不同的团队来维护,在公司或者开源社区共享,达到复⽤⽬的。
本节我们把加法和减法函数2个函数 封装成⼀个MyMath的数学静态库,并在main⼆进制⾥引⽤我
们静态库⾥的加法和减法函数,来演⽰下如何使⽤CMake来管理这⼀场景。
2.单步实操
我们创建⼀个新的⼯程 my_math 来演⽰如何⽣成静态库。
首先我们预览一下工程的结构图(写完以后的),接下来我们一部一部去编写!

Step 1:新建⽂件-CMakeLists.txt
# 1 设置最低版本号
cmake_minimum_required(VERSION 3.18)
# 2 设置项⽬名称
project(TestMyMath
LANGUAGES CXX
)
# 3 添加⽬录层级
add_subdirectory(my_lib)
add_subdirectory(app)
Step 2:新建⽂件-my_lib/CMakeLists.txt
# 1 收集库的源代码
file(GLOB SRC_LISTS "src/*.cpp")
# 2 添加构建⽬标
add_library(MyMath STATIC ${SRC_LISTS})
# 3 设置库的使⽤要求
target_include_directories(MyMath
PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include
)
# 4 修改默认的输出路径
set_target_properties(MyMath PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
)
Step 3:新建⽂件-app/CMakeLists.txt
# 1 搜集⽂件列表
file(GLOB SRC_LISTS "*.cpp")
# 2 添加构建⽬标
add_executable(main ${SRC_LISTS})
# 3 添加依赖库列表
target_link_libraries(main PRIVATE MyMath)
# 4 设置输出路径
set_target_properties(main PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
)
# 5 打印库⽂件相对main的相对路径
add_custom_command(
TARGET main POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo
"$<PATH:RELATIVE_PATH,$<TARGET_FILE:MyMath>,${CMAKE_CURRENT_BINARY_DIR}>"
COMMENT "获取静态库的输出路径"
)
Step 4:新建⽂件-add.cpp
#include "math.h"
int add(int a, int b) {
return a + b;
}
Step 5:新建⽂件-sub.cpp
#include "math.h"
int sub(int a, int b) {
return a - b;
}
Step 6:新建⽂件-math.h
int add(int a, int b);
int sub(int a, int b);
Step 7:新建⽂件-main.cpp
#include <iostream>
#include "math.h"
int main()
{
std::cout << "3 + 4 = " << add(3, 4) << std::endl;
std::cout << "3 - 4 = " << sub(3, 4) << std::endl;
}
Step 8:运⾏cmake
mkdir build && cd build
cmake ../
Step 9:编译链接
cmake --build .
Step 10:运⾏
./app/main
3.CMake的 3⼤核⼼-⽬标-属性-API
3.1 ⽬标-Target
目标的种类
3.2 属性-Property
属性的种类
属性的作⽤域与传播范围(main ---->curl )
3.3 操作⽬标和属性的核⼼API
3.3.1 add_library
函数作⽤:
添加⼀个静态库或者动态库⽬标,让cmake 从指定的⽂件列表⽣成。
基本形式
add_library(<name> [STATIC | SHARED | MODULE] [EXCLUDE_FROM_ALL] [<source>...])
默认情况下,将在与调⽤命令的源树⽬录相对应的构建树⽬录中创建库⽂件。 可以使⽤
ARCHIVE_OUTPUT_DIRECTORY 、 LIBRARY_OUTPUT_DIRECTORY 和
RUNTIME_OUTPUT_DIRECTORY ⽬标属性修改默认的输出路径。
参数解释:

3.3.2 target_include_directories
函数作⽤:
设置⽬标在开发和发布阶段的头⽂件搜索⽬录,可以传递性传播给下游的使⽤⽅。
基本形式
target_include_directories(<target>
[SYSTEM] # path 告诉编译器“这些是系统头⽂件”,GCC/Clang 会⽤ -isystem
⽽⾮ -I,从⽽ 抑制第三⽅头引出的警告。
[BEFORE] # 把路径插到已有列表最前⾯
<INTERFACE|PUBLIC|PRIVATE> path1 [path2 ...]
[<INTERFACE|PUBLIC|PRIVATE> pathN ...] …
)
参数解释:

3..3.3 target_link_libraries
函数作⽤:
设置⼆进制⽬标的依赖库列表,相当于使⽤通⽤的set属性设置函数设置了LINK_LIBRARIES或者
INTERFACE_LINK_LIBRARIES这个属性,在cmake源代码⾥这2个属性是2个 vector<string> 成员。最终以-l的形式出现在gcc参数⾥。
target_link_libraries(<target>
<PRIVATE|PUBLIC|INTERFACE> <item>...
[<PRIVATE|PUBLIC|INTERFACE> <item>...]...)
set_target_properties(<target> PROPERTIES
LINK_LIBRARIES|INTERFACE_LINK_LIBRARIES <item>...
)
PRIVATE 关键字:相当于使⽤set_target_properties 设置了LINK_LIBRARIES属性,设置的库列表 只 会写进⽬标的LINK_LIBRARIES列表⾥。
INTERFACE 关键字:相当于使⽤set_target_properties 设置了INTERFACE_LINK_LIBRARIES,只会 写进⽬标的INTERFACE_LINK_LIBARIERS列表⾥。
PUBLIC 关键字设置的列表会同时写进LINK_LIBRARIES和INTERFACE_LINK_LIBRARIES⾥。
INTERFACE_LINK_LIBRARIES 列表出现的库会被传播给这个⽬标的使⽤⽅。
通过 target_link_libraries最终是通过gcc 的-l 选项传递给链接器的。

3.3.4 set_target_properties和 get_target_properties
函数作⽤:
设置/查询 ⽬标(如可执⾏⽂件、库)的各种属性,控制编译、链接、安装等⾏为
基本形式
set_target_properties(<target1> <target2> ...
PROPERTIES <prop1> <value1>
<prop2> <value2> ...)
get_target_property(<variable> <target> <property>)
3.3.5 add_subdirectory
函数作⽤:
添加⼦⽬录到构建树,cmake会⾃动进⼊到源码树⼦⽬录,执⾏位于⼦⽬录⾥的CMakeLists.txt⽂
件。
基本形式
add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL] [SYSTEM])
关键⾏为
1. 处理顺序
CMake 会⽴即处理 source_dir 中的 CMakeLists.txt,当前⽂件的处理会暂停,直到⼦⽬录
处理完毕,在继续处理当前⽂件add_subdirectory之后的命令。
2. 路径解析
source_dir 相对路径:相对于当前 CMakeLists.txt ⽂件所在⽬录。
binary_dir 相对路径:相对于当前构建⽬录(不指定,则使⽤ source_dir )。
3. 变量作⽤域
⼦⽬录中定义的变量默认是局部的,不会影响⽗⽬录。
可通过 set(xxx PARENT_SCOPE) 将变量传递到⽗⽬录。
缓存变量是全局的,⼦⽬录⾥设置的缓存变量,⽗⽬录也可以获取到
4. CMake 在当前上下⽂执⾏完add_subdirectory命令,进⼊到⼦⽬录之后,在开始执⾏
CMakeLists.txt时会修改的内置变量:
3.3.6 file
函数作⽤:
查看⽬录下的所有⽂件,如果匹配规则,则添加⽂件名字到⽂件列表中,是否需要递归,需要显
⽰指定。
基本形式
file(GLOB|GLOB_RECURSE <variable> [LIST_DIRECTORIES true|false]
[RELATIVE <path>] [CONFIGURE_DEPENDS] <globbing-expressions>...
)
至此,本节内容到此结束,感谢观看!