为什么链接库的顺序有时会导致GCC错误?


#1楼

一个让我震惊的提示:如果您以“ gcc”或“ g ++”的形式调用链接器,则使用“ --start-group”和“ --end-group”不会将这些选项传递给链接器-也不会标记错误。 如果您有错误的库顺序,它将导致带有未定义符号的链接失败。

您需要将它们写为“ -Wl,-start-group”等,以告诉GCC将参数传递给链接器。


#2楼

另一种选择是两次指定库列表:

gcc prog.o libA.a libB.a libA.a libB.a -o prog.x

这样做不必麻烦正确的顺序,因为引用将在第二个块中得到解析。


#3楼

如果在链接器标志中添加-Wl,--start-group ,则不在乎它们的顺序或是否存在循环依赖性。

在Qt上,这意味着添加:

QMAKE_LFLAGS += -Wl,--start-group

节省了很多时间,而且似乎并没有减慢链接的速度(总之比编译要少得多的时间)。


#4楼

GNU ld链接器是所谓的智能链接器。 它将跟踪先前的静态库使用的功能,并永久地将其查找表中未使用的那些功能扔掉。 结果是,如果您过早地链接静态库,则该静态库中的函数以后在链接行上将不再对静态库可用。

典型的UNIX链接器从左到右起作用,因此将所有依赖库放在左边,将满足这些依赖关系的库放在链接行的右边。 您可能会发现某些库依赖于其他库,而同时其他库也依赖于它们。 这是复杂的地方。 当涉及循环引用时,请修复您的代码!


#5楼

(请参阅此答案的历史记录以获得更详尽的文字,但我现在认为读者更容易看到真实的命令行)。


以下所有命令共享的公用文件

$ cat a.cpp
extern int a;
int main() {return a;
}$ cat b.cpp
extern int b;
int a = b;$ cat d.cpp
int b;

链接到静态库

$ g++ -c b.cpp -o b.o
$ ar cr libb.a b.o
$ g++ -c d.cpp -o d.o
$ ar cr libd.a d.o$ g++ -L. -ld -lb a.cpp # wrong order
$ g++ -L. -lb -ld a.cpp # wrong order
$ g++ a.cpp -L. -ld -lb # wrong order
$ g++ a.cpp -L. -lb -ld # right order

链接器从左到右搜索,并记录未解析的符号。 如果库解析符号,它将使用该库的目标文件来解析符号(在这种情况下,它们来自libb.a)。

静态库彼此之间的依赖关系相同-必须首先使用需要符号的库,然后是解析符号的库。

如果静态库依赖于另一个库,但是另一个库又依赖于前一个库,则存在一个循环。 您可以通过-(-)包围循环依赖库,例如-( -la -lb -)来解决此问题(您可能需要转义括号,例如-\\(-\\) )。 链接器然后多次搜索那些包含的lib,以确保解决循环依赖性。 另外,您可以指定多个库,因此每个库都位于另一个库之前: -la -lb -la

链接到动态库

$ export LD_LIBRARY_PATH=. # not needed if libs go to /usr/lib etc
$ g++ -fpic -shared d.cpp -o libd.so
$ g++ -fpic -shared b.cpp -L. -ld -o libb.so # specifies its dependency!$ g++ -L. -lb a.cpp # wrong order (works on some distributions)
$ g++ -Wl,--as-needed -L. -lb a.cpp # wrong order
$ g++ -Wl,--as-needed a.cpp -L. -lb # right order

这里是相同的-库必须遵循程序的目标文件。 与静态库相比,这里的区别在于您不必在意彼此之间的依赖关系,因为动态库本身会解决它们的依赖关系

某些最新发行版显然默认使用--as-needed链接程序标志,该标志强制程序的目标文件位于动态库之前。 如果传递了该标志,则链接器将不会链接到可执行文件实际上并不需要的库(并且从左到右检测到此链接)。 我最近的archlinux发行版默认情况下不使用此标志,因此它没有给出未遵循正确顺序的错误。

创建前者时,忽略b.sod.so的依赖关系是不正确的。 链接a时,将要求您指定库,但是a并不需要整数b本身,因此不应考虑b自身的依赖关系。

如果您错过为libb.so指定依赖项,这是一个示例。

