静态库链接为何强制顺序?能否实现通用链接方式?
静态库链接顺序的深层原因与解决方案
为什么静态库必须卡着特定顺序链接?
这事儿得从GNU链接器(就是g++默认用的ld)的按需链接逻辑说起:
- 链接器处理输入文件是从左到右按顺序来的。
- 静态库(
.a文件)本质就是一堆.o目标文件打包成的归档包。链接器碰到静态库时,只会盯着当前有没有没解决的符号引用,只提取能搞定这些符号的.o文件——如果这时候还没任何未解决的符号,链接器直接就跳过整个静态库了,半点儿内容都不会拿。 - 拿你给的错误例子说:
g++ -ldynamic -lstatic src.cxx:链接器先处理动态库-ldynamic,接着碰-lstatic,这时候还没编译src.cxx,根本没未解决的符号,所以-lstatic直接被忽略。等后面编译src.cxx出来一堆未定义符号,链接器才不会回头去翻之前跳过的-lstatic,自然报错。g++ -lstatic src.cxx -ldynamic:同理,先处理-lstatic时没符号要解决,直接跳过,后面src.cxx需要的符号在-lstatic里,但链接器已经过了那一步,找不到就炸了。
- 而成功的命令比如
g++ src.cxx -ldynamic -lstatic:先编译src.cxx,产生了一堆未解决的符号,然后链接器顺着去-ldynamic和-lstatic里找能填坑的内容,自然就成了。
为啥动态库就没这顺序毛病?
动态库(.so文件)的链接逻辑跟静态库完全不是一回事:
- 链接动态库时,链接器不会像处理静态库那样“按需抠文件”,而是直接记下所有需要的动态符号依赖,不管当下有没有未解决的符号。
- 这些依赖会写到最终的可执行文件里,真正的符号解析要等到程序运行的时候(或者加载阶段,看具体链接方式)才做。所以动态库的顺序根本不影响链接阶段的成功——只要你把该加的库都加上就行。
能不能整个-ls(静态库)、-ld(动态库)这种标识来实现随便顺序链接?
其实不用搞新标识,GNU链接器早就给了选项能打破顺序限制:
--start-group+--end-group:把需要循环搜索的库夹在这俩选项中间,链接器会反复搜组里的库,直到所有未解决的符号都搞定,或者确定搞不定为止。比如你可以这么写:
这样不管你把库的顺序怎么调,链接器都会来回检查这几个库,直到符号都解析完。不过要注意:这么干会增加链接时间,因为链接器要反复遍历库,适合那些库之间互相依赖的场景。g++ -Wl,--start-group -ldynamic -lstatic -Wl,--end-group src.cxx--whole-archive:这个选项会强制链接器把整个静态库的所有.o文件都链接进去,而不是按需提取。用法是:
但这么做会让可执行文件变大,因为会把不需要的代码也塞进去,所以只在特殊情况用。g++ -Wl,--whole-archive -lstatic -Wl,--no-whole-archive -ldynamic src.cxx
总的来说:静态库的顺序问题是链接器“按需、单向走”的处理逻辑导致的,动态库因为把依赖解析延迟到运行时所以没这问题;现有的链接器选项已经能实现不卡顺序的链接,完全不用新增啥标识。
内容的提问来源于stack exchange,提问作者Sitesh
相关产品推荐
相关产品推荐

