cmake可见性和AppArmor示例
This commit is contained in:
parent
0eeb4a7bb6
commit
4b4b933e3d
19 changed files with 661 additions and 0 deletions
35
cmake/visibility/CMakeLists.txt
Normal file
35
cmake/visibility/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
cmake_minimum_required(VERSION 3.15)
|
||||
project(visibility_demo CXX)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
# ============ color ============
|
||||
add_library(color
|
||||
color/src/color.cpp
|
||||
color/src/rgb_convert.cpp
|
||||
)
|
||||
target_include_directories(color
|
||||
PUBLIC color/public # 对外头目录:用户由此 #include <color/color.h>
|
||||
PRIVATE color/include # 内部头目录:rgb_convert.h 只有 color 自己可见
|
||||
)
|
||||
# 宏出现在公开头文件的 #ifdef 里,决定 API 形状。
|
||||
# 若只标 PRIVATE:color.cpp 编译出了 brightColorCode,
|
||||
# 但用户看到的头文件里该声明被预处理掉 → 库和用户对 API 的理解不一致。
|
||||
target_compile_definitions(color PUBLIC COLOR_ENABLE_BRIGHT)
|
||||
|
||||
# ============ timeutil ============
|
||||
add_library(timeutil timeutil/timeutil.cpp)
|
||||
target_include_directories(timeutil PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/timeutil)
|
||||
|
||||
# ============ printer ============
|
||||
add_library(printer printer/src/printer.cpp)
|
||||
target_include_directories(printer PUBLIC printer/public)
|
||||
target_link_libraries(printer
|
||||
PUBLIC color # printer.h 引用了 color/color.h → 契约的一部分
|
||||
PRIVATE timeutil # 只有 printer.cpp 用 → 实现细节
|
||||
)
|
||||
# 时间格式只影响 printer.cpp 的编译 → PRIVATE,不泄漏、改格式不触发下游重编
|
||||
target_compile_definitions(printer PRIVATE "PRINTER_TIME_FORMAT=\"%H:%M:%S\"")
|
||||
|
||||
# ============ app ============
|
||||
add_executable(app app/main.cpp)
|
||||
target_link_libraries(app PRIVATE printer)
|
||||
64
cmake/visibility/README.md
Normal file
64
cmake/visibility/README.md
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
# CMake target 可见性 Demo(visibility)
|
||||
|
||||
> 来自博客 `docs/编程/20-接口可见性.md` §5.2「完整 Demo」。
|
||||
> 演示 `target_include_directories` / `target_link_libraries` /
|
||||
> `target_compile_definitions` 上 PUBLIC / PRIVATE / INTERFACE 的传播语义。
|
||||
|
||||
## 运行
|
||||
|
||||
```bash
|
||||
cd cmake/visibility
|
||||
cmake -B build && cmake --build build
|
||||
./build/app
|
||||
```
|
||||
|
||||
预期输出(终端里是彩色的):
|
||||
|
||||
```
|
||||
10:37:06 hello (绿色)
|
||||
bright red (高亮红 —— PUBLIC 宏 COLOR_ENABLE_BRIGHT 传播到 app 的证据)
|
||||
(没有 "leaked!" —— printer 的 PRIVATE 宏 PRINTER_TIME_FORMAT 被隔离的证据)
|
||||
```
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
visibility/
|
||||
├── CMakeLists.txt
|
||||
├── app/
|
||||
│ └── main.cpp # 最终用户,只认识 printer
|
||||
├── color/
|
||||
│ ├── public/color/color.h # 对外 API 头(含 PUBLIC 宏开关 COLOR_ENABLE_BRIGHT)
|
||||
│ ├── include/rgb_convert.h # 内部中间件头,仅库内 .cpp 共享(PRIVATE 目录)
|
||||
│ └── src/{color,rgb_convert}.cpp
|
||||
├── timeutil/
|
||||
│ └── {timeutil.h,timeutil.cpp} # printer 的私有依赖
|
||||
└── printer/
|
||||
├── public/printer/printer.h # 对外 API 头(引用了 color → color 是 PUBLIC 依赖)
|
||||
└── src/printer.cpp
|
||||
```
|
||||
|
||||
依赖与可见性一图流:
|
||||
|
||||
```
|
||||
app ──PRIVATE──> printer ──PUBLIC──> color ✓ app 能 include color.h、感知 COLOR_ENABLE_BRIGHT
|
||||
│ └─(内部) rgb_convert.h ✗ 外部看不见(include/ 是 PRIVATE 目录)
|
||||
└────PRIVATE──> timeutil ✗ app 看不见 timeutil.h
|
||||
└────PRIVATE 宏 PRINTER_TIME_FORMAT ✗ 不泄漏给 app
|
||||
```
|
||||
|
||||
## 验证实验(§5.3)
|
||||
|
||||
| # | 操作 | 实测结果 |
|
||||
|---|------|---------|
|
||||
| 1 | 直接编译运行 | ✅ 输出 bright red,不输出 leaked! |
|
||||
| 2 | main.cpp 加 `#include "rgb_convert.h"` | ✅ `fatal error: rgb_convert.h: No such file or directory` |
|
||||
| 3 | main.cpp 加 `#include "timeutil.h"` | ✅ `fatal error: timeutil.h: No such file or directory` |
|
||||
| 4 | printer 的 `PUBLIC color` 改 `PRIVATE color` | (未跑)printer 自身编译过,app 找不到 color/color.h 报错 |
|
||||
|
||||
## 判断口诀
|
||||
|
||||
打开自己的公开头文件看一眼:
|
||||
- 头文件里 `#include` 了谁 → 那个库 **PUBLIC**
|
||||
- 头文件里 `#ifdef` 了哪个宏(宏影响 API 形状)→ 那个宏 **PUBLIC**
|
||||
- 只在 .cpp 里出现的库/宏/路径 → **PRIVATE**
|
||||
19
cmake/visibility/app/main.cpp
Normal file
19
cmake/visibility/app/main.cpp
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#include <printer/printer.h>
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
Printer p;
|
||||
p.print("hello", Color::Green);
|
||||
|
||||
// COLOR_ENABLE_BRIGHT 是 color 的 PUBLIC 宏,
|
||||
// 顺着 app → printer → color 传播到这里,本分支会被编译进去:
|
||||
#ifdef COLOR_ENABLE_BRIGHT
|
||||
std::cout << brightColorCode(Color::Red) << "bright red" << "\033[0m\n";
|
||||
#endif
|
||||
|
||||
// PRINTER_TIME_FORMAT 是 printer 的 PRIVATE 宏,这里看不见:
|
||||
#ifdef PRINTER_TIME_FORMAT
|
||||
std::cout << "leaked!\n"; // 永远不会被编译进去
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
4
cmake/visibility/color/include/rgb_convert.h
Normal file
4
cmake/visibility/color/include/rgb_convert.h
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
#pragma once
|
||||
// 内部工具:把 RGB 分量拼成 ANSI 真彩色转义码。
|
||||
// 供 color 库内部多个 .cpp 共享,不属于对外 API。
|
||||
const char* rgbToAnsi(int r, int g, int b);
|
||||
11
cmake/visibility/color/public/color/color.h
Normal file
11
cmake/visibility/color/public/color/color.h
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
enum class Color { Red, Green, Blue };
|
||||
|
||||
const char* colorCode(Color c);
|
||||
|
||||
// 这个宏出现在公开头文件里,直接决定 API 的形状(多不多一个函数)。
|
||||
// 因此该宏必须对"用 color 的人"同样可见 → CMake 里标 PUBLIC。
|
||||
#ifdef COLOR_ENABLE_BRIGHT
|
||||
const char* brightColorCode(Color c); // 高亮色版本
|
||||
#endif
|
||||
22
cmake/visibility/color/src/color.cpp
Normal file
22
cmake/visibility/color/src/color.cpp
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#include "color/color.h"
|
||||
#include "rgb_convert.h" // 内部头:能找到它,靠的是 PRIVATE 的 include/ 搜索路径
|
||||
|
||||
const char* colorCode(Color c) {
|
||||
switch (c) {
|
||||
case Color::Red: return rgbToAnsi(205, 49, 49);
|
||||
case Color::Green: return rgbToAnsi(13, 188, 121);
|
||||
case Color::Blue: return rgbToAnsi(36, 114, 200);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
#ifdef COLOR_ENABLE_BRIGHT
|
||||
const char* brightColorCode(Color c) {
|
||||
switch (c) {
|
||||
case Color::Red: return rgbToAnsi(241, 76, 76);
|
||||
case Color::Green: return rgbToAnsi(35, 209, 139);
|
||||
case Color::Blue: return rgbToAnsi(59, 142, 234);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
#endif
|
||||
8
cmake/visibility/color/src/rgb_convert.cpp
Normal file
8
cmake/visibility/color/src/rgb_convert.cpp
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#include "rgb_convert.h"
|
||||
#include <cstdio>
|
||||
|
||||
const char* rgbToAnsi(int r, int g, int b) {
|
||||
static char buf[32]; // demo 从简,非线程安全
|
||||
std::snprintf(buf, sizeof(buf), "\033[38;2;%d;%d;%dm", r, g, b);
|
||||
return buf;
|
||||
}
|
||||
9
cmake/visibility/printer/public/printer/printer.h
Normal file
9
cmake/visibility/printer/public/printer/printer.h
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include <color/color.h> // 公开头引用了 color → color 必须是 PUBLIC 依赖
|
||||
// 注意:这里没有 timeutil.h,也没有 PRINTER_TIME_FORMAT
|
||||
|
||||
class Printer {
|
||||
public:
|
||||
void print(const std::string& msg, Color c);
|
||||
};
|
||||
12
cmake/visibility/printer/src/printer.cpp
Normal file
12
cmake/visibility/printer/src/printer.cpp
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#include "printer/printer.h"
|
||||
#include "timeutil.h" // 只在实现里用 → timeutil 是 PRIVATE 依赖
|
||||
#include <iostream>
|
||||
|
||||
#ifndef PRINTER_TIME_FORMAT // 只在本 .cpp 里用的宏 → PRIVATE
|
||||
#define PRINTER_TIME_FORMAT "%H:%M:%S" // 没从 CMake 传进来时的兜底
|
||||
#endif
|
||||
|
||||
void Printer::print(const std::string& msg, Color c) {
|
||||
std::cout << timestamp(PRINTER_TIME_FORMAT) << " "
|
||||
<< colorCode(c) << msg << "\033[0m" << std::endl;
|
||||
}
|
||||
9
cmake/visibility/timeutil/timeutil.cpp
Normal file
9
cmake/visibility/timeutil/timeutil.cpp
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#include "timeutil.h"
|
||||
#include <ctime>
|
||||
|
||||
std::string timestamp(const char* fmt) {
|
||||
char buf[32];
|
||||
std::time_t t = std::time(nullptr);
|
||||
std::strftime(buf, sizeof(buf), fmt, std::localtime(&t));
|
||||
return buf;
|
||||
}
|
||||
3
cmake/visibility/timeutil/timeutil.h
Normal file
3
cmake/visibility/timeutil/timeutil.h
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
std::string timestamp(const char* fmt); // fmt 形如 "%H:%M:%S"
|
||||
Loading…
Add table
Add a link
Reference in a new issue