chore: update build system and docs for new modules

- release/src/public/makefile: 添加 libxml/libcmd/libdatacenter 到 SUBDIRS
- SPEC.md: 补全 libdatacenter §11 完整功能规格(300+ 行)
- docs/README.md: 更新模块索引和依赖关系图
- 10/10 模块 x86 全量编译通过
This commit is contained in:
ypc 2026-07-07 17:30:18 +08:00
parent f56ede7316
commit 9d12019961
3 changed files with 387 additions and 69 deletions

394
SPEC.md
View File

@ -399,58 +399,362 @@ comm_send → 投递到对应 fd
## 11. libdatacenter 自研模块详细功能
### 功能点(来自 RTU 原工程 myDatacenter.h + datacenter/*.cpp 分析)
> 基于 RTU 原工程 libdatacenter v1 与 libdatacenter_2 完整源码分析。
> 新工程采用纯 C 接口(`extern "C"` + C++ 内部实现,参数文件读写通过钩子解耦。
#### 11.1 信号注册5 种信号类型)
| 序号 | 函数 | 说明 |
|------|------|------|
| D01 | `dc_signal_out(saddr, desc, data_type, p_data)` | 注册输出信号(遥测/遥信) |
| D02 | `dc_signal_out_with_callback(...)` | 输出信号+变化回调 |
| D03 | `dc_signal_in(saddr, desc, link_saddr, p_data)` | 注册输入信号(关联输出信号) |
| D04 | `dc_signal_in_with_callback(...)` | 输入信号+变化回调 |
| D05 | `dc_signal_ao(saddr, desc, data_type, ctrl_type, p_data, cb, mod)` | 注册模拟输出(遥控) |
| D06 | `dc_signal_param(saddr, desc, data_type, ctrl_type, p_data, num, cb, mod)` | 注册参数(定值) |
| D07 | `dc_signal_yk(saddr, desc, data_type, ctrl_type, p_data, cb, mod)` | 注册遥控信号 |
### 11.0 模块架构与设计思想
#### 11.2 信号控制
| 序号 | 函数 | 说明 |
|------|------|------|
| D08 | `dc_signal_ao_set_val(saddr, step, ctrl, p_data, mod)` | 设置 AO 值(SBO/直接) |
| D09 | `dc_signal_param_set_val(saddr, step, ctrl, zone, p_data, mod)` | 设置定值(带区号) |
| D10 | `dc_signal_yk_set_status(saddr, step, ctrl, p_data, mod)` | 设置遥控状态 |
```
┌──────────────────────────────────────────────────────────────┐
│ 应用层(协议栈/Web/主程序) │
│ 调用 dc_xxx_register / dc_xxx_set_val / dc_run_100ms 等 │
├──────────────────────────────────────────────────────────────┤
│ libdatacenter纯 C 接口层) │
│ ┌──────────┬──────────┬──────────┬──────────┬────────────┐ │
│ │ out 信号 │ in 信号 │ yk 信号 │ ao 信号 │ param 信号 │ │
│ │ (遥测/ │ (关联 │ (遥控) │ (模拟 │ (定值/ │ │
│ │ 遥信) │ 输出) │ │ 输出) │ 参数) │ │
│ └──────────┴──────────┴──────────┴──────────┴────────────┘ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ 内部引擎hash查找 / 值校验 / 脏标记 / 变化检测 / 回路阻断│ │
│ └──────────────────────────────────────────────────────────┘ │
│ ┌──────────────┬──────────────┬────────────────────────────┐ │
│ │ 事件队列 │ 扰动队列 │ 故障队列 │ │
│ │ (SOE) │ (Disturb) │ (Fault) │ │
│ └──────────────┴──────────────┴────────────────────────────┘ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ 参数配置钩子(解析/保存/变更通知) │ │
│ │ 异步执行钩子(发起/结果/超时/取消) │ │
│ └──────────────────────────────────────────────────────────┘ │
├──────────────────────────────────────────────────────────────┤
│ 实现层C++: unordered_map + XXH3_128bits 哈希 + mutex
└──────────────────────────────────────────────────────────────┘
```
#### 11.3 信号查询
| 序号 | 函数 | 说明 |
|------|------|------|
| D11 | `dc_get_out_signal_info(saddr, desc, data_type, p_data)` | 查询输出信号信息 |
| D12 | `dc_get_in_signal_info(...)` | 查询输入信号 |
| D13 | `dc_get_ao_signal_info(...)` | 查询 AO 信号 |
| D14 | `dc_get_param_signal_info(...)` | 查询参数信号 |
| D15 | `dc_get_yk_signal_info(...)` | 查询遥控信号 |
| D16 | `dc_get_signal_val(p_data, data_type)` | 信号值转字符串 |
| D17 | `dc_set_out_signal_val(saddr, set_data, mod)` | 设置输出信号值 |
| D18 | `dc_get_signal_count(type)` | 按类型统计信号数 |
**核心约束**
- 信号唯一标识用 `saddr`(字符串,如 `"RPC:1:YC:1:val"`
- 每个信号注册时绑定 `module_id`(模块标识字符串),用于回路阻断
- out 信号值变更不是同步回调,而是**脏标记 + 100ms 延迟批量检测**(避免频繁回调)
- yk/ao/param 控制值变更才是**同步回调**(控制场景需要即时响应)
- 参数定值支持多区(如运行区/检修区),每区独立存储
#### 11.4 事件/扰动/故障队列
| 序号 | 函数 | 说明 |
|------|------|------|
| D19 | `dc_event_queue_push(soe)` | SOE 事件入队 |
| D20 | `dc_event_register_queue_pop(cb)` | 注册事件消费回调 |
| D21 | `dc_disturb_dd_queue_push(dd)` | 扰动数据入队 |
| D22 | `dc_disturb_dd_register_queue_pop(cb)` | 注册扰动消费回调 |
| D23 | `dc_fault_queue_push(fault)` | 故障数据入队 |
| D24 | `dc_fault_register_queue_pop(cb)` | 注册故障消费回调 |
### 11.1 数据结构
#### 11.5 控制步骤枚举
#### 11.1.1 控制枚举
```c
SIGNAL_CTRL_STEP { READY, SELECT, DIRECT, CANCEL } // SBO 控制步骤
SIGNAL_CTRL_TYPE { NONE, DIRECT_NORMAL, SBO_NORMAL } // 控制类型
enum SIGNAL_CTRL_TYPE
{
NONE = 0, /* 无控制 */
DIRECT_NORMAL = 1, /* 直控(直接执行,无需选择-确认) */
SBO_NORMAL = 2, /* 选控(选择-确认两阶段SBO: Select Before Operate */
};
enum SIGNAL_CTRL_STEP
{
READY = 0, /* 就绪/空闲 */
SELECT = 1, /* 选择SBO 第一步:锁住信号,暂存选择值) */
DIRECT = 2, /* 执行SBO 第二步:确认后写入,或直控直接执行) */
CANCEL = 3, /* 取消(回退到 READY */
};
```
### 源文件组成15 个 .cpp 文件)
#### 11.1.2 控制上下文
```c
typedef struct
{
uint8_t step : 2; /* 当前控制步骤 SIGNAL_CTRL_STEP */
uint8_t type : 2; /* 控制类型 SIGNAL_CTRL_TYPE */
uint8_t backup : 4; /* 备用 */
uint8_t data_type; /* 数据类型 */
void *p_data; /* 暂存数据指针SELECT时保存选择值DIRECT时用于校验 */
} stru_signal_ctrl;
```
datacenter.cpp dc_cfg_check.cpp dc_event.cpp
dc_param.cpp dc_signal.cpp dc_signal_compare.cpp
dc_signal_core.cpp dc_signal_ctrl.cpp dc_signal_find.cpp
dc_signal_query.cpp dc_signal_show.cpp dc_signal_util.cpp
#### 11.1.3 信号参数元数据
```c
typedef struct
{
float min; /* 最小值 */
float max; /* 最大值 */
float step; /* 步长 */
char unit[32]; /* 单位(如 "kV", "A", "Hz" */
} stru_signal_param;
```
#### 11.1.4 内部信号节点
```c
typedef struct stru_signal
{
uint32_t id; /* 全局唯一ID递增分配用于 id_index 数组索引) */
XXH128_hash_t hash; /* 128位哈希saddr 的 XXH3_128bits */
char saddr[128]; /* 短地址 */
char desc[256]; /* 描述 */
uint8_t data_type; /* 数据类型 */
/* 数据指针列表out/in/yk/ao 为单元素param 为多区数组) */
void **vec_p_data; /* 动态数组:当前数据指针 */
int vec_p_data_count; /* 数据指针个数 */
void *p_last_data; /* 上一次数据快照out信号变更检测用 */
void **vec_p_default_data; /* 默认值指针param 恢复出厂用) */
/* 链接关系 */
char link_saddr[128]; /* in 信号:链接的 out saddr */
char **link_saddrs; /* out 被哪些 in 链接 */
int link_count;
uint8_t ctrl_type; /* 控制类型 SIGNAL_CTRL_TYPE */
stru_signal_param param; /* 参数元数据min/max/step/unit */
/* 回调列表(每个 cb 绑定 module_id 用于回路阻断) */
struct
{
char *module_id;
out_signal_change_cb out_cb; /* out 信号专用 */
signal_change_cb ctrl_cb; /* yk/ao/param 专用 */
} cb_list[16];
int cb_count;
char last_caller_module[64]; /* 最后修改本信号的模块ID回路阻断 */
} stru_signal;
```
#### 11.1.5 信号存储架构
```c
/* 每种信号类型一个独立的 mapsaddr→signal*+ id数组 */
typedef struct
{
pthread_mutex_t mtx;
uint32_t signal_id; /* 自增ID分配器 */
void *map_signals; /* C++ unordered_multimap<XXH128, signal*> */
stru_signal **id_index; /* id→指针 数组支持按ID遍历 */
int id_index_cap;
} stru_signal_map;
typedef struct
{
stru_signal_map signal_out;
stru_signal_map signal_in;
stru_signal_map signal_yk;
stru_signal_map signal_ao;
stru_signal_map signal_param;
} stru_datacenter;
```
### 11.2 模块生命周期与周期性函数
| 序号 | 函数 | 说明 |
|------|------|------|
| D00a | `dc_init(path)` | 初始化:解析参数配置文件(param.xml→self_param.xml),注册配置中的信号 |
| D00b | `dc_run_100ms()` | 每100ms① out信号变化检测+批量触发回调 ② 事件/扰动/故障队列弹出消费 |
| D00c | `dc_run_1000ms()` | 每1000ms检测参数变更标志有变更则写 self_param.xml |
### 11.3 信号注册5 种类型,均带 module_id
**关键设计**:所有注册函数必须传入 `module_id` 字符串,用于回路阻断——当模块 A 修改信号值时A 自身的回调不会被触发,只通知其他模块。
| 序号 | 函数 | 说明 |
|------|------|------|
| D01 | `dc_signal_out(saddr, desc, data_type, p_data, module_id)` | 注册输出信号(遥测/遥信) |
| D02 | `dc_signal_out_with_callback(saddr, desc, data_type, p_data, cb, module_id)` | 注册输出信号+变化回调(延迟触发,非同步) |
| D03 | `dc_signal_out_link_with_callback(saddr, pp_data, cb, module_id)` | 链接已有 out 信号,获取数据指针并注册回调 |
| D04 | `dc_signal_in(saddr, desc, link_saddr, pp_data, module_id)` | 注册输入信号,自动关联输出信号的数据指针 |
| D05 | `dc_signal_in_with_callback(saddr, desc, link_saddr, pp_data, cb, module_id)` | 输入信号+回调回调挂在被链接的out上 |
| D06 | `dc_signal_ao(saddr, desc, data_type, ctrl_type, p_data, cb, module_id)` | 注册模拟输出信号 |
| D07 | `dc_signal_ao_link_with_callback(saddr, pp_data, cb, module_id)` | 链接已有 ao 信号 |
| D08 | `dc_signal_param(saddr, desc, data_type, ctrl_type, pp_data, num, cb, module_id)` | 注册定值参数信号num为定值区数 |
| D09 | `dc_signal_param_link_with_callback(saddr, pp_data, num, cb, module_id)` | 链接已有 param 信号 |
| D10 | `dc_signal_yk(saddr, desc, data_type, ctrl_type, p_data, cb, module_id)` | 注册遥控信号 |
| D11 | `dc_signal_yk_link_with_callback(saddr, pp_data, cb, module_id)` | 链接已有 yk 信号 |
**注册流程**(以 out 为例):
```
dc_signal_out(saddr, desc, data_type, p_data, module_id)
→ 检查 saddr 是否已存在(重复注册报错)
→ 计算 XXH3_128bits(saddr)
→ 分配 p_last_data保存旧值快照用于变更检测
→ 插入 g_datacenter.signal_out
→ dc_set_param_cfg_change(true) /* ao/param 注册需标记配置变更 */
```
**in 信号关联逻辑**
```
dc_signal_in(saddr, desc, link_saddr, pp_data)
→ 查找 link_saddr 对应的 out 信号
→ (*pp_data) = out信号的 vec_p_data[0](共享同一数据指针)
→ 在 out 信号的 link_saddrs 中追加 in 的 saddr
→ signal.data_type = out.data_type数据类型跟随 out
```
### 11.4 信号控制(含 SBO 流程 + 值校验 + 回路阻断)
| 序号 | 函数 | 说明 |
|------|------|------|
| D12 | `dc_signal_ao_set_val(saddr, step, ctrl, p_data, module_id)` | 设置 AO 值(带 SBO 流程控制+值校验) |
| D13 | `dc_signal_ao_set_val_without_check(saddr, data_type, p_data, module_id)` | 设置 AO 值(跳过校验,用于初始化恢复) |
| D14 | `dc_signal_param_set_val(saddr, step, ctrl, zone, p_data, module_id)` | 设置定值(指定区号,带校验) |
| D15 | `dc_signal_param_set_val_without_check(saddr, data_type, zone, p_data, module_id)` | 设置定值(跳过校验) |
| D16 | `dc_signal_yk_set_status(saddr, step, ctrl, p_data, module_id)` | 设置遥控状态 |
**SBO 控制流程**
```
─── READY ──→ SELECT锁住信号暂存选择值到 ctrl.p_data
│ │
│ ├──→ CANCEL回退 READYctrl.step = READY
│ │
│ └──→ DIRECT校验值==选择值 → 写入 vec_p_data → ctrl.step=READY
└──→ DIRECT直控模式直接写入无需 SELECT
```
**值校验链**(以 `dc_check_val_valid` 为例):
1. 检查 zone 是否越界
2. 检查新旧值是否变化(无变化→拒绝)
3. 根据 data_type 检查值是否在 param.min/max范围内
4. 所有类型bool/int/float/double/IP/MAC/str全覆盖
**回路阻断机制**(核心设计):
```cpp
// 回调通知时,跳过发起修改的模块自身
for(auto &entry : p_signal->cb_list)
{
if (entry.first == module_id) continue; // 回路阻断:不发给自己
entry.second(saddr, step, data_type, zone, p_data);
}
```
**out 信号变化的延迟回调**(与 ao/yk/param 不同):
```
dc_set_out_signal_val(saddr, set_data, module_id)
→ p_signal->last_caller_module = module_id /* 记录调用方 */
→ dc_mark_signal_dirty(p_signal) /* 标记脏,不立即回调 */
→ 写入新值到 vec_p_data[0]
dc_run_100ms()
→ dc_signal_out_change_check()
→ 遍历 g_dirty_out_signals
→ 比较 vec_p_data[0] vs p_last_data
→ 有变化→通知cb_list跳过 last_caller_module
→ 更新 p_last_data
```
### 11.5 信号查询
| 序号 | 函数 | 说明 |
|------|------|------|
| D17 | `dc_get_out_signal_info(saddr, desc, desc_len, data_type, pp_data)` | 查询 out 信号 |
| D18 | `dc_get_in_signal_info(saddr, desc, desc_len, data_type, pp_data)` | 查询 in 信号 |
| D19 | `dc_get_ao_signal_info(saddr, desc, desc_len, data_type, p_param, ctrl_type, pp_data)` | 查询 ao 信号(含参数元数据) |
| D20 | `dc_get_param_signal_info(saddr, desc, desc_len, data_type, p_param, ctrl_type, pp_vec_data, p_count)` | 查询 param 信号(多区数据指针列表) |
| D21 | `dc_get_yk_signal_info(saddr, desc, desc_len, data_type, ctrl_type, pp_data)` | 查询 yk 信号 |
| D22 | `dc_get_signal_val(p_data, data_type, buf, buf_len)` | 信号值→字符串(纯 C 接口) |
| D23 | `dc_set_out_signal_val(saddr, set_data, module_id)` | 设置 out 信号值(脏标记+延迟回调) |
| D24 | `dc_get_signal_count(type_str)` | 按类型统计信号数("out"/"in"/"yk"/"ao"/"param" |
| D25 | `dc_get_signal_info_by_id(type_str, id, saddr, saddr_len, desc, desc_len, data_type_str, type_str_len, ctrl_type, link_str, link_len)` | 按ID查询信号基本信息供前端遍历 |
### 11.6 事件/扰动/故障队列
| 序号 | 类型 | 入队函数 | 注册消费回调 | 数据内容 |
|------|------|----------|-------------|----------|
| D26 | SOE 事件 | `dc_event_queue_push(p_soe)` | `dc_event_register_queue_pop(cb)` | saddr + status + 时间戳(sec,ms) |
| D27 | 扰动数据 | `dc_disturb_dd_queue_push(p_dd)` | `dc_disturb_dd_register_queue_pop(cb)` | saddr + fVal + 时间戳(sec,ms) |
| D28 | 故障录波 | `dc_fault_queue_push(p_fault)` | `dc_fault_register_queue_pop(cb)` | vec_soe + vec_disturb_yc |
**队列消费机制**
- 支持多个消费者(`vector<dc_queue_pop_cb>`
- `dc_run_100ms()` 中批量弹出消费,加锁 swap 减少锁持有时间
- push 时自动补时间戳sec==0 && ms==0 时自动获取当前时间)
### 11.7 参数配置文件解析与保存(解耦钩子设计)
**设计原则**参数文件读写通过钩子函数注册datacenter 不直接依赖 tinyxml2。
```c
/**
* @brief 参数配置文件提供者(由应用层注册)
* @param path 输出:返回配置文件的路径
* @param len 路径缓冲区大小
* @param buf 输出:返回配置文件的内容缓冲区
* @param size 输出:返回内容大小
* @return 0 成功,-1 没找到/不支持
*/
typedef int (*dc_param_cfg_read_cb)(char *path, int len, char **buf, int *size);
/**
* @brief 参数配置保存回调(由应用层注册)
* @param path 文件路径
* @param buf 要保存的内容
* @param size 内容大小
* @return 0 成功,-1 失败
*/
typedef int (*dc_param_cfg_save_cb)(const char *path, const char *buf, int size);
```
| 序号 | 函数 | 说明 |
|------|------|------|
| D29 | `dc_param_cfg_register_read_cb(cb)` | 注册参数配置读取回调 |
| D30 | `dc_param_cfg_register_save_cb(cb)` | 注册参数配置保存回调 |
| D31 | `dc_param_cfg_changed()` | 查询配置是否有未保存变更(返回 0/1 |
**配置文件语义**由钩子实现方保证datacenter 不解析格式):
- `param.xml`参数模板元数据saddr, desc, type, min, max, step, unit, default, value
- `self_param.xml`:用户运行时值(仅 saddr + value持久化动态修改
- 初始化时:先读 param.xml 的元数据注册信号 → 再读 self_param.xml 覆盖运行时值
- 配置变更时dc_param_cfg_check() 检测到变更标志 → 调 save_cb 写入 self_param.xml
### 11.8 类型系统工具函数
| 序号 | 函数 | 说明 |
|------|------|------|
| D32 | `dc_get_data_type_str_by_id(data_type)` | DATA_TYPE_U8→"uint8_t" |
| D33 | `dc_get_data_type_id_by_str("float")` | "float"→DATA_TYPE_F32 |
| D34 | `dc_get_data_type_len(data_type)` | 获取字节长度 |
| D35 | `dc_create_data_ptr_by_type(data_type)` | 根据类型 new 并清零 |
| D36 | `dc_delete_signal_data(p_data, data_type)` | 根据类型 delete |
| D37 | `dc_set_signal_val_from_str(p_data, data_type, str)` | 字符串→值("3.14"→3.14f |
| D38 | `dc_set_signal_val(p_data, data_type, set_data)` | 内存拷贝赋值 |
| D39 | `dc_data_compare(data_type, p_data1, p_data2)` | 类型感知的值比较 |
### 11.9 调试与导出
| 序号 | 函数 | 说明 |
|------|------|------|
| D40 | `dc_save_out_signals_xml(path)` | 导出所有已注册 out 信号到 XML供前端 PLC 配置读取) |
### 11.10 源文件对照表
| RTU原工程文件 | 新工程文件 | 说明 |
|---------------|-----------|------|
| `inc/dc_signal.h` | `inc/myDatacenter.h` | 合并为单头文件纯C接口 |
| `inc/dc_event.h` | ↑ | 合并 |
| `inc/dc_param.h` | ↑ | 合并 |
| `src/dc_signal.cpp` | `src/myDatacenter.cpp` | 信号注册主体 |
| `src/dc_signal_core.cpp` | ↑ | map操作+脏标记 |
| `src/dc_signal_ctrl.cpp` | ↑ | 值校验+控制流程 |
| `src/dc_signal_query.cpp` | ↑ | 信号查询+out变化检测 |
| `src/dc_signal_compare.cpp` | ↑ | 值比较+元数据应用 |
| `src/dc_signal_find.cpp` | ↑ | hash查找 |
| `src/dc_signal_util.cpp` | ↑ | 类型工具函数 |
| `src/dc_signal_show.cpp` | ↑ | 信号展示+cmd命令可选 |
| `src/datacenter.cpp` | ↑ | 初始化+生命周期 |
| `src/dc_param.cpp` | `src/dc_param_hook.cpp` | 参数配置文件钩子注册 |
| `src/dc_cfg_check.cpp` | ↑ | self_param.xml变更检测+保存 |
| `src/dc_event.cpp` | `src/dc_event.cpp` | 事件队列 |
| `src/dc_signal_internal.h` | `src/dc_signal_internal.h` | 内部共享声明 |
### 11.11 新旧工程差异对比
| 维度 | RTU 原工程 v1 | RTU 原工程 v2 | 新工程 libdatacenter |
|------|-------------|-------------|-------------------|
| 接口语言 | C++ (std::string) | 纯C (const char*) | 纯C (extern "C") |
| 哈希查找 | XXH128 multimap | XXH128 multimap | unordered_map + XXH3_128bits hasherO(1),复用 libmy_xxhash CBB |
| 参数文件 | tinyxml2 直接解析 | 同上 | 回调钩子解耦 |
| 异步执行 | 无 | 有_exec_async | 预留接口+钩子 |
| 回路阻断 | ✓ | ✓ | ✓ |
| module_id | std::string | const char* | const char* |
| 控制校验 | ✓ | ✓ | ✓ |
| SBO流程 | ✓ | ✓ | ✓ |
| 多区定值 | ✓ | ✓ | ✓ |
| 变更检测 | 脏标记+100ms | 同v1 | 同v1 |
| 调试命令 | cmd_dc | 无 | 预留 |
| 错误码 | -1/0 | enum dc_error_t | enum dc_error_t |
| 未实现 | — | — | 异步执行模型(预留)、tinyxml2绑定(钩子替代) |

View File

@ -17,36 +17,50 @@
| libfunc | [API-libfunc.md](public/libfunc/API-libfunc.md) | 纯 C | 65 个基础工具函数 |
| libmd5 | [API-libmd5.md](public/libmd5/API-libmd5.md) | 纯 C | MD5 消息摘要 (RFC 1321) |
| libtask | [API-libtask.md](public/libtask/API-libtask.md) | 纯 C | 定时器 + 事件 + 消息队列 |
| libdatacenter | [API-libdatacenter.md](public/libdatacenter/API-libdatacenter.md) | C 接口+C++ 内部 | 信号数据中心5种信号+事件队列) |
| libcJSON | [API-libcJSON.md](public/libcJSON/API-libcJSON.md) | 纯 C (开源库) | JSON 解析/生成 |
| libmy_xxhash | [API-libmy_xxhash.md](public/libmy_xxhash/API-libmy_xxhash.md) | 纯 C (开源库) | xxHash 快速哈希 |
| libxml | [API-libxml.md](public/libxml/API-libxml.md) | C 接口+C++ 内部 | XML 解析C接口包裹 tinyxml2 |
| libcmd | [API-libcmd.md](public/libcmd/API-libcmd.md) | C 接口+C++ 内部 | 命令注册/补全 + 内置 linenoise |
### 模块依赖关系图
```
┌──────────┐
│ myBase.h │ (颜色/大小端/类型常量)
└────┬─────┘
┌──────────────┼──────────────┐
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌──────────┐
│ liblist │ │ libfunc │ │ libmd5 │
│ (链表) │ │ (65函数)│ │ (MD5) │
└────┬────┘ └────┬────┘ └──────────┘
│ │
▼ ▼
┌─────────────────────────┐
│ liblog │ (异步日志,依赖
│ (消息池+批量+文件轮转) │ liblist + libfunc)
└─────────────────────────┘
┌──────────┐
│ myBase.h │ (颜色/大小端/类型常量)
└────┬─────┘
┌──────────────┼──────────────┐
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌──────────┐
│ liblist │ │ libfunc │ │ libmd5 │
│ (链表) │ │ (65函数)│ │ (MD5) │
└────┬────┘ └────┬────┘ └──────────┘
│ │
▼ ▼
┌─────────────────────────┐
│ liblog │ (异步日志)
│ (消息池+批量+文件轮转) │
└─────────────────────────┘
┌──────────┐ ┌──────────────┐
│ libcJSON │ │ libmy_xxhash │ (开源库,直接使用)
└──────────┘ └──────────────┘
┌────────────────────────────────┐
│ libtask │ (事件/定时器/消息队列)
│ (timerfd + epoll + pthread) │
└────────────────────────────────┘
┌──────────┐ ┌──────────────┐
│ libcJSON │ │ libmy_xxhash │ (开源库)
└──────────┘ └──────┬───────┘
┌─────────────────────┼─────────────────────┐
│ ▼ │
│ ┌──────────┐ ┌──────────┐ ┌─────────┐ │
│ │ libtask │ │ libxml │ │ libcmd │ │ (P2库提前实现
│ │ (事件/ │ │ (C接口+ │ │ (命令 │ │ 供datacenter
│ │ 定时器) │ │ tinyxml2)│ │ 框架) │ │ 依赖)
│ └──────────┘ └────┬─────┘ └────┬────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────────────────┐ │
│ │ libdatacenter │ │
│ │ (信号数据中心 5种信号类型) │ │
│ │ 依赖: libxml + libcmd │ │
│ │ + libmy_xxhash │ │
└──────────┴─────────────────────────────┘
```
### 构建与编译

View File

@ -1,4 +1,4 @@
SUBDIRS := ./liblist ./libfunc ./liblog ./libmd5 ./libcJSON ./libmy_xxhash ./libtask
SUBDIRS := ./liblist ./libfunc ./liblog ./libmd5 ./libcJSON ./libmy_xxhash ./libtask ./libxml ./libcmd ./libdatacenter
define make_subdir
@for d in $(SUBDIRS); do [ -f "$$d/makefile" ] && (cd "$$d" && make -f makefile $1) || true; done
endef