提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
- 一、表述详解
- 二、完整项目示例
-
- [1. 项目目录结构](#1. 项目目录结构)
- [2. 源码文件](#2. 源码文件)
- [3. CMake 构建脚本](#3. CMake 构建脚本)
-
- [写法1:使用 `PUBLIC`(标准正确用法)](#写法1:使用
PUBLIC(标准正确用法)) - [写法2:错误演示(改用 `PRIVATE`)](#写法2:错误演示(改用
PRIVATE))
- [写法1:使用 `PUBLIC`(标准正确用法)](#写法1:使用
- [4. 编译与效果测试](#4. 编译与效果测试)
- [三、`PRIVATE` 的**正确使用场景**](#三、
PRIVATE的正确使用场景) -
- 调整后的目录结构
- 新增文件:`src/private_inc/internal.h`
- [修改 `src/lib.cpp`](#修改
src/lib.cpp) - [优化后的 CMake 配置](#优化后的 CMake 配置)
- 四、总结
通过实操对比 PUBLIC / PRIVATE 的效果
一、表述详解
bash
cmake_demo/
├── include/
│ └── lib.h # 带导出宏的头文件
├── src/
│ ├── lib.cpp # 动态库实现
│ └── main.cpp # 调用方程序
└── CMakeLists.txt
核心结论
target_include_directories(mylib PRIVATE 路径) 的适用场景:
该头文件路径仅被 lib.cpp(库的实现文件)使用,不会被 main.cpp(依赖该库的外部代码)包含 ,此时用 PRIVATE;
如果外部代码(main.cpp)需要包含这个路径下的头文件(lib.h),必须用 PUBLIC,否则外部目标会找不到头文件。
补充核心定义(关键)
| 作用域 | 适用场景 |
|---|---|
PUBLIC |
路径既给 lib.cpp 用,也给所有依赖 mylib 的目标(如main.cpp)用(接口头文件路径) |
PRIVATE |
路径仅给 lib.cpp 自用,不传递给外部依赖目标(库内部私有头文件路径) |
INTERFACE |
路径不给自身用,仅传递给外部依赖目标 |
二、完整项目示例
1. 项目目录结构
采用标准工程规范,公共头文件放在 include 目录,源文件放在 src 目录:
cmake_demo/
├── include/ # 公共头文件目录(外部可访问)
│ └── lib.h # 库接口声明
├── src/
│ ├── lib.cpp # 库实现文件
│ └── main.cpp # 主程序(调用库函数)
└── CMakeLists.txt # 构建脚本
2. 源码文件
include/lib.h(库的公共接口)
头文件保护宏防止重复包含,声明加法函数,会被 main.cpp 直接包含:
c
#ifndef LIB_H
#define LIB_H
// 加法函数声明:对外提供的接口
int add(int a, int b);
#endif // LIB_H
src/lib.cpp(库的实现文件)
包含公共头文件,实现加法逻辑:
c
// 包含库的接口头文件
#include "lib.h"
// 实现加法函数
int add(int a, int b) {
return a + b;
}
src/main.cpp(主程序)
调用库的 add 函数,需要包含 lib.h:
c
#include <stdio.h>
// 包含库的公共头文件
#include "lib.h"
int main() {
int res = add(10, 20);
printf("10 + 20 = %d\n", res);
return 0;
}
3. CMake 构建脚本
写法1:使用 PUBLIC(标准正确用法)
因为 main.cpp 需要依赖 include 路径找到 lib.h,因此路径需要传递给外部目标 ,用 PUBLIC:
cmake
cmake_minimum_required(VERSION 3.15)
project(AddLibraryDemo)
# C++标准配置
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 1. 创建静态库目标 mylib
add_library(mylib src/lib.cpp)
# 2. 为库添加头文件路径:PUBLIC 表示路径自身可用,且传递给依赖它的目标
target_include_directories(mylib PUBLIC include)
# 3. 创建可执行目标
add_executable(main_app src/main.cpp)
# 4. 链接库:main_app 会自动继承 mylib 的 PUBLIC/INTERFACE 头文件路径
target_link_libraries(main_app PRIVATE mylib)
写法2:错误演示(改用 PRIVATE)
如果我们把 PUBLIC 改为 PRIVATE,代表 include 路径仅给 mylib 自身使用,不传递:
cmake
# 仅修改这一行,其余代码不变
target_include_directories(mylib PRIVATE include)
4. 编译与效果测试
编译命令(终端执行)
bash
# 创建构建目录并进入
mkdir build && cd build
# 生成构建文件
cmake ..
# 编译
make
结果对比
-
PUBLIC配置 :编译成功,运行./main_app,输出:10 + 20 = 30 -
PRIVATE配置 :编译直接报错 ,提示找不到头文件:fatal error: lib.h: No such file or directory #include "lib.h"原因:
main_app无法继承include路径,编译器找不到头文件。
三、PRIVATE 的正确使用场景
为了让你理解 PRIVATE 不是无用的,我们扩展场景:给库添加私有内部头文件 ,仅 lib.cpp 使用,外部无需访问。
调整后的目录结构
cmake_demo/
├── include/ # 公共头文件(对外)
│ └── lib.h
├── src/
│ ├── private_inc/ # 库私有头文件(仅内部用)
│ │ └── internal.h
│ ├── lib.cpp
│ └── main.cpp
└── CMakeLists.txt
新增文件:src/private_inc/internal.h
c
#ifndef INTERNAL_H
#define INTERNAL_H
// 库内部使用的工具函数,不对外部暴露
static int calc(int x) {
return x * 2;
}
#endif
修改 src/lib.cpp
c
#include "lib.h"
// 包含私有内部头文件
#include "internal.h"
int add(int a, int b) {
// 调用内部工具函数
return calc(a + b);
}
优化后的 CMake 配置
公共路径用 PUBLIC,私有路径用 PRIVATE:
cmake
cmake_minimum_required(VERSION 3.15)
project(AddLibraryDemo)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_library(mylib src/lib.cpp)
# 公共头文件:传递给外部依赖目标
target_include_directories(mylib PUBLIC include)
# 私有头文件:仅库自身使用,不传递
target_include_directories(mylib PRIVATE src/private_inc)
add_executable(main_app src/main.cpp)
target_link_libraries(main_app PRIVATE mylib)
效果
main_app能继承include路径,正常找到lib.h;main_app无法访问src/private_inc路径,保证了库内部实现的封装性;lib.cpp可以同时找到公共头文件和私有头文件。
四、总结
- 表述纠正 :当
main.cpp依赖该头文件路径时,必须用PUBLIC;仅lib.cpp依赖时,才用PRIVATE; - 核心规则
- 对外暴露的接口头文件路径 →
PUBLIC(传递给依赖目标); - 库内部私有的实现头文件路径 →
PRIVATE(仅自身使用,封装隔离);
- 对外暴露的接口头文件路径 →
- 单目标/多目标通用 :这套规则是现代CMake的标准规范,无论项目大小都推荐使用,比全局的
include_directories更安全、更易维护。