g++编译C++动态库必须加-fPIC和-shared:-fPIC生成位置无关代码,-shared指定构建共享对象;缺一不可,否则报relocation错误或生成非动态库文件。

g++ 编译 C++ 源文件为动态库的关键命令
直接用 g++ 编译 C++ 文件生成动态库,必须加 -fPIC 和 -shared,缺一不可。不加 -fPIC 会导致链接时报错 relocation R_X86_64_32 against `.rodata' can not be used when making a shared object;不加 -shared 则生成的是普通可执行目标文件,不是动态库。
典型流程分两步:
- 先用
g++ -c -fPIC xxx.cpp -o xxx.o把每个源文件编译成位置无关的目标文件 - 再用
g++ -shared xxx.o yyy.o -o libxxx.so合并生成动态库
注意:不能跳过 -c 直接 g++ -fPIC -shared xxx.cpp -o libxxx.so —— 虽然语法上能过,但若源文件里有 main() 或全局构造函数,会触发链接器拒绝(undefined reference to `main' 或初始化冲突)。
头文件和符号导出要注意什么
C++ 动态库默认不导出所有符号,类、模板、内联函数容易“消失”,运行时调用会报 undefined symbol。这不是链接阶段的问题,而是符号未被暴露。
常见做法是显式控制可见性:
- 编译时加
-fvisibility=hidden(推荐),再在要导出的类/函数前加__attribute__((visibility("default"))) - 或统一加
-fvisibility=default(不推荐,体积大、符号污染风险高) - 头文件中避免直接定义模板实现(.h 中只声明,.tpp 或 .cpp 中实现),否则实例化失败
验证导出符号:用 nm -D libxxx.so | c++filt 查看实际导出的 C++ 符号名是否符合预期。
链接时找不到 libxxx.so 怎么办
即使 g++ main.cpp -L. -lxxx -o app 写对了,运行时仍可能报 error while loading shared libraries: libxxx.so: cannot open shared object file。这是因为动态链接器(ld-linux.so)在运行时并不查 -L 路径。
解决方法有三种,按优先级排序:
- 运行前临时设置:
LD_LIBRARY_PATH=. ./app(仅测试用,别写进部署脚本) - 编译时嵌入运行时库路径:
g++ main.cpp -L. -lxxx -Wl,-rpath,'$ORIGIN' -o app($ORIGIN表示可执行文件所在目录,最稳妥) - 系统级注册:把
.so放到/usr/local/lib,再运行sudo ldconfig(需 root,适合安装包)
别依赖 /etc/ld.so.conf.d/ 自建配置后忘记 ldconfig —— 这是线上环境最常漏掉的一步。
为什么用 g++ 而不是 gcc
哪怕源码全是 C 风格,只要用了 .cpp 后缀、或链接了 C++ 标准库(如 std::string, std::vector)、或含 extern "C" 块,就必须用 g++。因为:
-
gcc默认不链接libstdc++,会报undefined reference to `operator new(unsigned long)' -
g++自动带-lstdc++,且正确处理 C++ ABI(如 name mangling、异常栈展开) - 混用
gcc编译 +g++链接,或反过来,极大概率在std::类型析构时崩溃
一个简单判断:如果 g++ -shared xxx.o -o libxxx.so 成功,而 gcc -shared xxx.o -o libxxx.so 报一堆 undefined reference to `__cxa_atexit',那就是该换编译器了。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