$ export LD_LIBRARY_PATH=. # not needed if libs go to /usr/lib etc
$ g++ -fpic -shared d.cpp -o libd.so
$ g++ -fpic -shared b.cpp -o libb.so # wrong (but links)$ g++ -L. -lb a.cpp # wrong, as above
$ g++ -Wl,--as-needed -L. -lb a.cpp # wrong, as above
$ g++ a.cpp -L. -lb # wrong, missing libd.so
$ g++ a.cpp -L. -ld -lb # wrong order (works on some distributions)
$ g++ -Wl,--as-needed a.cpp -L. -ld -lb # wrong order (like static libs)
$ g++ -Wl,--as-needed a.cpp -L. -lb -ld # "right"

如果现在查看二进制文件具有哪些依赖关系,您会注意到二进制文件本身也取决于libd ,而不仅取决于libb 。 如果libb以后依赖于另一个库,则需要重新链接该二进制文件(如果您这样做)。 而且,如果其他人在运行时使用dlopen加载了libb (考虑动态加载插件),则调用也会失败。 因此, "right"确实也应该是wrong


#6楼

我已经看到很多了,我们的某些模块链接了超过100个我们的代码库以及系统库和第三方库。

根据不同的链接器HP / Intel / GCC / SUN / SGI / IBM / etc,您可以获得未解析的函数/变量等,在某些平台上,您必须列出库两次。

在大多数情况下,我们使用库,核心,平台,不同抽象层的结构化层次结构,但是对于某些系统,您仍然必须按照link命令的顺序进行操作。

一旦找到了解决方案文档,那么下一个开发人员就不必再次解决它。

我的老讲师曾经说过“ 高凝聚力和低耦合 ”,今天仍然如此。


#7楼

这是一个示例,用于阐明涉及静态库时GCC的工作方式。 因此,假设我们有以下情形:

  • myprog.o包含main()函数,取决于libmysqlclient
  • libmysqlclient静态的,为了示例(您当然更喜欢共享库,因为libmysqlclient很大); 在/usr/local/lib ; 并依赖于libz东西
  • libz (动态)

我们该如何链接? (注意:使用gcc 4.3.4在Cygwin上编译的示例)

gcc -L/usr/local/lib -lmysqlclient myprog.o
# undefined reference to `_mysql_init'
# myprog depends on libmysqlclient
# so myprog has to come earlier on the command linegcc myprog.o -L/usr/local/lib -lmysqlclient
# undefined reference to `_uncompress'
# we have to link with libz, toogcc myprog.o -lz -L/usr/local/lib -lmysqlclient
# undefined reference to `_uncompress'
# libz is needed by libmysqlclient
# so it has to appear *after* it on the command linegcc myprog.o -L/usr/local/lib -lmysqlclient -lz
# this works

#8楼

您可以使用-Xlinker选项。

g++ -o foobar  -Xlinker -start-group  -Xlinker libA.a -Xlinker libB.a -Xlinker libC.a  -Xlinker -end-group

ALMOST等于

g++ -o foobar  -Xlinker -start-group  -Xlinker libC.a -Xlinker libB.a -Xlinker libA.a  -Xlinker -end-group

小心点!

  1. 组内的顺序很重要! 这是一个示例:调试库具有调试例程,但非调试库具有相同的弱版本。 您必须将调试库FIRST放入组中,否则您将解析为非调试版本。
  2. 您需要在组列表中的每个库之前加上-Xlinker

#9楼

至少在某些平台上,链接顺序确实很重要。 我已经看到与库链接顺序错误的应用程序崩溃(错误的意思是A在B之前链接,但B取决于A)。

