【CMake】cmake实现属性传递的秘密(目标的默认输出路径 以及 如何修改输出路径)

文章目录

  • [一、目标的默认输出路径 以及 如何修改输出路径](#一、目标的默认输出路径 以及 如何修改输出路径)
    • [1. 源文件 和 头文件中内容(含完整项目路径展示)](#1. 源文件 和 头文件中内容(含完整项目路径展示))
    • [2. 顶层 以及 子目录下CMakeList.txt文件 的编辑](#2. 顶层 以及 子目录下CMakeList.txt文件 的编辑)
    • [3. 目标(可执行程序 、动/静态库)的默认输出路径](#3. 目标(可执行程序 、动/静态库)的默认输出路径)
    • [4. 如何修改 目标(可执行程序 、动/静态库)的输出路径](#4. 如何修改 目标(可执行程序 、动/静态库)的输出路径)
  • 二、cmake实现属性传递的秘密
    • [1. 属性的传递机制](#1. 属性的传递机制)
    • [2. 多层级CMakeLists.txt文件,中间层PUBLIC继承 传递属性的效果](#2. 多层级CMakeLists.txt文件,中间层PUBLIC继承 传递属性的效果)
    • [3. 多层级CMakeLists.txt文件,中间层PRIVATE继承 中断属性传递的效果](#3. 多层级CMakeLists.txt文件,中间层PRIVATE继承 中断属性传递的效果)

一、目标的默认输出路径 以及 如何修改输出路径

1. 源文件 和 头文件中内容(含完整项目路径展示)

项目路径展示图:

bash 复制代码
my_math
├── build
├── CMakeLists.txt
├── my_app
│    ├── CMakeLists.txt
│    └── main.cpp
└── my_lib
     ├── CMakeLists.txt
  	 ├── include
  	 │    └── math.h
	 └── src
		  ├── add.cpp
		  └── sub.cpp
  • my_math/my_lib/src/add.cpp
  • my_math/my_lib/src/sub.cpp

  • my_math/my_lib/include/math.h

  • my_math/my_app/main.cpp

编辑以下源文件会报错,因为该源文件包含的 main.h头文件是用户自定义的,该头文件没放在系统路径下,系统查找不到该源文件,于是报错。
需要手动添加一下系统的头文件查找路径,以下是添加步骤:

${workspaceFolder} 表示项目目录的路径:也就是 /home/zh/CMake_test

2. 顶层 以及 子目录下CMakeList.txt文件 的编辑

  • my_math/my_lib/CMakeLists.txt
  • my_math/my_app/CMakeLists.txt
  • my_math/CMakeLists.txt

子目录my_app的CMakeLists.txt文件中定义的 目标main 依赖 子目录my_lib的CMakeLists.txt文件中定义的 目标MyMath
所以 顶层CMakeLists.txt下,一定要先add_subdirectory 子目录my_lib,再add_subdirectory 子目录my_app

3. 目标(可执行程序 、动/静态库)的默认输出路径

bash 复制代码
my_math
├── build(空目录)
├── CMakeLists.txt
├── my_app
│    ├── CMakeLists.txt
│    └── main.cpp
└── my_lib
     ├── CMakeLists.txt
  	 ├── include
  	 │    └── math.h
	 └── src
		  ├── add.cpp
		  └── sub.cpp

目标(可执行程序 、动/静态库)的默认输出路径:

CMake默认会将目标的输出文件(可执行文件、动态库、静态库)放置在构建目录(${CMAKE_BINARY_DIR})中,且该路径与定义该目标的CMakeLists.txt文件相对于项目根目录的路径保持一致。

4. 如何修改 目标(可执行程序 、动/静态库)的输出路径

目标类型 属性名(单个目标) 全局变量名 适用场景
可执行文件 RUNTIME_OUTPUT_DIRECTORY CMAKE_RUNTIME_OUTPUT_DIRECTORY 控制可执行文件(如 .exe)的输出路径
动态库 LIBRARY_OUTPUT_DIRECTORY CMAKE_LIBRARY_OUTPUT_DIRECTORY 控制动态库文件(如 .so、.dll)的输出路径
静态库 ARCHIVE_OUTPUT_DIRECTORY CMAKE_ARCHIVE_OUTPUT_DIRECTORY 控制静态库文件(如 .a、.lib)的输出路径
  • my_math/my_app/CMakeLists.txt

RUNTIME_OUTPUT_DIRECTORY:可执行程序目标 的输出路径
通过 set_target_properties函数 可以修改目标的属性

  • my_math/my_lib/CMakeLists.txt

ARCHIVE_OUTPUT_DIRECTORY:静态库目标 的输出路径
通过 set_target_properties函数 可以修改目标的属性


二、cmake实现属性传递的秘密

1. 属性的传递机制

关键字 对当前目标的影响 是否传播 对当前目标依赖者的影响 解释
PRIVATE ✅ 生效 ❌ 否 ❌ 不生效 只自己用
PUBLIC ✅ 生效 ✅ 是 ✅ 生效 自己-依赖者用
INTERFACE ❌ 不生效 ✅ 是 ✅ 生效 自己不用-依赖者用

2. 多层级CMakeLists.txt文件,中间层PUBLIC继承 传递属性的效果

项目路径展示图:

bash 复制代码
Project/
├── CMakeLists.txt           # 顶层
├── core/                    # 第1层
│   ├── CMakeLists.txt
│   ├── include/
│   │   └── core_utils.h
│   └── src/
│       └── core_utils.cpp
├── network/                 # 第2层
│   ├── CMakeLists.txt
│   ├── include/
│   │   └── net_client.h
│   └── src/
│       └── net_client.cpp
└── app/                     # 第3层
    ├── CMakeLists.txt
    ├── include/
    │   └── app_config.h
    └── src/
        └── main.cpp
  1. 顶层 CMakeLists.txt (Project/CMakeLists.txt)
bash 复制代码
cmake_minimum_required(VERSION 3.15)
project(PropertyPropagationDemo)

# 添加第一层目录
add_subdirectory(core)
  1. 第一层:核心库 (core/CMakeLists.txt)
bash 复制代码
# 创建静态库目标
add_library(core_lib STATIC
    src/core_utils.cpp
)

# PUBLIC 属性:自身使用 + 传递给使用者
target_include_directories(core_lib PUBLIC
    ${CMAKE_CURRENT_SOURCE_DIR}/include  # 头文件目录
)

target_compile_definitions(core_lib PUBLIC
    CORE_ENABLE_LOGGING=1  # 日志功能开关
)

# PRIVATE 属性:仅自身使用
target_compile_definitions(core_lib PRIVATE
    CORE_DEBUG_MODE=0  # 内部调试标志
)

# INTERFACE 属性:仅传递给使用者
target_compile_definitions(core_lib INTERFACE
    USE_CORE_API=1  # 标识使用核心API
)

# 添加第二层目录
add_subdirectory(../network ${CMAKE_BINARY_DIR}/network)
  1. 第二层:网络库 (network/CMakeLists.txt)
bash 复制代码
# 创建共享库目标
add_library(network_lib SHARED
    src/net_client.cpp
)

# PUBLIC 继承 core_lib 的属性
target_link_libraries(network_lib PUBLIC
    core_lib
)

# 添加本层特有的 PUBLIC 属性
target_include_directories(network_lib PUBLIC
    ${CMAKE_CURRENT_SOURCE_DIR}/include
)

target_compile_definitions(network_lib PUBLIC
    NETWORK_TIMEOUT=3000  # 网络超时设置
)

# PRIVATE 属性(仅本层使用)
target_compile_options(network_lib PRIVATE
    -Wno-deprecated  # 禁用弃用警告
)

# INTERFACE 属性(仅传递给使用者)
target_compile_definitions(network_lib INTERFACE
    USE_NETWORK_API=1  # 标识使用网络API
)

# 添加第三层目录
add_subdirectory(../app ${CMAKE_BINARY_DIR}/app)
  1. 第三层:应用程序 (app/CMakeLists.txt)
bash 复制代码
# 创建可执行文件
add_executable(my_app
    src/main.cpp
)

# PRIVATE 链接 network_lib
target_link_libraries(my_app PRIVATE
    network_lib
)

# 添加本层属性
target_compile_definitions(my_app PRIVATE
    APP_VERSION="1.0"
)

# 打印最终继承的属性
message("\n 最终应用程序继承的属性:")
message("----------------------------------------")

# 获取包含目录
get_target_property(app_includes my_app INCLUDE_DIRECTORIES)
message("包含目录: ${app_includes}")

# 获取编译定义
get_target_property(app_defines my_app COMPILE_DEFINITIONS)
message("编译定义: ${app_defines}")

# 获取编译选项
get_target_property(app_options my_app COMPILE_OPTIONS)
message("编译选项: ${app_options}")

  • 执行 CMake 配置后输出(属性继承结果分析):
bash 复制代码
最终应用程序继承的属性:
----------------------------------------
包含目录: 
  /Project/core/include        # ← 来自 core_lib (PUBLIC)
  /Project/network/include     # ← 来自 network_lib (PUBLIC)

编译定义: 
  CORE_ENABLE_LOGGING=1        # ← 来自 core_lib (PUBLIC)
  USE_CORE_API=1               # ← 来自 core_lib (INTERFACE)
  NETWORK_TIMEOUT=3000         # ← 来自 network_lib (PUBLIC)
  USE_NETWORK_API=1            # ← 来自 network_lib (INTERFACE)
  APP_VERSION="1.0"            # ← 自身定义 (PRIVATE)

编译选项: 
  (空)                        # ← 未继承任何编译选项

  • 属性传递路径详解
属性来源 属性类型 属性内容 是否传递到 my_app 原因说明
core_lib PUBLIC CORE_ENABLE_LOGGING=1 PUBLIC 属性通过 network_lib 传递
-- PUBLIC include/core PUBLIC 头文件目录被继承
-- PRIVATE CORE_DEBUG_MODE=0 PRIVATE 属性不传递
-- INTERFACE USE_CORE_API=1 INTERFACE 属性被继承
network_lib PUBLIC NETWORK_TIMEOUT=3000 直接 PUBLIC 属性
-- PUBLIC include/network PUBLIC 头文件目录被继承
-- PRIVATE -Wno-deprecated PRIVATE 编译选项不传递
-- INTERFACE USE_NETWORK_API=1 INTERFACE 属性被继承
my_app PRIVATE APP_VERSION="1.0" 自身属性

  • 关键继承规则图解(属性如何传递到 目标my_app)
bash 复制代码
core_lib
├── PUBLIC:     → network_lib → my_app
├── PRIVATE:    × 停止传递
└── INTERFACE:  → network_lib → my_app # network_lib是 PUBLIC继承core_lib, 
                                       # 所以 network继承 core_lib传递过来的属性后,
network_lib                            # 可以将 继承到的属性继续向 my_app传递
├── PUBLIC:     → my_app
├── PRIVATE:    × 停止传递
└── INTERFACE:  → my_app

my_app
└── PRIVATE:    自身属性

3. 多层级CMakeLists.txt文件,中间层PRIVATE继承 中断属性传递的效果

修改后的第二层 CMakeLists.txt (network/CMakeLists.txt)

  1. 原:network_lib目标 PUBLIC继承 core_lib
    target_link_libraries(network_lib PUBLIC core_lib)
  2. 修改为:network_lib目标 PRIVATE继承 core_lib
    target_link_libraries(network_lib PRIVATE core_lib)
bash 复制代码
# ... 其他部分保持不变 ...

# 由 PUBLIC继承core_lib 改为 PRIVATE继承core_lib
target_link_libraries(network_lib PRIVATE  # 关键修改
    core_lib
)

# ... 其他部分保持不变 ...

  • 执行 CMake 配置后输出(属性继承结果分析):
bash 复制代码
最终应用程序继承的属性:
----------------------------------------
包含目录: 
  /Project/network/include     # ← 仅来自 network_lib (PUBLIC)

编译定义: 
  NETWORK_TIMEOUT=3000         # ← 来自 network_lib (PUBLIC)
  USE_NETWORK_API=1            # ← 来自 network_lib (INTERFACE)
  APP_VERSION="1.0"            # ← 自身定义 (PRIVATE)

编译选项: 
  (空)

  • 属性传递路径详解
属性来源 属性类型 属性内容 是否传递到 my_app 原因说明
core_lib PUBLIC CORE_ENABLE_LOGGING=1 network_lib目标 PRIVATE 继承core_lib 中断传递
-- PUBLIC include/core network_lib目标 PRIVATE 继承core_lib 中断传递
-- PRIVATE CORE_DEBUG_MODE=0 PRIVATE 属性不传递
-- INTERFACE USE_CORE_API=1 network_lib目标 PRIVATE 继承core_lib 中断传递
network_lib PUBLIC NETWORK_TIMEOUT=3000 直接 PUBLIC 属性
-- PUBLIC include/network PUBLIC 头文件目录被继承
-- PRIVATE -Wno-deprecated PRIVATE 编译选项不传递
-- INTERFACE USE_NETWORK_API=1 INTERFACE 属性被继承
my_app PRIVATE APP_VERSION="1.0" 自身属性

  • 关键继承规则图解(属性如何传递到 目标my_app)
bash 复制代码
core_lib
├── PUBLIC:     → network_lib (但停止传递)
├── PRIVATE:    × 停止传递
└── INTERFACE:  → network_lib (但停止传递) # network_lib是 PRIVATE继承core_lib, 
                                         # 所以 network继承到 core_lib传递过来的属性后,
network_lib                              # 不能将 继承到的属性继续向 my_app传递
├── PUBLIC:     → my_app
├── PRIVATE:    × 停止传递
└── INTERFACE:  → my_app

my_app
└── PRIVATE:    自身属性

相关推荐
wangjialelele2 小时前
现代C++:C++17新特性整理
c语言·开发语言·c++·visual studio code
字节高级特工2 小时前
C++从入门到熟悉:深入剖析const和constexpr
前端·c++·人工智能·后端·算法
The森2 小时前
macOS 26(M芯片)部署 cocos2d-x(C++)全链路指南——Xcode + Rosetta
c++·经验分享·笔记·macos·xcode·cocos2d
王璐WL2 小时前
【C++】构造函数+类型转换+static成员
c++
仲舟2 小时前
【Qt游戏】骰子街Machi_Koro_AI
c++·人工智能·qt·游戏
Trouvaille ~2 小时前
【优选算法篇】队列与宽度优先搜索(BFS)——层层递进的视野
c++·算法·leetcode·青少年编程·面试·蓝桥杯·宽度优先
REDcker2 小时前
ARMv8、AArch64 与 arm64:命名与体系结构要点
开发语言·c++·arm
旖-旎3 小时前
位运算(判断字符是否唯一)(1)
c++·算法·leetcode·位运算
ouliten3 小时前
C++笔记:标签分派
c++·笔记