动态C库加载系统允许解释器在运行时直接加载C库中的符号,并将其封装为内置函数。这种方式避免了代码生成,提供了更灵活和高效的C库集成方案。
- 动态符号加载: 使用
dlopen/dlsym直接加载C库中的函数符号 - 类型安全转换: 自动处理C类型与解释器类型之间的转换
- 配置驱动: 通过JSON配置文件定义要加载的函数
- 插件集成: 完全兼容现有的插件系统
- 错误处理: 完善的错误处理和日志记录
┌─────────────────────────────────────────────────────────────┐
│ DynamicLibraryPlugin │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ DynamicLibraryLoader ││
│ │ ┌─────────────────┐ ┌─────────────────────────────────┐││
│ │ │ Symbol Loader │ │ Function Wrapper │││
│ │ │ (dlopen/dlsym) │ │ (Type Conversion) │││
│ │ └─────────────────┘ └─────────────────────────────────┘││
│ └─────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────┐
│ ScopeManager │
│ (Function │
│ Registration) │
└─────────────────┘
#include "interpreter/plugins/dynamic_library_plugin.h"
// 从配置文件加载
auto plugin = std::make_unique<DynamicLibraryPlugin>("configs/math_library.json");
if (plugin->isValid()) {
// 注册函数到作用域管理器
plugin->getLoader()->registerFunctions(scopeManager);
}// 直接指定库路径和名称
auto plugin = std::make_unique<DynamicLibraryPlugin>("/usr/lib/libm.so", "math");
if (plugin->isValid()) {
plugin->getLoader()->registerFunctions(scopeManager);
}{
"library_name": "math",
"library_path": "/usr/lib/x86_64-linux-gnu/libm.so",
"description": "标准C数学库的动态加载插件",
"header_files": ["math.h"],
"functions": [
{
"name": "sin",
"c_signature": "double sin(double x)",
"description": "计算正弦值",
"parameters": [
{
"name": "x",
"type": "double",
"is_pointer": false,
"is_const": false,
"description": "角度值(弧度)"
}
],
"return_type": "double",
"is_void_return": false
}
],
"type_mappings": {
"double": "Double",
"int": "Integer",
"char*": "String",
"void": "null"
}
}| C类型 | 解释器类型 | 说明 |
|---|---|---|
double |
Double |
双精度浮点数 |
int |
Integer |
整数 |
size_t |
Integer |
大小类型 |
char* |
String |
字符串指针 |
const char* |
String |
常量字符串指针 |
void |
null |
空类型 |
系统自动为每个C函数创建包装器,处理以下任务:
- 参数提取: 从
Scope中提取参数并转换为C类型 - 函数调用: 调用实际的C函数
- 返回值转换: 将C函数返回值转换为解释器类型
- 错误处理: 捕获异常并记录日志
// 加载数学库
auto math_plugin = std::make_unique<DynamicLibraryPlugin>("configs/math_library.json");
// 测试sin函数
auto scope = std::make_unique<Scope>();
scope->setArgument("x", new Double(1.0));
auto sin_func = scopeManager.getFunction("sin");
auto result = sin_func->call(scope.get());
std::cout << "sin(1.0) = " << dynamic_cast<Double*>(result)->getValue() << std::endl;// 加载字符串库
auto string_plugin = std::make_unique<DynamicLibraryPlugin>("configs/string_library.json");
// 测试strlen函数
auto scope = std::make_unique<Scope>();
scope->setArgument("str", new String("Hello, World!"));
auto strlen_func = scopeManager.getFunction("strlen");
auto result = strlen_func->call(scope.get());
std::cout << "strlen = " << dynamic_cast<Integer*>(result)->getValue() << std::endl;- 无需代码生成: 直接加载C库符号,避免生成中间代码
- 运行时灵活性: 可以在运行时动态加载不同的库
- 类型安全: 自动处理类型转换,减少错误
- 配置驱动: 通过配置文件轻松管理要加载的函数
- 插件兼容: 完全兼容现有的插件系统
- 性能优化: 直接调用C函数,性能接近原生调用
- 类型支持: 目前主要支持基本类型,复杂类型需要扩展
- 函数签名: 需要预先知道函数签名
- 平台依赖: 依赖
dlopen/dlsym,主要支持Unix-like系统 - 错误处理: C库函数的错误处理需要额外考虑
系统设计为可扩展的,可以轻松添加:
- 新的类型映射
- 更复杂的函数签名支持
- 自定义错误处理策略
- 函数调用缓存机制
- 多线程安全支持
动态库加载系统完全兼容现有的插件管理器和作用域系统:
// 在PluginManager中使用
PluginManager manager;
auto dynamic_plugin = std::make_unique<DynamicLibraryPlugin>("configs/math_library.json");
if (dynamic_plugin->isValid()) {
dynamic_plugin->getLoader()->registerFunctions(scopeManager);
}这为解释器提供了强大的C库集成能力,使得可以轻松利用现有的C库生态系统。