gcc编译的程序版本不兼容
A. 用不同版本GCC编译出的库只能用对应的GCC使用吗
不同版本的动态库是为了升级方便,旧的程序需要与旧的库链接,新的程序与新的.
一般的做法是把libabc.so连接(symbolic link, ln -s libabc.so.N libabc.so)到最新的版本,这样以后的新程序,在用gcc -labc的时候,都会链接到新的版本.旧的已经链接好的程序并不会产生不兼容的问题,因为旧程序在过去已经链接过了(动态库链接的信息可以用ldd来查看: ldd /bin/ls).
symbolic link, ln是推荐的维护版本的办法,不建议更改文件名.
如果你要有一个方便的办法链接旧的版本, 建一个旧的版本的symbolic link就可以了,libabc11.so
ln -s libabc.so.11 libabc11.so
gcc -labc11...
B. gcc g++ 使用哪些编译选项可以让编译出来的程序兼容32位和64位
用32位的gcc,编译出来后,能在32位上运行,也能在64位上兼容。
C. 高版本gcc编译出的程序在低版本glibc机器上运行
比如我们用gcc 9.3.0编译程序,但需要发布的机器gcc版本是4.8.5,怎么办?祥孙
你可能想到如下方法
将libc和libstdc++静态编译,编译时带上如下参数。
glibc并不推荐静态链接,你依赖的其他库可能依赖的了glibc,并且往往是动态链接的,可以通过 nm <bin> | grep GLIBC_ 确定你的程序是否依赖了glibc。
使用携带gcc9.3.0环境的容器发布程序,是可以的。但是在一些没有容器且没有sudo权限的场合,依然不太友好。
这个方法虽然听起来不是很优雅,但其实如果你对elf文件有一些了解,是不错的方式。下面说下具体的方法。
当你有条件获得程序源码,并能够重新编译时,可以直接在编译时指定相关参数来解决。
先说编译时要增加的参数:
gcc参数
ld参数
这两个参数分别设置的elf文件中的rpath和interpreter字段。
rpath
全名 run-time search path ,是elf文件中一个字段,它指定了可执行文件执行时搜索so文件的第一优先位置,一般编译器默认将该字段设为空。elf文件中还有一个类似的字段runpath,其作用与rpath类似,但搜索优先级稍低。搜索优先级:
如果你需要使用相对路径指定lib文件夹,可以使用 ORIGIN 变量,ld会将ORIGIN理解成可执行文件所在的路径。
interpreter
动态库加载器,程序启动时,操作系统会先把控制权转交给ld-linux-x86-64.so.2,该so负责加载所有程序依赖的so。。这个字段在链接时会帮你自动设置,64bit程序一般为 /lib64/ld-linux-x86-64.so.2 。修改rpath或者LD_LIBRARY_PATH指向本地lib目录,但通过ldd程序,发现/lib64/ld-linux-x86-64.so.2这个so仍然指向系统so。原因就是这个字并宽段是写谨蔽链死在elf文件中的,并不受LD_LIBRARY_PATH影响。
编译时带上这两个参数,下面只需要将你程序依赖的so打包一份,随程序进行发布即可。
当你无法编译程序时,也可以通过其他方式修改rpath和interpreter。这种情况需要使用到一个工具 patchelf ,通过 dnf install patchelf 即可安装。你可以通过它修改elf文件的rpath和interpreter:
除了绝对路径,一种比较常见的方式是在部署前,使用 pwd 获取当前路径,使用相对路径指向本地lib。