.a link or .o link in Makefile

 
最近在公司做项目,整个Makefile由我来完成,我的想法是每个模块做成一个.a库,最后链接成可执行程序,但是在最后链接却提示找不到符号表,
觉得很奇怪,明明已经编译进目标文件了,为啥这么奇怪,最近在网络上看到一个例子,收益匪浅,转载一下:
 
为一个比较大的程序写makefile,文件都编译通过了,可偏在链接的时候出问题了。简单地说,该程序有一个主文件main.cpp,以及文件A.cpp与文件B.cpp,main.cpp调用了A.cpp中定义的函数,A.cpp又调用了B.cpp中定义的函数,但main.cpp没有调用B.cpp中的函数。在编译的时候,首先把A.cpp的目标文件A.o打包为库libA.a,把B.cpp的目标文件B.o打包为库libB.a,把main.cpp编译成目标文件main.o,然后使用命令"g++ main.o -lB -lA -static -o xxx"以生成最终的可执行文件。编译器报错:在链接libA.o的时候,找不到A.cpp所调用的B.cpp中的函数符号。
折腾了好久,最后不过是把-lB与-lA的顺序调了一下,问题便解决了。在网上找到一篇文章,终于明白了到底是怎样一回事。

这个链接写得很完善:http://blog.csdn.net/soloist/archive/2005/09/30/493238.aspx

编译器编译源文件时会把源文件的全局符号(global symbol)分成强(strong)弱(weak)两类传给汇编器,而随后汇编器则将强弱信息编码并保存在目标文件的符号表中。那么何谓强弱呢?编译 器认为函数与初始化了的全局变量都是强符号,而未初始化的全局变量则成了弱符号

有了强弱符号的概念,链接器(Unix平台)就会按如下规则处理与选择被多次定义的全局符号:
规则1
: 不允许强符号被多次定义(即不同的目标文件中不能有同名的强符号);
规则2: 如果一个符号在某个目标文件中是强符号,在其它文件中都是弱符号,那么选择强符号;
规则3: 如果一个符号在所有目标文件中都是弱符号,那么选择其中任意一个


在符号解析(symbol resolution)阶段,链接器按照所有目标文件和库文件出现在命令行中的顺序从左至右依次扫描它们,在此期间它要维护若干个集合:(1)集合E是将 被合并到一起组成可执行文件的所有目标文件集合;(2)集合D是所有之前已被加入E的目标文件定义的符号集合;(3)集合U是未解析符号 (unresolved symbols,即那些被E中目标文件引用过但在D中还不存在的符号)的集合。一开始,E、D、U都是空的。

(1): 对命令行中的每一个输入文件f,链接器确定它是目标文件还是库文件,如果它是目标文件,就把f加入到E,并把f中未解析的符号和已定义的符号分别加入到U、D集合中,然后处理下一个输入文件。

(2): 如果f是一个库文件,链接器会尝试把U中的所有未解析符号与f中各目标模块定义的符号进行匹配。如果某个目标模块m定义了一个U中的未解析符号,那么就把 m加入到E中,并把m中未解析的符号和已定义的符号分别加入到U、D集合中。不断地对f中的所有目标模块重复这个过程直至到达一个不动点(fixed point),此时U和D不再变化。而那些未加入到E中的f里的目标模块就被简单地丢弃,链接器继续处理下一输入文件。

(3): 当扫描完所有输入文件时如果U非空或者有同名的符号被多次加入D,链接器报告错误信息并退出。否则,它把E中的所有目标文件合并在一起生成可执行文件。

暂且摘录这么多。
首先要注意的是,上文提到: 链接器按照所有目标文件和库文件出现在命令行中的顺序从左至右依次扫描它们因此,这个顺序是一个关键的地方。回到上面提到的例子,链接器先是碰到main.o,把main.o中用到的A.cpp中的函数符号放到U集合中,接下来碰到库libB.a,由于main.cpp并没有调用B.cpp中的函数,所以libB.a中的函数符号并不会与U中的任何未定义函数符号匹配,反而会把libB.a中的未定义函数符号放到U集合中,然后便是libA.a了,经过匹配后,便可以把U集合中关于main.o的函数符号移到D集合中,但libA.a中用到libB.a的函数符号,可是这些符号并不会出现在D集合中(因为先前并没有被任何.o文件调用),因此,这些符号便移到U集合中。最后,链接工作结束了,U集合不会空,所以便出现libA.a中的.o文件找不到在libB.a中的已定义函数符号。同样道理,把-lB与-lA在编译命令中的顺序调转便可以解决问题了。
为了进一步验证这个想法,可以在main.cpp中调用B.cpp中的一个函数,假设为f(此函数也同样被A.cpp调用),编译命令依旧为-lB -lA。当然,链接依然出错,但函数符号f却能被正确解释。

所以,以后写makefile的链接命令就要小心了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

iowin888

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值