| Files | Last commit | Last update |
|---|---|---|
| 4 months ago | ||
| 4 months ago | ||
| 4 months ago | ||
| 4 months ago | ||
| 4 months ago | ||
| 2 months ago | ||
| 4 months ago |
/*
- Copyright (c) 2024 Huawei Technologies Co., Ltd.
- openUBMC is licensed under Mulan PSL v2.
- You can use this software according to the terms and conditions of the Mulan PSL v2.
- You may obtain a copy of Mulan PSL v2 at:
-
http://license.coscl.org.cn/MulanPSL2 - THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
- EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
- MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
- See the Mulan PSL v2 for more details. */
简化模块系统示例
设计重点
基于您澄清的实际使用场景,重新调整了模块系统的设计重点:
🎯 核心定位
- C++侧: 实现模块,导出功能给 expr2 脚本使用
- expr2脚本侧: 使用 import/require 语法加载和使用模块
- 重点: 简化C++模块的实现和导出体验
🔧 技术特点
- 极简语法: 只需两个宏即可定义模块
- 导出为主: 重点是将C++功能导出给脚本使用
- 自动注册: 模块会自动注册到模块管理器
- 脚本友好: 为expr2脚本引擎优化的接口设计
使用方法
1. 定义模块(头文件)
#include <mc/module.h>
// 定义模块
MC_MODULE(devices)
namespace mc::devices {
// 定义您的类和函数
class sensor {
public:
void set_name(const std::string& name);
const std::string& get_name() const;
double read();
// ...
};
}
// 导出给脚本使用
MC_EXPORT((mc::devices::sensor, "Sensor"),
((set_name, "setName"))
((get_name, "getName"))
((read, "read")))
2. 实现模块(源文件)
#include "devices.h"
// 实现模块反射工厂
MC_REGISTER_BUILTIN_MODULE(devices)
namespace mc::devices {
// 实现您的类和函数
void sensor::set_name(const std::string& name) {
m_name = name;
}
// ...
}
3. 在expr2脚本中使用(未来)
// 类似于 Lua 的 require
const devices = require("devices");
// 创建对象
const sensor = new devices.Sensor();
sensor.setName("温度传感器");
const value = sensor.read();
项目结构
simple_module/
├── simple_devices.h # 模块接口定义
├── simple_devices.cpp # 模块实现
├── main.cpp # C++侧演示程序
├── README.md # 说明文档
└── meson.build # 构建配置
构建说明
# 在项目根目录
cd builddir
meson compile simple_devices_example
./examples/simple_module/simple_devices_example
设计优势
对于C++开发者
- 简洁: 只需两个宏即可定义模块
- 清晰: 明确的导出语义,知道哪些功能会被脚本使用
- 灵活: 可以同时在C++和脚本中使用
对于脚本开发者
- 一致: 所有模块都通过相同的require/import方式加载
- 完整: 导出的功能包含完整的类型信息和方法
- 安全: 通过反射系统确保类型安全
对于架构设计
- 隔离: 每个模块有独立的反射工厂
- 可扩展: 支持动态模块加载(预留)
- 高效: 自动缓存和延迟加载
后续计划
- 集成expr2: 在expr2脚本引擎中实现真正的require/import语法
- 动态加载: 支持.so/.dll动态模块加载
- 工具链: 提供模块生成和管理工具
- 文档完善: 提供完整的开发指南和API文档
总结
这个设计真正实现了"C++实现,脚本使用"的目标,让C++开发者可以轻松地将功能导出给脚本系统使用,同时保持了架构的清晰性和可扩展性。
主要改进:
- ✅ 简化了C++侧的模块定义语法
- ✅ 突出了导出功能的核心作用
- ✅ 为expr2脚本引擎预留了完整的接口
- ✅ 移除了不必要的C++侧复杂功能
这个设计更符合实际的使用场景和需求!
模块系统测试
本示例演示了 libmcpp 模块系统的完整功能,包括模块加载、使用、卸载以及重新加载。
测试内容
1-5. 基础模块测试
包含了四种不同模式的模块加载测试:
- 标准模块模式 (
mc.devices->modules/mc/devices.so) - 标准模块模式 (
mc.network->modules/mc/network.so) - init.so 模式 (
mc.protocol->modules/mc/protocol/init.so) - 深层路径模式 (
mc.test.database->modules/mc/test/database.so)
6. 模块两阶段卸载机制验证 ⭐
这是我们新增的重要功能,用于验证模块系统的两阶段卸载机制:
什么是两阶段卸载?
模块系统采用智能指针管理,卸载分为两个阶段:
-
第一阶段:逻辑卸载 - 调用
module_manager.unload()- 仅从模块管理器中移除模块引用
- 动态库仍在内存中,持有
module_ptr的代码仍可使用
-
第二阶段:物理卸载 - 释放所有
module_ptr引用- 当最后一个
module_ptr被销毁时 - 动态库才真正从内存中卸载
- 当最后一个
验证机制
我们在测试模块中添加了 卸载检测器:
// 在 devices/module.cpp 和 network/module.cpp 中
class module_unload_detector {
public:
module_unload_detector() {
// 模块加载时打印
std::cout << "[DEVICES MODULE] 模块加载 #" << ++s_load_count << std::endl;
}
~module_unload_detector() {
// 动态库真正卸载时打印
std::cout << "[DEVICES MODULE] 动态库真正卸载!" << std::endl;
}
};
// 全局对象,当动态库卸载时析构函数会被调用
static module_unload_detector g_unload_detector;
测试流程
- 保存模块引用 - 获取并持有
module_ptr - 第一阶段卸载 - 调用
unload()但模块仍可用 - 第二阶段卸载 - 释放
module_ptr,观察卸载日志 - 重新加载验证 - 重新加载模块,验证真正的重新初始化
预期输出
运行测试时,您应该看到类似输出:
[DEVICES MODULE] 模块加载 #1 (地址: 0x...)
调用 module_manager.unload('mc.devices')...
模块管理器状态: 未加载
✓ 模块引用仍然可用: after_unload_test
✓ 验证成功:第一阶段卸载后,持有引用的模块仍可使用
释放 devices_module_ref...
注意观察控制台输出,应该看到 '[DEVICES MODULE] 动态库真正卸载!' 消息
[DEVICES MODULE] 动态库真正卸载! 地址: 0x...
重新加载 devices 模块...
[DEVICES MODULE] 模块加载 #2 (地址: 0x...)
验证要点
✅ 逻辑卸载验证 - unload() 后模块管理器认为模块已卸载,但持有引用的代码仍可使用
✅ 物理卸载验证 - 释放所有引用后,观察到析构函数被调用
✅ 重新加载验证 - 重新加载后获得新的模块实例
✅ 控制台输出验证 - 通过控制台输出确认真正的重新初始化
实际意义
这种两阶段卸载机制确保了:
- 安全性 - 不会意外卸载仍在使用中的模块
- 灵活性 - 支持热更新场景(先加载新版本,再卸载旧版本)
- 一致性 - 引用计数自动管理模块生命周期
这是现代模块系统的标准设计模式,类似于 shared_ptr 的工作原理。
运行测试
cd builddir
meson compile
./examples/module_test_example
注意观察控制台输出中的模块加载/卸载消息,这些是验证两阶段卸载机制的关键信息。