C++11 教学示例:动态加载共享库(.so)
·



1️⃣ 概述
在 Linux 系统中,C++ 程序可以通过共享库(.so 文件)实现代码复用。
我们可以用 dlopen()、dlsym() 等函数在运行时动态加载 .so,实现类似“插件”的机制。
2️⃣ 示例目标
我们将完成:
-
一个共享库
dbclient_mysql.so -
一个可执行文件
utestsym -
主程序动态加载
.so并调用其中的函数
3️⃣ 文件结构
project/
├── dbclient_mysql.cpp # 共享库源文件
└── utestsym.cpp # 主程序源文件
4️⃣ 编写共享库
dbclient_mysql.cpp
// dbclient_mysql.cpp
#include <iostream>
#include <string>
// 为了让函数名在 C++ 下不被 name mangling,必须加 extern "C"
extern "C" {
// 模拟数据库连接函数
int db_connect(const char* host, int port) {
std::cout << "[dbclient_mysql] Connecting to " << host
<< ":" << port << std::endl;
return 0; // 0 表示成功
}
// 模拟断开连接函数
void db_disconnect() {
std::cout << "[dbclient_mysql] Disconnected." << std::endl;
}
// 模拟版本查询函数
const char* db_version() {
return "mysql client 1.0";
}
} // extern "C"
编译共享库
g++ -std=c++11 -fPIC -shared -g -o dbclient_mysql.so dbclient_mysql.cpp
说明:
-
-fPIC:生成位置无关代码(共享库必须) -
-shared:输出为.so文件
5️⃣ 编写主程序
utestsym.cpp
// utestsym.cpp
#include <iostream>
#include <dlfcn.h> // 动态库操作接口
int main()
{
/* 1. 加载共享库
| 参数 | 符号解析时机 | 优点 | 缺点 |
| ----------- | ---------- | ----------- | ------------ |
| `RTLD_LAZY` | 第一次调用时 | 加载快,可延迟错误 | 调用时才报错,调试困难 |
| `RTLD_NOW` | dlopen 调用时 | 早期发现错误,调试方便 | 加载慢,可能浪费解析时间 |
*/
void *handle = dlopen("./dbclient_mysql.so", RTLD_NOW);
if (!handle)
{
std::cerr << "无法加载库: " << dlerror() << std::endl;
return 1;
}
dlerror(); // 清空之前的错误
// 2. 查找函数符号
typedef int (*db_connect_func)(const char *, int);
typedef void (*db_disconnect_func)();
typedef const char *(*db_version_func)();
db_connect_func db_connect = (db_connect_func)dlsym(handle, "db_connect");
db_disconnect_func db_disconnect = (db_disconnect_func)dlsym(handle, "db_disconnect");
db_version_func db_version = (db_version_func)dlsym(handle, "db_version");
const char *err = dlerror();
if (err)
{
std::cerr << "查找符号失败: " << err << std::endl;
dlclose(handle);
return 1;
}
// 3. 调用库中函数
std::cout << "版本号: " << db_version() << std::endl;
db_connect("localhost", 3306);
db_disconnect();
// 4. 卸载库
dlclose(handle);
return 0;
}
编译主程序
g++ -std=c++11 -g -o utestsym utestsym.cpp -ldl
⚠️ 注意:
-ldl必须加,用于链接动态加载库。
6️⃣ 运行程序
./utestsym
输出结果:

7️⃣ 调试与补充
查看 .so 导出的符号
nm -D dbclient_mysql.so | grep db_
结果示例:

如果库不在当前目录
可以设置环境变量:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
✅ 总结
| 步骤 | 内容 | 命令 |
|---|---|---|
| 1️⃣ | 编译共享库 | g++ -std=c++11 -fPIC -shared -g -o dbclient_mysql.so dbclient_mysql.cpp |
| 2️⃣ | 编译主程序 | g++ -std=c++11 -g -o utestsym utestsym.cpp -ldl |
| 3️⃣ | 运行 | ./utestsym |
💬 学习要点
-
共享库函数需使用
extern "C"导出。 -
dlopen()加载.so;dlsym()查找函数;dlclose()卸载。 -
-ldl是链接动态加载库的必需参数。 -
此机制可用于插件系统、数据库驱动加载等模块化场景。


更多推荐

所有评论(0)