前面我们已经学习CMake在编译二进制程序上的应用了,但是在工程场景中不可避免要用到很多库,因此只会编译普通的二进制程序是没有意义的,必须要学会如何链接库。
本期先学习CMake如何用在静态库上。
相关代码代码上传至作者gitee:CMake 学习: CMake工具开发介绍仓库,虽然标记的是C++
目录
[创建目标的 API](#创建目标的 API)
[按功能分类的目标属性设置 API(专用命令)](#按功能分类的目标属性设置 API(专用命令))
[通用目标属性操作 API](#通用目标属性操作 API)
[通用属性操作 API(适用于任意作用域)](#通用属性操作 API(适用于任意作用域))
[查询与调试类 API](#查询与调试类 API)
[目标操作 API](#目标操作 API)
[属性操作 API(通用,适用于多种作用域)](#属性操作 API(通用,适用于多种作用域))
[export 与 install(EXPORT) 的区别](#export 与 install(EXPORT) 的区别)
前言
静态库的不经过链接过程,本质上只是一个目标归档文件。
打包为静态库并且使用的过程:
- 编译源文件,生成目标文件(
.o)
bash
g++ -c file1.cpp file2.cpp file3.cpp
-c 选项告诉编译器只编译不链接。
执行后你会得到 file1.o、file2.o、file3.o 三个目标文件。
- 使用
ar工具创建静态库
bash
ar rcs libmylib.a file1.o file2.o file3.o
libmylib.a 是你指定的静态库名称,必须以 lib 开头,以 .a 结尾。
r:插入或替换文件;c:创建库(若不存在);s:建立索引,加速链接。
- (可选)验证库内容
bash
ar t libmylib.a
列出库中包含的目标文件,确认无误。
- 使用静态库编译主程序
假设你有一个主程序文件 main.cpp,它调用了库中的函数。编译命令如下:
bash
g++ main.cpp -L. -lmylib -o myprogram
-L.:告诉链接器在当前目录(.)查找库文件。
-lmylib:指定要链接的库名为 mylib(编译器会自动补全为 libmylib.a)。
-o myprogram:指定输出的可执行文件名。
- 运行程序
bash
./myprogram
示例
我们以一个简单地数学加减函数,编辑为库,使用静态库来编辑
项目目录结构是这样的

我们来逐步拆解
顶层
顶层CMakeLists.txt
bash
#设置最低版本号
cmake_minimum_required(VERSION 3.18)
#项目名称
project(MathTest)
#目录层级添加
add_subdirectory(MyLib)#先执行MyLib目录的
add_subdirectory(app)#然后执行app目录的
因为app搜索不到头文件,因此我们还需要修改C/C++设置。在includePath中添加:${workspaceFolder}/MyMath/MyLib/include

或者也可以按CTRL +shift+P,选择"C/C++编辑配置",在下图的位置修改

MyLib
CMakeLists.txt
bash
#1、收集库源代码
file(GLOB SRC_LIST "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
#2、添加构建目标
add_library(MyMath STATIC ${SRC_LIST})
#3、库使用要求
target_include_directories(MyMath
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include
)
include
math.h
bash
int add(int a,int b);
int sub(int a, int b);
src
add.cpp
cpp
#include"math.h"
int add(int a ,int b)
{
return a+b;
}
sub.cpp
cpp
#include"math.h"
int sub(int a ,int b)
{
return a-b;
}
app
CMakeLists.txt
bash
#搜索文件列表
file(GLOB SRC_LIST "*.cpp")
#添加依赖目标
add_executable(main ${SRC_LIST})
#添加依赖库列表
target_link_libraries(main PRIVATE MyMath)
main.cpp
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;
return 0;
}
编译链接
随后创建build目录编译链接运行

这里运行的时候大家会发现可执行文件跑到了build目录下的app目录中
源代码目录顶层有一个顶层CMakeLists.txt,构建目录build对应有一个顶层的CMakeCache.txt与之对应。而它们的app、MyLib等也会一一对应
因此我们就会发现,目标定义在那里,二进制执行文件就会相对应地放在哪里。
我们同样也可以修改默认输出路径,只需要在CMakeLists.txt里添加即可。
bash
#app目录下的CMakeLists.txt
#搜索文件列表
file(GLOB SRC_LIST "*.cpp")
#添加依赖目标
add_executable(main ${SRC_LIST})
#添加依赖库列表
target_link_libraries(main PRIVATE MyMath)
# 指定可执行文件(main)输出到源码顶层目录
set_target_properties(main PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
)
bash
#MyLib目录下的CMakeLists.txt
#1、收集库源代码
file(GLOB SRC_LIST "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
#2、添加构建目标
add_library(MyMath STATIC ${SRC_LIST})
#3、库使用要求
target_include_directories(MyMath
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include
)
# 指定静态库(MyMath)输出到源码顶层目录
set_target_properties(MyMath PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
)
重新测试

我们会在build目录下发现可执行文件和库文件已经放到build下的bin和lib下

CMake的核心属性
前面我们学习过,CMake是基于目标的属性传递的现代化构建系统。拥有属于自己的核心属性:目标、属性和API,和CMake的属性传递机制一起,组成了CMake现代构建系统的和核心
目标(target)
核心目标类型详解
1. EXECUTABLE
创建命令 :add_executable(<name> [source1 source2 ...])
作用 :生成一个可执行文件。这是最基础的目标类型,用于构建应用程序或命令行工具。产物后缀根据平台自动确定(Windows 下为 .exe,Unix-like 下无后缀或自定义)。
典型产物 :main、curl、myapp.exe
2. STATIC
创建命令 :add_library(<name> STATIC [source1 source2 ...])
作用 :构建静态库。静态库是目标文件的归档文件,链接时会被完整复制到可执行文件中。产物后缀通常为 .a(Unix-like)或 .lib(Windows)。
典型产物 :libfoo.a、foo.lib
3. SHARED
创建命令 :add_library(<name> SHARED [source1 source2 ...])
作用 :构建动态链接库(共享库)。动态库在运行时被加载,多个程序可共享同一份代码。产物后缀因平台而异:.so(Linux)、.dylib(macOS)、.dll(Windows,同时可能生成导入库 .lib)。
典型产物 :libfoo.so、foo.dll(及 foo.lib 导入库)
4. MODULE
创建命令 :add_library(<name> MODULE [source1 source2 ...])
作用 :构建插件模块。与共享库类似,但不会被自动链接到其他目标,通常用于通过 dlopen 或 LoadLibrary 在运行时动态加载。产物后缀与共享库相同(如 .so、.dll)。
典型产物 :libplugin.so、plugin.dll
5. OBJECT
创建命令 :add_library(<name> OBJECT [source1 source2 ...])
作用 :编译源文件生成目标文件(.o/.obj),但不归档或链接。这些目标文件可以稍后被其他库或可执行文件引用,实现编译结果的重用。目标文件本身不生成独立的库文件,仅存在于 CMake 内部的对象库概念中。
产物说明 :没有直接的库文件,但可通过 $<TARGET_OBJECTS:objlib> 在其他目标中引用其编译后的目标文件。
6. INTERFACE
创建命令 :add_library(<name> INTERFACE)
作用 :不编译任何源文件,仅用于传递使用要求 (如头文件搜索路径、编译定义、链接选项)。常用于纯头文件库或仅提供接口的库。它可以链接其他目标,并将自身的 INTERFACE_* 属性传播给使用者。
产物说明:无任何构建产物,仅作为 CMake 中的逻辑目标存在。
7. IMPORTED
创建命令 :add_library(<name> <type> IMPORTED) (<type> 可为 STATIC、SHARED、MODULE、UNKNOWN)
作用 :引用磁盘上已存在的外部构建产物 (如预编译的第三方库),而不在项目中重新构建。通过设置其 IMPORTED_LOCATION 等属性,可以像普通目标一样使用该库,便于依赖管理。
产物说明:不生成新文件,仅提供对已有文件的 CMake 目标封装。
8. ALIAS
创建命令 :add_library(<alias> ALIAS <target>)
作用 :为同项目内的现有目标(通常是库目标)创建一个别名,方便在不同目录或命名空间中引用。别名目标不可修改属性,也不产生新的构建,仅用于简化引用。
产物说明:无独立产物,完全指向原始目标。
创建命令参数详解
1. EXECUTABLE
-
命令 :
add_executable(<name> [WIN32] [MACOSX_BUNDLE] [EXCLUDE_FROM_ALL] [source1 source2 ...]) -
参数含义:
-
<name>:必需,可执行文件的逻辑目标名称,也是构建产物的基本名称(平台自动添加后缀)。 -
WIN32:可选 ,在 Windows 上创建 GUI 应用程序(无控制台窗口),对应WinMain入口点。 -
MACOSX_BUNDLE:可选 ,在 macOS 上创建应用程序包(.app目录结构)。 -
EXCLUDE_FROM_ALL:可选 ,将该目标排除在默认的ALL构建目标之外,需要显式构建。 -
source1 source2 ...:可选,构建该可执行文件所需的源文件列表(支持生成器表达式)。
-
2. STATIC / SHARED / MODULE / OBJECT
命令 :add_library(<name> <type> [EXCLUDE_FROM_ALL] [source1 source2 ...])
-
参数含义:
-
<name>:必需,库的逻辑目标名称,产物名称默认基于此(可自定义)。 -
<type>:必需 ,库类型,取值为STATIC、SHARED、MODULE、OBJECT之一。 -
EXCLUDE_FROM_ALL:可选,同上,排除默认构建。 -
source1 source2 ...:可选 ,构成该库的源文件列表。对于OBJECT库,源文件被编译为目标文件但不归档。
-
3. INTERFACE
命令 :add_library(<name> INTERFACE [EXCLUDE_FROM_ALL])
-
参数含义:
-
<name>:必需,接口库的逻辑名称,用于传递使用要求。 -
INTERFACE:必需,指明这是一个接口库(无源文件)。 -
EXCLUDE_FROM_ALL:可选,同上。
-
4. IMPORTED
命令 :add_library(<name> <type> IMPORTED [GLOBAL])
-
参数含义:
-
<name>:必需,为外部库在 CMake 中创建的别名。 -
<type>:必需 ,外部库的实际类型,如STATIC、SHARED、MODULE或UNKNOWN(当类型不确定时)。 -
IMPORTED:必需,关键字,表示这是一个导入目标。 -
GLOBAL:可选,使目标在全局可见(默认仅在创建它的目录及子目录可见)。
-
5. ALIAS
命令 :add_library(<alias> ALIAS <target>)
-
参数含义:
-
<alias>:必需,为现有目标创建的别名。 -
ALIAS:必需,关键字。 -
<target>:必需 ,同一项目中已存在的目标名称(必须是库目标,且不能是ALIAS本身)。
-
总结
| 类型 | 创建命令 | 作用说明 |
|---|---|---|
| EXECUTABLE | add_executable(<name> [sources...]) |
生成可执行文件(应用程序/命令行工具) |
| STATIC | add_library(<name> STATIC [sources...]) |
构建静态库(.a / .lib),链接时被完整复制到可执行文件 |
| SHARED | add_library(<name> SHARED [sources...]) |
构建动态链接库(.so / .dylib / .dll),运行时加载 |
| MODULE | add_library(<name> MODULE [sources...]) |
构建插件模块(.so / .dll),用于 dlopen 等动态加载,不自动链接 |
| OBJECT | add_library(<name> OBJECT [sources...]) |
编译源文件为目标文件(.o / .obj),不归档,可被其他目标引用 |
| INTERFACE | add_library(<name> INTERFACE) |
纯头文件库或仅传递使用要求的目标,无编译产物 |
| IMPORTED | add_library(<name> <type> IMPORTED) |
引用磁盘上已有的预编译库,不参与构建,仅提供目标接口 |
| ALIAS | add_library(<alias> ALIAS <target>) |
为现有目标创建别名,方便引用,不产生新构建 |
属性(Properties)
| 属性类别 | 作用域 | 常用设置命令 | 常用获取命令 | 常用示例属性 |
|---|---|---|---|---|
| 全局属性 | 整个 CMake 运行环境 | set_property(GLOBAL PROPERTY <name> <value>) |
get_property(<VAR> GLOBAL PROPERTY <name>) |
CMAKE_CXX_KNOWN_FEATURES、IN_TRY_COMPILE |
| 目录属性 | 当前目录及子目录 | set_directory_properties(PROPERTIES <name> <value>) |
get_directory_property(<VAR> [DIRECTORY dir] <name>) |
INCLUDE_DIRECTORIES、COMPILE_DEFINITIONS |
| 目标属性 | 单个目标(可执行文件/库) | set_target_properties(<target> PROPERTIES <name> <value>) |
get_target_property(<VAR> <target> <name>) |
COMPILE_DEFINITIONS、LINK_LIBRARIES、OUTPUT_NAME |
| 源文件属性 | 单个源文件 | set_source_files_properties(<file> PROPERTIES <name> <value>) |
get_source_file_property(<VAR> <file> <name>) |
COMPILE_FLAGS、LANGUAGE、HEADER_FILE_ONLY |
| 测试属性 | 单个测试(由 add_test 定义) |
set_tests_properties(<test> PROPERTIES <name> <value>) |
get_test_property(<test> <VAR> <name>) |
TIMEOUT、WORKING_DIRECTORY、ENVIRONMENT |
| 缓存变量属性 | 单个缓存变量 | set_property(CACHE <varname> PROPERTY <name> <value>) |
get_property(<VAR> CACHE <varname> PROPERTY <name>) |
TYPE、ADVANCED、HELPSTRING |
| 安装文件属性 | 由 install 命令生成的文件 |
set_property(INSTALL <file> PROPERTY <name> <value>) |
get_property(<VAR> INSTALL <file> PROPERTY <name>) |
属性作用域与传播
| 属性类别 | 关键字 (若适用) | 构建影响 | 传播范围 | 对目标的影响 | 核心作用 |
|---|---|---|---|---|---|
| 目标私有属性 | PRIVATE |
仅影响当前目标 | 不传播 | 直接影响当前目标的编译或链接行为。例如 PRIVATE 链接的库仅用于当前目标。 |
封装目标内部实现,隐藏依赖。 |
| 目标接口属性 | INTERFACE |
不影响当前目标 | 传播给所有依赖者 | 自身不产生构建,但为使用者提供要求。例如 INTERFACE_INCLUDE_DIRECTORIES 告知使用者所需的头文件路径。 |
定义目标的使用接口,便于依赖管理。 |
| 目标公有属性 | PUBLIC |
影响当前目标 | 传播给所有依赖者 | 既是自身构建的一部分,也成为其公共API的一部分。例如 PUBLIC 的编译定义会影响库和其使用者。 |
共享公共构建要求,保持依赖链一致。 |
| 目录作用域属性 | 无 | 影响目录下所有目标 | 向下传播给子目录 | 为目录及其子目录内的所有目标设置默认值。例如在根目录设置 CMAKE_CXX_STANDARD。 |
实现项目范围的统一配置。 |
| 全局作用域属性 | 无 | 影响整个项目 | 全局可见 | 设置影响整个CMake运行环境的参数。例如查询编译器支持的C++特性。 | 存储全局状态和系统级信息。 |
| 继承属性 | INHERITED |
取决于原始设置 | 向上作用域链查找 | 当属性在当前作用域未设置时,允许其从父目录乃至全局继承值。 | 实现配置的层级覆盖与复用。 |
CMake常用API
创建目标的 API
add_executable
-
作用:定义一个可执行文件目标。
-
表达式:
bash
add_executable(<name> [WIN32] [MACOSX_BUNDLE]
[EXCLUDE_FROM_ALL] [source1] [source2...])
参数解析:
-
<name>:目标名称,在项目中全局唯一,后续通过该名称引用。 -
WIN32:可选,Windows 平台下构建为 GUI 应用(不打开控制台窗口)。 -
MACOSX_BUNDLE:可选,macOS 下构建为应用程序 Bundle。 -
EXCLUDE_FROM_ALL:可选,该目标不会加入默认的all构建规则,需显式构建。 -
[source...]:源文件列表,可以是 .c/.cpp 等,也支持生成器表达式。
- 效果 :创建一个名为
<name>的目标,并可选地指定源文件;该目标后续可通过target_...系列命令配置编译、链接等属性。
add_library
-
作用:定义一个库目标(静态、动态、对象库、接口库等)。
-
表达式:
bash
add_library(<name> [STATIC | SHARED | MODULE | OBJECT | INTERFACE]
[source1...])
参数解析:
-
<name>:目标名称。 -
STATIC:静态库(.a/.lib)。 -
SHARED:动态库(.so/.dll/.dylib)。 -
MODULE:插件模块,运行时动态加载,不链接到其他目标。 -
OBJECT:对象库,只编译源文件生成.o文件,不打包为库,可供其他目标链接。 -
INTERFACE:接口库,不编译源文件,仅用于传递依赖(如头文件库)。 -
EXCLUDE_FROM_ALL:同add_executable。 -
[source...]:源文件列表(接口库不能包含源文件,只能通过target_sources添加INTERFACE源文件)。
- 效果 :创建一个库目标,类型由参数决定;接口库(
INTERFACE)不产生实际构建输出,仅用于传递依赖。
add_custom_target
-
作用:定义一个自定义目标,不产生实际构建产物,常用于执行命令或作为依赖聚合点。
-
表达式:
bash
add_custom_target(<name> [ALL] [COMMAND ...] [DEPENDS ...])
参数解析:
-
<name>:目标名称。 -
ALL:将该目标加入默认all构建。 -
COMMAND:指定要执行的命令(可多个),支持生成器表达式。 -
DEPENDS:依赖的其他目标或文件。 -
BYPRODUCTS:声明该命令会生成的副产品(如生成的文件),用于依赖链。 -
WORKING_DIRECTORY:执行命令的工作目录。 -
COMMENT:构建时输出的提示信息。 -
VERBATIM:保证参数正确转义,推荐始终使用。 -
USES_TERMINAL:在构建时开启终端交互(如需要输入密码时)。 -
SOURCES:添加源文件,仅用于 IDE 展示。
- 效果:生成一个总是被视为"未构建"的目标,可用于触发自定义命令或管理构建顺序。
按功能分类的目标属性设置 API(专用命令)
这些命令分别设置目标的某类具体属性,底层实际修改的是目标的相应属性变量。
target_include_directories
-
作用:为目标添加头文件搜索路径。
-
表达式:
bash
target_include_directories(<target> [SYSTEM] [AFTER|BEFORE]
<INTERFACE|PUBLIC|PRIVATE> [items...])
参数解析:
-
<target>:目标名。 -
SYSTEM:可选,将路径视为系统目录(编译器会忽略该目录中的警告)。 -
AFTER|BEFORE:控制路径在包含列表中的顺序,默认AFTER。 -
<INTERFACE|PUBLIC|PRIVATE>:指定传播范围。-
PRIVATE:仅当前目标使用,依赖者不继承。 -
PUBLIC:当前目标和依赖者都使用。 -
INTERFACE:仅依赖者使用,当前目标不编译源文件时使用(如头文件库)。
-
-
[items...]:路径列表(绝对路径、相对路径、生成器表达式)。
效果 :设置目标的 INCLUDE_DIRECTORIES 属性,并影响依赖传递。
- 效果 :将路径添加到目标的
INCLUDE_DIRECTORIES属性中,并根据作用域(PUBLIC/INTERFACE)传播给依赖者。
target_compile_definitions
-
作用:为目标添加预处理器定义。
-
表达式:
bash
target_compile_definitions(<target> <INTERFACE|PUBLIC|PRIVATE> [items...])
参数解析:
-
<target>:目标名。 -
<INTERFACE|PUBLIC|PRIVATE>:传播范围。 -
[items...]:宏定义,格式MACRO或MACRO=VALUE(无需-D前缀,CMake 自动处理)。
- 效果 :将定义添加到目标的
COMPILE_DEFINITIONS属性,并根据作用域传播。
target_compile_options
-
作用:为目标添加编译选项。
-
表达式:
bash
target_compile_options(<target> [BEFORE]
<INTERFACE|PUBLIC|PRIVATE> [items...])
参数解析:
-
<target>:目标名。 -
BEFORE:可选,将选项添加到现有选项之前。 -
<INTERFACE|PUBLIC|PRIVATE>:传播范围。 -
[items...]:编译器标志,如-Wall、/W4,支持生成器表达式。
- 效果 :将选项添加到目标的
COMPILE_OPTIONS属性,并依作用域传播。
target_link_libraries
-
作用:指定目标要链接的库或目标。
-
表达式:
bash
target_link_libraries(<target> <INTERFACE|PUBLIC|PRIVATE> [items...])
参数解析:
-
<target>:目标名。 -
<INTERFACE|PUBLIC|PRIVATE>:传播范围。-
PRIVATE:仅当前目标链接,依赖者不继承。 -
PUBLIC:当前目标和依赖者都链接,且传递使用要求(如头文件路径、编译定义)。 -
INTERFACE:仅依赖者链接(用于接口库)。
-
-
[items...]:可以是另一个目标名、库文件路径、链接器标志、生成器表达式。
- 效果 :设置目标的
LINK_LIBRARIES属性,并处理传递性依赖(接口库、链接库路径等)。
target_link_options
-
作用:为目标添加链接器选项(CMake 3.13+)。
-
表达式:
bash
target_link_options(<target> [BEFORE] <INTERFACE|PUBLIC|PRIVATE> [items...])
参数解析:
-
参数含义与
target_compile_options类似,区别是作用于链接阶段。 -
[items...]:链接器标志,如-L/path、-Wl,--rpath,支持生成器表达式。
- 效果 :将选项添加到目标的
LINK_OPTIONS属性,并依作用域传播。
target_sources
-
作用:为目标追加源文件。
-
表达式:
bash
target_sources(<target> <INTERFACE|PUBLIC|PRIVATE> [items...])
参数解析:
-
<target>:目标名。 -
<INTERFACE|PUBLIC|PRIVATE>:传播范围。-
PRIVATE:源文件仅用于当前目标编译。 -
PUBLIC:源文件用于当前目标和依赖者(很少见,主要用于对象库)。 -
INTERFACE:源文件仅由依赖者编译(常用于头文件库的.h文件,以便 IDE 显示)。
-
-
[items...]:源文件列表(支持生成器表达式)。
- 效果 :将源文件添加到目标的
SOURCES属性,并处理传递性(接口库可传递源文件)。
target_compile_features
-
作用 :指定目标所需的编译特性(如
cxx_std_11)。 -
表达式:
bash
target_compile_features(<target> <INTERFACE|PUBLIC|PRIVATE> [features...])
参数解析:
-
<target>:目标名。 -
<INTERFACE|PUBLIC|PRIVATE>:传播范围。 -
[features...]:语言特性名称,如cxx_std_11、cxx_std_14、c_std_99等。CMake 会根据特性自动设置CXX_STANDARD等属性。
- 效果 :设置
COMPILE_FEATURES属性,CMake 会自动添加相应的编译选项(如-std=c++11)。
target_precompile_headers
-
作用:为目标指定预编译头文件(CMake 3.16+)。
-
表达式:
bash
target_precompile_headers(<target> <INTERFACE|PUBLIC|PRIVATE> [header...])
参数解析:
-
<target>:目标名。 -
<INTERFACE|PUBLIC|PRIVATE>:传播范围。 -
[header...]:头文件列表(<header.h>或"header.h")。 -
REUSE_FROM <other_target>:复用另一个目标的预编译头文件,避免重复生成。
- 效果 :将头文件标记为预编译头,生成对应的
PRECOMPILE_HEADERS属性,提升编译速度。
通用目标属性操作 API
set_target_properties
-
作用:直接设置一个或多个目标的一个或多个属性。
-
表达式:
bash
set_target_properties(<target1> <target2> ... PROPERTIES
<prop1> <value1> <prop2> <value2> ...)
参数解析:
-
<target1> <target2> ...:一个或多个目标名。 -
PROPERTIES:固定关键字。 -
<prop1> <value1> <prop2> <value2> ...:属性名和值对。
- 效果 :将指定属性赋值为对应值,覆盖原有值。常用于设置
CXX_STANDARD、POSITION_INDEPENDENT_CODE、FOLDER等非传播性属性。
get_target_property
-
作用:获取目标的某个属性值。
-
表达式:
bash
get_target_property(<var> <target> <property>)
参数解析:
-
<var>:用于存储结果的变量名。 -
<target>:目标名。 -
<property>:属性名。
- 效果 :将属性值存入变量
<var>;若属性不存在,则<var>为<property>-NOTFOUND。
get_target_properties
-
作用:一次性获取目标的多个属性。
-
表达式:
bash
get_target_properties(<target> <prop1> <prop2> ...)
参数解析:
-
<var>:存储结果的变量名,结果是一个分号分隔的列表。 -
<target>:目标名。 -
<prop1> <prop2> ...:多个属性名。
- 效果 :将属性值依次存入以
<prop>_<target>命名的变量(如CXX_STANDARD_myexe)。
通用属性操作 API(适用于任意作用域)
CMake 中的属性可附加于多种对象(目录、目标、源文件、测试等)。以下命令适用于任何作用域,包括目标。
set_property
-
作用:在指定作用域上设置属性(可追加、可覆盖)。
-
表达式:
bash
set_property(<GLOBAL | DIRECTORY [dir] | TARGET [target...]
| SOURCE [src...] | TEST [test...] | INSTALL [file...]
| CACHE [entry...]>
[APPEND] [APPEND_STRING] PROPERTY <name> [value...])
参数解析:
-
<GLOBAL | DIRECTORY ...>:指定作用域。-
GLOBAL:全局属性。 -
DIRECTORY [dir]:当前目录或指定目录的属性。 -
TARGET [target...]:一个或多个目标的属性。 -
SOURCE [src...]:一个或多个源文件的属性。 -
TEST [test...]:一个或多个测试的属性。 -
INSTALL [file...]:安装文件的属性。 -
CACHE [entry...]:缓存条目的属性。
-
-
APPEND:追加值(列表形式)。 -
APPEND_STRING:将值作为字符串追加(不添加分号)。 -
PROPERTY <name>:属性名。 -
[value...]:属性值。
- 效果 :在指定对象上设置属性。
APPEND追加值,APPEND_STRING拼接字符串。
get_property
-
作用:获取指定作用域上属性的值,并提供灵活的输出控制。
-
表达式:
bash
get_property(<var> <GLOBAL | DIRECTORY [dir] | TARGET <target>
| SOURCE <source> | TEST <test> | INSTALL <file> | CACHE <entry>>
PROPERTY <name> [SET | DEFINED | BRIEF_DOCS | FULL_DOCS])
参数解析:
-
<var>:存储结果的变量名。 -
作用域选择器(同上,但只能指定单一对象)。
-
PROPERTY <name>:属性名。 -
可选标志:
-
SET:返回布尔值,表示属性是否被显式设置。 -
DEFINED:类似SET,但某些内部属性即使未显式设置也返回真。 -
BRIEF_DOCS:获取属性的简要文档。 -
FULL_DOCS:获取属性的完整文档。
-
- 效果 :将属性值存入
<var>,可选查询属性是否存在(SET)或获取文档字符串。
define_property
-
作用:定义自定义属性的文档和行为(是否可继承等)。
-
表达式:
bash
define_property(<GLOBAL | DIRECTORY | TARGET | SOURCE
| TEST | VARIABLE | CACHE>PROPERTY <name>
[INHERITED] [BRIEF_DOCS <brief>] [FULL_DOCS <full>])
参数解析:
-
<GLOBAL | DIRECTORY ...>:属性适用的作用域类型。 -
PROPERTY <name>:自定义属性名。 -
INHERITED:可选,表示该属性可以继承(如目录属性可继承给子目录)。 -
BRIEF_DOCS <brief>:简短文档字符串。 -
FULL_DOCS <full>:详细文档字符串。
- 效果 :声明一个自定义属性,使其在
get_property的BRIEF_DOCS或FULL_DOCS时有说明,并可指定是否自动继承。
查询与调试类 API
get_cmake_property
-
作用:获取 CMake 内部的全局属性(如变量列表、目标列表等)。
-
表达式:
bash
get_cmake_property(<var> <property>)
参数解析:
-
<var>:存储结果的变量名。 -
<property>:CMake 内置属性名,如VARIABLES、CACHE_VARIABLES、COMMANDS、MACROS、TARGETS等。
- 效果 :将全局属性(如
TARGETS、CACHE_VARIABLES)存入<var>。
get_directory_property
-
作用:获取目录属性,也可间接获取目标属性(通过作用域)。
-
表达式:
bash
get_directory_property(<var> [DIRECTORY <dir>] <prop>)
参数解析:
-
<var>:存储结果的变量名。 -
DIRECTORY <dir>:可选,指定目录(绝对或相对路径)。 -
<prop>:目录属性名,如INCLUDE_DIRECTORIES、COMPILE_DEFINITIONS等。
- 效果:获取当前目录或指定目录的属性值。
get_source_file_property / set_source_file_properties
-
作用 :操作源文件级属性(如
LANGUAGE、COMPILE_FLAGS等)。 -
表达式:
bash
get_source_file_property(<var> <file> <property>)
set_source_files_properties(<files...> PROPERTIES <prop1> <value1> ...)
参数解析:
-
get_source_file_property:-
<var>:存储结果的变量名。 -
<file>:源文件路径(相对或绝对)。 -
<property>:属性名,如LANGUAGE、COMPILE_FLAGS等。
-
-
set_source_files_properties:-
<files...>:一个或多个源文件。 -
PROPERTIES:关键字。 -
<prop1> <value1> ...:属性名值对。
-
- 效果:获取或设置单个源文件的属性,这些属性可能影响编译命令。
属性传递性相关概念(作用域说明)
在上述专用命令(target_...)中,PUBLIC、PRIVATE、INTERFACE 三个关键字决定了属性在目标依赖链中的传播方式:
| 作用域 | 效果 |
|---|---|
PRIVATE |
属性仅对当前目标生效,不传播给依赖者。 |
INTERFACE |
属性不对当前目标生效,但会传播给依赖者。 |
PUBLIC |
属性对当前目标生效,并且也传播给依赖者。 |
这种设计使得依赖管理(如头文件路径、编译定义)可以在整个依赖图中自动传递,无需手动重复设置
总结
目标操作 API
| 分类 | API | 作用 | 表达式(核心语法) | 效果 |
|---|---|---|---|---|
| 创建目标 | add_executable |
定义可执行文件目标 | add_executable(<name> [source...]) |
创建可执行目标,可指定源文件 |
add_library |
定义库目标(静态/动态/接口等) | `add_library(<name> [STATIC | SHARED | |
add_custom_target |
定义自定义目标(无产物) | add_custom_target(<name> [COMMAND...] [DEPENDS...]) |
生成一个"总是未构建"的目标,用于执行命令或聚合依赖 | |
| 专用配置命令 | target_include_directories |
添加头文件搜索路径 | `target_include_directories(<target> [PUBLIC | PRIVATE |
target_compile_definitions |
添加预处理器定义 | `target_compile_definitions(<target> [PUBLIC | PRIVATE | |
target_compile_options |
添加编译选项 | `target_compile_options(<target> [PUBLIC | PRIVATE | |
target_link_libraries |
指定链接的库或目标 | `target_link_libraries(<target> [PUBLIC | PRIVATE | |
target_link_options |
添加链接器选项 | `target_link_options(<target> [PUBLIC | PRIVATE | |
target_sources |
追加源文件 | `target_sources(<target> [PUBLIC | PRIVATE | |
target_compile_features |
指定所需编译特性 | `target_compile_features(<target> [PUBLIC | PRIVATE | |
target_precompile_headers |
指定预编译头文件 | `target_precompile_headers(<target> [PUBLIC | PRIVATE | |
| 通用目标属性操作 | set_target_properties |
直接设置目标的一个或多个属性 | set_target_properties(<targets...> PROPERTIES <prop1> <val1> <prop2> <val2> ...) |
批量设置目标属性,如 CXX_STANDARD、FOLDER 等 |
get_target_property |
获取目标的单个属性值 | get_target_property(<var> <target> <property>) |
将属性值存入变量,若不存在则变量为 ...-NOTFOUND |
|
get_target_properties |
获取目标的多个属性值 | get_target_properties(<target> <prop1> <prop2> ...) |
将各属性值存入以 <prop>_<target> 命名的变量 |
|
| 查询与调试 | get_cmake_property |
获取全局 CMake 属性(如所有目标列表) | get_cmake_property(<var> <property>) |
将全局属性(如 TARGETS、CACHE_VARIABLES)存入变量 |
属性操作 API(通用,适用于多种作用域)
| 分类 | API | 作用 | 表达式(核心语法) | 效果 |
|---|---|---|---|---|
| 通用属性读写 | set_property |
在指定作用域(目标、目录、源文件等)上设置属性 | set_property(<作用域> [APPEND] PROPERTY <name> [values...]) |
为指定对象设置属性值,APPEND 追加值,APPEND_STRING 拼接字符串 |
get_property |
获取指定作用域上属性的值 | `get_property(<var> <作用域> PROPERTY <name> [SET | DEFINED | |
define_property |
定义自定义属性的文档及继承行为 | define_property(<作用域> PROPERTY <name> [INHERITED] [BRIEF_DOCS <text>] [FULL_DOCS <text>]) |
声明一个自定义属性,使其在 get_property 中可显示帮助信息,并可选自动继承 |
|
| 目录/源文件属性 | get_directory_property |
获取目录属性 | get_directory_property(<var> [DIRECTORY <dir>] <prop>) |
获取当前目录或指定目录的属性值 |
get_source_file_property |
获取源文件属性(如 LANGUAGE) |
get_source_file_property(<var> <file> <property>) |
将源文件的指定属性存入变量 | |
set_source_files_properties |
设置源文件属性 | set_source_files_properties(<files...> PROPERTIES <prop1> <val1> ...) |
为源文件设置属性(如 COMPILE_FLAGS) |
|
| 全局属性查询 | get_cmake_property |
获取 CMake 全局属性 | get_cmake_property(<var> <property>) |
查询如 TARGETS、DIRECTORIES 等全局信息 |
| 变量/缓存属性 | set_property (CACHE) |
设置缓存条目属性 | set_property(CACHE <entry> PROPERTY <name> <value>) |
修改缓存条目的属性(如 ADVANCED、TYPE) |
get_property (CACHE) |
获取缓存条目属性 | get_property(<var> CACHE <entry> PROPERTY <name>) |
获取缓存条目的属性值 |
说明 :
<作用域>可以是GLOBAL、DIRECTORY、TARGET、SOURCE、TEST、INSTALL、CACHE之一,具体取决于操作对象。
CMake支持的类型
| 类型 | 创建命令 | 产物示例/说明 |
|---|---|---|
| EXECUTABLE | add_executable(<name> [source...]) |
可执行文件 。这是最终的用户应用程序或工具。在不同平台上产物不同,例如 Linux 下为 main,Windows 下为 main.exe 。 |
| STATIC | add_library(<name> STATIC [source...]) |
静态库 。它是目标文件(.o/.obj)的归档文件。在链接时,其内容会被复制到最终的可执行文件中。产物例如 Linux 下的 libfoo.a,Windows 下的 foo.lib 。 |
| SHARED | add_library(<name> SHARED [source...]) |
动态链接库(共享库) 。它在运行时被加载,可以被多个程序共享。产物例如 Linux 下的 libfoo.so,macOS 下的 libfoo.dylib,Windows 下的 foo.dll(通常还会伴随生成一个用于链接的导入库 foo.lib)。 |
| MODULE | add_library(<name> MODULE [source...]) |
模块库 。它是一种特殊的动态库,不用于链接 (即不能出现在 target_link_libraries() 的右侧),而是设计用于在运行时通过 dlopen 或 LoadLibrary 等机制动态加载的插件 。产物例如 libplugin.so 或 plugin.dll。 |
| OBJECT | add_library(<name> OBJECT [source...]) |
对象库 。它编译源文件,但不归档或链接成库文件 ,只生成中间的目标文件(.o/.obj)。这些目标文件集合可以通过 $<TARGET_OBJECTS:name> 在其他目标中引用,从而实现编译结果的重用,并避免重复编译 。 |
| INTERFACE | add_library(<name> INTERFACE) |
接口库 。它不编译任何源文件,也不生成任何库文件 。它纯粹是一个逻辑目标,用于传递使用要求(如头文件搜索路径、编译定义等)。最常见的用途是表示仅头文件(header-only)库 。 |
| IMPORTED | add_library(<name> <type> IMPORTED) |
导入库 。它用于引用磁盘上已存在的外部构建产物 (如第三方预编译库),而不在当前项目中重新构建它。通过设置其属性(如 IMPORTED_LOCATION),可以像普通目标一样使用它 。<type> 可以是 STATIC、SHARED、MODULE 或 UNKNOWN。 |
add_subdirectory
作用 :向当前构建中添加一个子目录(即子项目)。CMake 会进入该子目录,处理其中的 CMakeLists.txt 文件,并将其构建目标整合到当前构建树中。
表达式:
cpp
add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL] [SYSTEM])
参数解析:
-
source_dir:必需,子目录的路径(相对于当前CMakeLists.txt所在目录,也可以是绝对路径)。 -
binary_dir:可选,指定子目录对应的构建输出目录。若不指定,则默认使用source_dir相对于当前二进制目录的相对路径。 -
EXCLUDE_FROM_ALL:可选,子目录中的目标不会加入默认的all构建规则,除非显式依赖。 -
SYSTEM:可选(CMake 3.25+),将子目录视为系统目录,其包含路径将被视为系统路径,编译器会抑制其中的警告。
效果:
-
CMake 会在处理当前
CMakeLists.txt的过程中,暂停当前目录的解析,转而进入source_dir并执行其中的CMakeLists.txt。 -
子目录中定义的所有目标(
add_executable、add_library等)都会被添加到当前构建树中,可以被父目录中的目标引用(如通过target_link_libraries直接使用目标名)。 -
若指定了
binary_dir,子目录的构建产物会存放在该目录下,否则存放在默认位置。
典型使用场景:
-
将大型项目拆分为多个模块,每个模块放在独立子目录中,各自拥有独立的
CMakeLists.txt。 -
引用第三方库(如
add_subdirectory(third_party/foo))来集成其源码。
Install静态库
顶层CMakeLists.txt
cpp
cmake_minimum_required(VERSION 3.18)
project(InstallMyMath
LANGUAGES CXX
)
add_subdirectory(MyMath)
底层CMakeLists.txt
cpp
# 1 收集源代码
file(GLOB SRC_LISTS "src/*.cpp")
# 2 添加构建目标
add_library(MyMath STATIC ${SRC_LISTS})
# 3 设置库的使用要求,也就是下游消费者必须包含的头文件搜索路径
target_include_directories(MyMath INTERFACE
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>" # include
)
# 4 设置库的默认输出路径
set_target_properties(MyMath PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
)
# 5 安装我们的静态库
include(GNUInstallDirs)
install(TARGETS MyMath
EXPORT MyMathTargets
DESTINATION ${CMAKE_INSTALL_LIBDIR} # lib
)
# 6 安装头文件
install(DIRECTORY include/
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/math # /usr/local/include/math/math.h
FILES_MATCHING PATTERN "*.h"
)
# 7 安装导出目标集合 到 构建树
export(EXPORT MyMathTargets
FILE ${CMAKE_CURRENT_BINARY_DIR}/MyMathTargets.cmake
)
# 8 安装导出目标集合 到 安装树
install(EXPORT MyMathTargets
FILE MyMathTargets.cmake
NAMESPACE MyMath:: # MyMath::MyMath
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MyMath # /usr/local/lib/cmake/MyMath/MyMathTargets.cmake
)
# 9 生成find_package 需要的 配置文件
include(CMakePackageConfigHelpers)
configure_package_config_file(
${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/MyMathConfig.cmake
INSTALL_DESTINATION "lib/cmake/MyMath"
)
# 10 安装配置文件到cmake 标准的安装路径
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/MyMathConfig.cmake
DESTINATION "lib/cmake/MyMath"
)
配置文件
bash
@PACKAGE_INIT@
include(${CMAKE_CURRENT_LIST_DIR}/MyMathTargets.cmake)
运行结果:

find_packge查找静态库
目录结构:

CMakeLists.txt:
cpp
cmake_minimum_required(VERSION 3.10)
project(MyMathApp)
# 查找 MyMath 库
find_package(MyMath REQUIRED CONFIG)
# 添加可执行文件
add_executable(main main.cpp)
# 添加依赖关系
target_link_libraries(main PRIVATE MyMath::MyMath)

export
作用 :从当前构建树中导出一个或多个目标,并生成一个 CMake 配置文件(.cmake),描述这些目标的接口(包含目录、编译定义、链接库等)。其他项目可以通过 include 这个文件来导入这些目标,而无需先执行安装。
表达式:
cpp
export(TARGETS <target>... [NAMESPACE <namespace>] [APPEND]
FILE <filename> [EXPORT_LINK_INTERFACE_LIBRARIES])
export(PACKAGE <PackageName>)
export(TARGETS ...) 形式
参数解析:
-
TARGETS <target>...:要导出的目标列表(如库、可执行文件等)。 -
NAMESPACE <namespace>:可选,为目标名称添加前缀命名空间,导入时目标名会变为<namespace><target>。 -
APPEND:可选,如果FILE指定的文件已存在,则追加内容而非覆盖。 -
FILE <filename>:输出文件的路径(通常放在构建目录中,如MyMathTargets.cmake)。 -
EXPORT_LINK_INTERFACE_LIBRARIES:可选(旧版兼容),用于控制是否导出链接接口库(现代 CMake 已通过INTERFACE属性自动处理)。
效果:
-
生成一个 CMake 脚本文件,其中包含
add_library(... IMPORTED)等命令,用于在外部项目中导入这些目标。 -
导出的目标会保留其所有
PUBLIC和INTERFACE属性(如INTERFACE_INCLUDE_DIRECTORIES、INTERFACE_COMPILE_DEFINITIONS等),因此导入后可直接使用。 -
通常与
export(PACKAGE)配合,使find_package能够在构建树中找到该包。
export(PACKAGE <PackageName>) 形式
作用 :将当前构建树注册到 CMake 的用户包注册表中,使 find_package 能在构建目录中直接找到该包(无需安装)。
参数:
<PackageName>:包名称,例如MyMath。
效果:
-
在 CMake 的用户包注册表(
~/.cmake/packages)中记录该包的构建目录位置。 -
当其他项目调用
find_package(MyMath)时,CMake 会先搜索注册表,从而找到当前构建树中的导出文件。
export 与 install(EXPORT) 的区别
| 特性 | export |
install(EXPORT) |
|---|---|---|
| 使用场景 | 构建树内共享(不安装) | 安装后共享(部署到系统或用户目录) |
| 生成文件位置 | 构建目录(如 ${CMAKE_BINARY_DIR}) |
安装目录(如 /usr/local/lib/cmake/) |
| 导入方式 | include(...) 或 find_package(配合 export(PACKAGE)) |
find_package(依赖安装路径或 CMAKE_PREFIX_PATH) |
| 目标名称 | 可直接使用(带命名空间) | 安装后通常带有 IMPORTED 标记 |
| 依赖管理 | 导出文件依赖构建树中的其他目标 | 导出文件依赖安装后的文件路径 |
本期关于CMake在静态库上的应用方面的介绍到这里就结束了,后续我们还会更新动态库相关的知识点。敬请期待
封面图自取:
