bjam,别弄乱了链接顺序!

来源:互联网 发布:php专家系统 编辑:程序博客网 时间:2024/04/30 09:14

    公司目前用bjam做build工具。bjam为boost项目所采用,对构建常规的C/C++工程比较方便,但是限制也很多,尤其是内建的脚本语言太晦涩,使得定制自己的构建规则很不方便。不过今天我想说的倒不是这些缺点,而是bjam 3.1.13在FreeBSD平台上的一个bug。

    我们有3个文件,分别是

<1> main.c :

#include <stdio.h>
void foo_one(int);
int main()
{
    foo_one(2007);
    return 0;
}

<2> one.c :

#include <stdio.h>
void foo_two(int);
void foo_one(int a)
{
    foo_two(a);
    printf("in one lib:%d/n",a);
}

<3> two.c :

#include <stdio.h>
void foo_two(int a)
{
    printf("in two lib:%d/n",a + 100);
}


    现在把one.c和two.c分别build成libone.a和libtwo.a,然后用下面这个jamfile来构建可执行文件main :

project server : requirements
        <warnings>on
        <warnings-as-errors>on
        <user-interface>console
        : default-build release ;

exe main :
         main.c
         libone.a
         libtwo.a ;

install all :
        main
        : <location>./ ;

    因为main.c只引用了one.c里的foo_one,然后one.c引用了two.c里的foo_two,所以它们应该依照这个顺序出现在构建脚本中(如上例)。可是兄弟们,当你运指如飞敲入`bjam'和回车,满心欢喜地等待大功告成时,却发现这厮却撂挑子了,给出的理由是:

libone.a(one.o)(.text+0xd): In function `foo_one':
: undefined reference to `foo_two'

    咦,foo_two怎么会找不到?不明明在libtwo里待着吗?按照Unix平台的链接规则(请参考这篇文章)链接器应该能把libtwo.a里的foo_two给揪出来,可为什么结果会这样呢?幸好bjam提供了debug相关选项能看清它所有的命令行调用。咱们也不必瞎猜了,赶紧运行`bjam -d2'来一窥究竟吧。

    其它的输出信息就不必理会了,重要的是链接是如何调用的。在作者的机器上这条命令是这样的:

"g++" -o "main" "../../build/server_project/test/gcc-3.4.4/release/main.o" "libtwo.a" "libone.a" -Wl,--strip-all

    对顺序敏感的读者一定发现了libtwo.a出现在libone.a之前,和它们在构建脚本中出现的顺序刚好相反,而这正是链接失败的元凶(还不明白的同学请仔细研读上面给出的参考文档)。

    经试验,发现bjam在FreeBSD上用.a与.so构建目标时都会有顺序反转的问题,由于在unix平台上链接的成功依赖于链接顺序,所以这个bug很容易让不明就里的同学抓狂。

    补充一点,windows平台上的bjam无此问题。但即使有,对使用Visual C++的用户也没有致命的影响,因为它的链接器对链接顺序并不敏感。
 

原创粉丝点击