为何macOS创建C++共享库时出现依赖错误而Ubuntu无此问题
为何共享库构建在Ubuntu/RedHat可行,却在macOS/Cygwin报错?
问题场景
用户将原本可正常运行的单文件C++代码拆分到多个文件(func1在f1.cpp,func0/func2在f2.cpp,main在main.cpp)后,执行以下构建流程:
编译目标文件
g++ -c -pipe -std=c++11 -fPIC main.cpp g++ -c -pipe -std=c++11 -fPIC f1.cpp g++ -c -pipe -std=c++11 -fPIC f2.cpp
构建共享库
g++ -shared -o libx1.so f1.o g++ -shared -o libx2.so f2.o
生成可执行文件并运行
g++ main.o -L. -lx1 -lx2 -o exe export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ./exe
- 正常运行环境:RedHat(GCC 8.3.1)、Ubuntu(GCC 9.4.0)
- 报错环境:Cygwin(GCC 11.3.0)、macOS(GCC 11.2.0),报错信息为:
g++ -shared -o libx1.so f1.o undefined reference to func0(int) g++ -shared -o libx2.so f2.o undefined reference to func1(int)
根本原因
问题出在不同操作系统链接器对共享库未定义符号的默认处理逻辑差异:
- Linux(Ubuntu/RedHat):使用GNU链接器(ld),默认允许共享库中存在未定义符号。这些符号可以延迟到最终链接可执行文件,甚至运行时再完成解析。所以即便
libx1.so依赖libx2.so里的func0,libx2.so依赖libx1.so里的func1,构建共享库阶段不会报错,后续链接可执行文件时两个库的符号会互相补全。 - macOS:采用Mach-O二进制格式,配套的ld64链接器默认要求构建共享库时必须解析所有符号,不允许遗留未定义引用。
- Cygwin:模拟Windows的PE二进制格式规则,链接器同样默认要求共享库的符号完全解析,不能依赖其他共享库的符号来填补缺失。
GCC版本只是次要因素:Linux上即使升级到高版本GCC,链接器默认行为依然允许未定义符号;而macOS/Cygwin的严格规则是由操作系统的二进制格式决定的,和GCC版本关联不大。
解决方法
要在macOS/Cygwin上完成构建,需修改共享库构建命令,明确告知链接器允许未定义符号:
- macOS:添加
-undefined dynamic_lookup参数
g++ -shared -undefined dynamic_lookup -o libx1.so f1.o g++ -shared -undefined dynamic_lookup -o libx2.so f2.o
- Cygwin:添加
--enable-auto-import参数
g++ -shared --enable-auto-import -o libx1.so f1.o g++ -shared --enable-auto-import -o libx2.so f2.o
内容的提问来源于stack exchange,提问作者R71
相关产品推荐
相关产品推荐

