最小命令是g++ -shared -fpic -o libmath.so math.cpp,必须加-fpic生成位置无关代码,否则链接失败报relocation错误。

Linux 下用 g++ 编译 .so 文件的最小命令是什么
直接能跑起来的命令就一条,但漏掉 -fPIC 就会链接失败:
g++ -shared -fPIC -o libmath.so math.cpp。关键不是“共享”,而是位置无关代码——
libmath.so 被加载到任意内存地址都得能运行,所以源码编译时必须加 -fPIC。不加的话,链接器报错类似 relocation R_X86_64_32 against `a local symbol' can not be used when making a shared object,本质是汇编指令里写了绝对地址。
常见错误现象:
- 只写
g++ -shared -o libmath.so math.cpp→ 链接失败 - 用
gcc替代g++编译含 C++ 类/异常的代码 → 运行时崩溃(缺少 C++ 运行时符号) - 头文件没加
extern "C"导出函数 → C 程序调用时找不到符号(C++ 名字修饰导致)
Windows 上生成 .dll 要注意哪些导出符号问题
Windows 不靠文件后缀识别导出,靠显式声明。最稳妥的是在函数前加 __declspec(dllexport),比如:
extern "C" __declspec(dllexport) int add(int a, int b) { return a + b; }。不加的话,默认所有符号都不导出,dumpbin /exports mylib.dll 会显示空列表。
使用场景和坑点:
立即学习“C++免费学习笔记(深入)”;
- 如果用
.def文件控制导出,必须确保函数名跟编译后一致(C++ 类成员函数基本没法用.def导出) -
extern "C"必须包住__declspec(dllexport),否则 C++ 名字修饰仍存在,C 程序或 Python 的ctypes找不到add,只能看到类似?add@@YAHHH@Z - 动态库依赖的 STL 或 CRT,发布时得确认目标机器有对应版本,否则
LoadLibrary返回 NULL,GetLastError()是 126(模块未找到)
怎么让主程序在运行时正确找到并加载动态库
路径没配对,dlopen 或 LoadLibrary 就会失败,不是代码问题,是环境问题。
Linux 下优先级顺序(从高到低):
-
LD_LIBRARY_PATH环境变量里列出的路径(临时调试可用,但别放生产) -
/etc/ld.so.cache里的缓存路径(改完/etc/ld.so.conf.d/*.conf后要运行sudo ldconfig) -
/usr/lib和/lib(系统级,普通用户写不了)
Windows 下只查当前目录、PATH 环境变量、系统目录(System32 等),不会查 DLL 自身所在目录——除非用 SetDllDirectory 显式设置,或者把 DLL 放进 EXE 同目录(最简单有效)。
C++ 动态库里定义全局对象或静态变量安全吗
不安全,尤其跨平台时初始化顺序不可控。比如一个 std::string 全局变量,在 main() 开始前构造,但它的分配器可能还没初始化好;DLL 卸载时析构顺序也未必按构造逆序来。
更麻烦的是跨 DLL 边界:
- 两个动态库都 static 链接了 libc++,各自有一份
std::cout实例 → 输出可能乱序或丢失 - 用
new在 A.dll 分配内存,传指针给 B.exe 释放 → Windows 上大概率崩(堆不共享) - RTTI 和异常处理表在多个模块间可能冲突,特别是混用不同编译器或标准库版本
真正稳定的做法:把资源生命周期完全收归一个模块管理,对外只暴露纯 C 接口(init()/destroy()),内部用单例+原子标志控制初始化,避免任何全局构造函数。










