Linux和FreeBSD在使用非系统自带的gcc时的区别

来源:岁月联盟 编辑:exp 时间:2012-02-15
下面拿CentOS 5和FreeBSD 9.0做下比较:
 
CentOS 5 自带的gcc是gcc (GCC) 4.1.2,通过yum可以安装gcc44 (GCC) 4.4.4
 
FreeBSD 9.0 自带的gcc是gcc (GCC) 4.2.1,通过ports可以安装gcc 4.6 (目前是4.6.2)
 
我们用C++写一个非常简单的C++程序:
 
int main(){
  return 0;
}
 
然后用g++编译:
 
# g++44 main.cpp -o main
 
然后用ldd查看,Linux下的输出结果为:
       libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x000000336f000000)
        libm.so.6 => /lib64/libm.so.6 (0x000000336cc00000)
       libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x000000336e400000)
        libc.so.6 => /lib64/libc.so.6 (0x000000336c400000)
        /lib64/ld-linux-x86-64.so.2 (0x000000336c000000)
 
FreeBSD下的输出结果为:
      libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0×800849000)
        libm.so.5 => /lib/libm.so.5 (0x800b59000)
       libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x800d7a000)
        libc.so.7 => /lib/libc.so.7 (0x800f87000)
 
其中有两行我故意标红了。因为他们是来自于gcc。那么就有这么一个问题:不同版本的gcc,这两个库,一样吗?或者我这么问,gcc 4.4、gcc 4.6、gcc 4.2、gcc 4.1相比,他们的C++标准库(libstdc++.so)的接口一样吗? 实现一样吗?(此处指需要被编译的那部分,如非模板类)
 
我们来看看CentOS怎么做的:
 
CentOS 5的gcc44-c++这个包,只带了两个so。/usr/lib/gcc/x86_64-redhat-linux6E/4.4.4/32/libstdc++.so和/usr/lib/gcc/x86_64-redhat-linux6E/4.4.4/libstdc++.so。而这两个so竟然只是文本文件,内容大概是这样:
INPUT ( -lstdc++_nonshared /usr/lib64/libstdc++.so.6 )
 
也就是说,它会静态链接到/usr/lib/gcc/x86_64-redhat-linux6E/4.4.4/libstdc++_nonshared.a这个文件,并动态链接到/usr/lib64/libstdc++.so.6(这个文件由gcc 4.1提供)
 
所以,在CentOS 5中,用gcc 4.4编译出来的东西,运行环境不需要安装gcc 4.4 !
 
然后看FreeBSD怎么做的:
 
gcc 4.6的so,安装在/usr/local/lib/gcc46/目录下。如果你是在64位环境下安装的,那么只有64位版本的,没有32位版本的。最关键的是,它确实是一个elf格式的so,而不是文本文件、软链接什么的。
 
如果在FreeBSD下这么编译一个文件:
 
# g++46 -o t test.cpp
 
那么它会错误的链接到4.2的so上
 
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0×800849000)
libm.so.5 => /lib/libm.so.5 (0x800b59000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x800d7a000)
libc.so.7 => /lib/libc.so.7 (0x800f87000)
 
你的程序还能不能正常工作,那就看天命了。正确的做法是,在链接的时候加上-Wl,-rpath=/usr/local/lib/gcc46 。
 
FreeBSD的官网上有一个文档解释了这个问题:http://www.freebsd.org/doc/en/articles/custom-gcc/article.html但是这个文档有点老,而且写的不是很详细。
 
现在如果只是为了让ports用gcc 4.6,那么直接在/etc/make.conf中加入“USE_GCC=4.6”即可

作者 snnn