注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

绿色圣光

~生活·自愚自乐~

 
 
 

日志

 
 

Fedora 13 软件编译  

2010-06-04 12:54:21|  分类: 电脑知识 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

最近在 Fedora 13 上编译软件,总是通不过,提示让添加某某库的链接。这个困扰了我挺长时间,因为以前都没问题的。直到我在 Fedora 的 Wiki 上看到了这个后才终于明白了:UnderstandingDSOLinkChange


基础知识

默认情况下,ld 允许用户通过中间对象或库间接地链接到需要的对象或库。这很方便,但是也很危险,因为这使得你程序的依赖绑架到了其他对象的依赖上。如果这些对象的联系改变了,它们会破坏掉你的程序,而不会修改你自己的代码!

例如:

libxml2.so 含有:

 NEEDED            Shared library: [libdl.so.2]
NEEDED Shared library: [libz.so.1]

在旧系统中,一个链接了 libxml2 并且使用 dlopen 函数的程序不需要再链接 libdl ,而一个链接了 libxml2 并且使用 gzopen 函数的程序也不需要再链接 libz 。当这些程序要运行时,一旦 libxml2 不再依赖 libdl 或者 libz ,它们就会挂掉。

有何区别?

例如(向 Roland McGrath 致敬):

 ==> foo1.c <==
#include <stdio.h>
extern int foo ();
int
main ()
{
printf ("%d\n", foo ());
}
 ==> foo2.c <==
extern int foo ();
int bar () { return foo (); }
 ==> foo3.c <==
int foo () { return 0; }

准备与位置无关的代码:

 gcc -g -fPIC -c foo1.c foo2.c foo3.c

生成 foo3.so:

 gcc -shared -o foo3.so foo3.o

生成 foo2.so ,链接 foo3.so:

 gcc -shared -o foo2.so foo2.o foo3.so

下面“建议”的改变会影响到下一步:生成 foo1。

当前

虽然对 foo3.so 的链接只是隐式的,但还是会成功地调用 gcc。

 gcc -o foo1 foo1.o foo2.so -Wl,--rpath-link=.

建议

对 gcc 的调用会失败,并且明确提示用户需要链接的共享对象。

 gcc -o foo1 foo1.o foo2.so -Wl,--rpath-link=.
/usr/bin/ld: foo1.o: undefined reference to symbol 'foo'
/usr/bin/ld: note: 'foo' is defined in DSO ./foo3.so so try adding it to the linker
command line

因此,不同点是,你是否可以指向一个你在链接行中没有明确列出的数据源对象,但那是它们其中一个的 DT_NEEDED 依赖(或者递归的,我想)。

最大的区别在于,按照“建议”的改变, ld 默认将不再跳过需要链接的库。当前默认的是,如果一个库被程序列出要使用的另一个库所需要,那么它可以被跳过链接。简单地说,如果 libA 被 libB 需要,而你的程序同时需要 libA 和 libB,你的程序可以仅链接 libB。然后,如果另一个版本的 libB 发布了,且其需求列表中不再包含 libA ,那么重新编译你的程序时,它会莫名其妙地挂掉。

我怎么办?

如果你遇到这种错误,错误信息会提示你显示链接到你所需要的数据源对象。以 foo 为例,添加 foo3.so 就会修正错误:

 gcc -o foo1 foo1.o foo2.so foo3.so -Wl,--rpath-link=.

示例 deltarpm

运行 fedora-cvs deltarpm 或者从下面这里检查一个 deltarpm 的“devel”版本:

:pserver:anonymous@cvs.fedproject.org:/cvs/pkgs

进入 devel 文件夹并运行“'make srpm”来创建一个RPM源码包。

在 /etc/mock 目录中,复制所需的 fedora-rawhide-*.cfg 文件为 test.cfg。编辑 test.cfg ,把“root”改成“test”。

在 test.cfg 中添加下面的内容:

 [ld-test]
name=ld-test
baseurl=http://roland.fedorapeople.org/ld-test/
enabled=1
gpgcheck=0

(注意:在 gcc-4.4.3-5.fc13 中,ld 已经这样修改了,因此这步是不需要的)

这会开启模拟最新版的 ld 。然后,通过模拟执行 -r /path/to/deltarpm/srpm 运行构建。

/var/lib/mock/test/result/build.log 中会显示如下错误:

RPM build errors:
/usr/bin/ld.bfd: rpmdumpheader.o: undefined reference to symbol 'Fopen'
/usr/bin/ld.bfd: note: 'Fopen' is defined in DSO /usr/lib/librpmio.so.0
so try adding it to the linker command line

/usr/lib/librpmio.so.0: could not read symbols: Invalid operation
*** /usr/bin/ld: ld behavior mismatch! ***
*** /usr/bin/ld.bfd succeeeded ***
*** /usr/bin/ld.bfd --no-add-needed exits 1 ***
*** arguments: --eh-frame-hdr --build-id -m elf_i386 --hash-style=gnu -dynamic-linker
 /lib/ld-linux.so.2 -o rpmdumpheader /usr/lib/gcc/i686-redhat-linux/4.4.2/../../..
/crt1.o /usr/lib/gcc/i686-redhat-linux/4.4.2/../../../crti.o /usr/lib/gcc/
i686-redhat-linux/4.4.2/crtbegin.o -L/usr/lib/gcc/i686-redhat-linux/4.4.2 -L/usr/lib
/gcc/i686-redhat-linux/4.4.2 -L/usr/lib/gcc/i686-redhat-linux/4.4.2/../../..
rpmdumpheader.o -lrpm -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed
-lgcc_s --no-as-needed /usr/lib/gcc/i686-redhat-linux/4.4.2/crtend.o /usr/lib/gcc/
i686-redhat-linux/4.4.2/../../../crtn.o collect2: ld returned 1 exit status
make: *** [rpmdumpheader] Error 1

这表明该 deltarpm 在没有链接 /usr/lib/librpmio.so.0 的情况下使用了它。要修正的话,把 -lrpmio 添加到任何使用 librpmio 的二进制文件的gcc命令行中。在 deltarpm 中,这可以通过修改 Makefile 文件迅速修正:

rpmdumpheader: rpmdumpheader.o
- $(CC) $(LDFLAGS) $^ -lrpm -o $@
+ $(CC) $(LDFLAGS) $^ -lrpm -lrpmio -o $@
  评论这张
 
阅读(1268)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017