为什么链接库的顺序有时会导致GCC错误?相关推荐

  1. VS远程开发(远程调试)编译报错:对‘xxx’未定义的引用(设置库依赖顺序)(已解决)pthread(项目-->属性-->链接器-->输入-->库依赖项)

    如图在VS中对linux进行远程开发时,编译报错: 貌似是因为在代码中使用了pthread.h的函数,链接库依赖顺序出了问题,我在ubuntu里手动使用gcc main.c -lpthread -o ...

  2. [原]从一个链接错误探究GCC的链接库顺序

    作者:朱金灿 来源:http://blog.csdn.net/clever101 使用CodeBlocks10.05编一个小程序用到了png库和zlib库.我发现编译png静态库时,只需要指定zlib ...

  3. CMakeLists学习二、链接库搜索路径与ld

    CMakeLists学习二.链接库搜索路径与ld 前言 gcc的链接 gcc链接命令 ld搜索路径 ldconfig刷新动态库缓存 CMakeLists指定链接搜索路径 后记 前言 本文继续CMake ...

  4. Linux gcc 制作动/静态链接库

    gcc 静态链接库 以 math.c为例 gcc -c math.c ar rcs libmath.a math.o ar命令 将多个文件打包成一个备份文件 参数r:用来替换库中已有的目标文件,或加入 ...

  5. linux 静态编译多媒体框架,Go编译32位GNU静态链接库的方法

    Go链接库系统的难用可谓是人尽皆知,不同Go版本编译出来的不兼容,而且只支持GNU的,不能编译出Windows上的dll和lib. 本次有需求是将Go代码编译成32位GNU静态链接库. Go代码 编写 ...

  6. GCC编译、链接、运行时库查找顺序(最真实可信)

    参考了不少资料,其中最靠谱是这个:http://www.mingw.org/wiki/librarypathhowto 和http://www.kaizou.org/2015/01/linux-lib ...

  7. gcc/g++链接时.o文件及库的顺序问题

    折腾gcc/g++链接时.o文件及库的顺序问题 链接静态库的顺序问题 GCC 编译使用动态链接库和静态链接库--及先后顺序----及环境变量设置总结 交叉编译静态库的链接顺序 问题: 1.当lib1. ...

  8. linux下运行时链接库的路径顺序

    那么自制的库在没有指定运行时库的路径时,一般是不会找到你特定目录的,先来说说链接库的搜寻顺寻: 1.编译目标代码时指定的动态库搜索路径(指的是用-wl,rpath或-R选项而不是-L): exampl ...

  9. libcurl linux 静态链接库_GCC 程序编译的静态链接和动态链接

    转自:Mr_Bluyee 在链接阶段中,所有对应于源文件的 .o 文件."-l" 选项指定的库文件.无法识别的文件名(包括指定的.o目标文件和.a库文件)按命令行中的顺序传递给链接 ...

最新文章

  1. 将base64编码图片上传到七牛云
  2. 第14天学习Java的笔记(成员变量和局部变量)
  3. Kyma Application connection url
  4. vue实现HTML转PDF (已解决清晰、页边距、图片跨域导出等问题)
  5. 自定义相册、九宫格显示图片
  6. c语言中的数组二分法排序程序,#C语言#二分法查找有序数组
  7. Visual Studio 2017中的第一个Python项目
  8. iOS项目工程添加.a文件遇到的Dsymutil Error
  9. 计算机机房建设公司 武汉,武汉信息化机房建设企业
  10. set+线段树 Codeforces Round #305 (Div. 2) D. Mike and Feet
  11. 最新版本的NGUI插件NGUI Next-Gen UI
  12. 安卓开发小程序之美图秀秀
  13. ad怎么导入cad的外形尺寸_CAD文件导入AD09
  14. 财务模块的一些基础概念
  15. 1047: 对数表 Python
  16. 2020滑铁卢大学计算机科学学费,官宣!2020加拿大高校学费与涨幅~
  17. Chrome开发者工具,如何清除Cookies
  18. UE4地形使用卫星贴图
  19. AllenNLP—笔记—json
  20. 用keil怎么擦除_keil如何使用?图文教程告诉你keil怎么使用

热门文章

  1. Binder相关面试总结(一):为什么Android要采用Binder作为IPC机制?
  2. 监听者模式理解(Swing)
  3. PathComposePathEffectView 使用
  4. php session 过期,php session失效的原因
  5. eclipse的tomcat如何运行自动弹网页_如何在 3 天内零成本完成 AI 小程序开发
  6. 读取excel日期 c++_实例9:用Python自动生成Excel档每日出货清单
  7. python微信库wxpy_使用wxpy这个基于python实现的微信工具库的一些常见问题
  8. python支持中文吗_Python中使用中文
  9. ES6学习(五) -- 箭头函数
  10. Java面试题,深入理解final关键字