编译时链接libxxx.so需用-L指定库路径、-l指定库名(省略lib前缀和.so后缀),C++调用C库须用extern "C"包裹头文件以防符号修饰导致undefined reference。

编译时链接 libxxx.so 需要 -l 和 -L
GCC 生成的 .so(比如 libmathutil.so)本质是符合 ELF 标准的共享对象,C++ 项目完全能用,前提是符号可见、ABI 兼容、调用约定一致。
关键不是“能不能”,而是怎么让 g++ 在链接阶段找到它:
-
-L/path/to/libs:告诉链接器去哪找库文件(注意不是头文件路径) -
-lmathutil:链接名为libmathutil.so的库(lib前缀和.so后缀必须省略) - 头文件仍需
#include "mathutil.h",且-I/path/to/headers不能少 - 如果库在当前目录,写
-L.;但生产环境建议用绝对路径或标准路径(如/usr/local/lib)
C 函数在 C++ 里调用要加 extern "C"
这是最容易翻车的地方。GCC 编译的 .so 通常导出的是 C 风格符号(无 name mangling),而 C++ 默认按 C++ 方式链接——函数名被修饰后,g++ 找不到原始符号。
解决方法只有一种:在 C++ 代码中显式声明为 C 链接:
立即学习“C++免费学习笔记(深入)”;
#ifdef __cplusplus
extern "C" {
#endif
#include "mathutil.h"
#ifdef __cplusplus
}
#endif
或者更直接,在调用处包一层:
extern "C" {
#include "mathutil.h"
}
不加这个,编译可能通过,但链接时报 undefined reference to 'add' —— 因为实际符号可能是 _Z3addii。
运行时找不到 libxxx.so 怎么办
链接成功 ≠ 运行成功。Linux 下报错 error while loading shared libraries: libxxx.so: cannot open shared object file 是典型运行时问题。
有三种可靠解法,按优先级排序:
- 把库复制到系统路径(如
/usr/local/lib),再执行sudo ldconfig刷新缓存 - 临时设置
LD_LIBRARY_PATH:export LD_LIBRARY_PATH=/path/to/libs:$LD_LIBRARY_PATH,再运行程序 - 编译时硬编码 rpath:
g++ main.cpp -L. -lmathutil -Wl,-rpath,'$ORIGIN'($ORIGIN表示可执行文件所在目录)
最后一种最干净,避免污染环境变量,也适合打包分发。
用 dlopen 动态加载 GCC 的 .so 没问题
如果你不想在编译期绑定库,而是运行时决定是否加载(比如插件机制),dlopen 完全支持 GCC 生成的 .so。
注意三点:
- 必须链接
-ldl:g++ main.cpp -ldl - 函数指针类型要匹配,例如
typedef int (*add_func)(int, int); - 符号名必须是 C 风格的——也就是你用
nm -D libmathutil.so能看到的裸名(如add),不是 C++ mangling 后的名字
如果库是纯 C 写的,这点天然满足;如果是 C++ 源码但用了 extern "C" 导出,也 OK。
真正卡住人的往往不是技术步骤,而是符号可见性、rpath 设置、以及忘记 extern "C" 包裹头文件——这三个点漏掉任意一个,都会让程序在某个环节静默失败。


















