⾼版本gcc编译linux,⾼版本gcc编译出的程序在低版本glibc机
器上运⾏
⽐如我们⽤ 9.3.0编译程序,但需要发布的机器gcc版本是4.8.5,怎么办?
你可能想到如下⽅法
静态编译
容器发布linux下gcc编译的四个步骤
打包依赖的so,使⽤本地so运⾏程序
1.静态编译
将libc和libstdc++静态编译,编译时带上如下参数。
g++ --libgcc -static-libstdc++
glibc并不推荐静态链接,你依赖的其他库可能依赖的了glibc,并且往往是的,可以通过nm | grep GLIBC_确定你的程序是否依赖了glibc。
2.容器发布
使⽤携带gcc9.3.0环境的容器发布程序,是可以的。但是在⼀些没有容器且没有sudo权限的场合,依然不太友好。
3.打包依赖的so发布
这个⽅法虽然听起来不是很优雅,但其实如果你对elf⽂件有⼀些了解,是不错的⽅式。下⾯说下具体的⽅法。
3.1 ⽅式1 在编译时设置rpath和dynamic linker
当你有条件获得程序源码,并能够重新编译时,可以直接在编译时指定相关参数来解决。
先说编译时要增加的参数:
# 绝对路径
gcc -Wl,-rpath='/my/lib',-dynamic-linker='/my/lib/ld-linux.so.2'
gcc参数
-Wl,option
Pass option as an option to the linker.
ld参数
-rpath=dir
Add a directory to the runtime library search path. This is used when linking an ELF executable with shared objects.
--dynamic-linker=file
Set the name of the dynamic linker.
这两个参数分别设置的elf⽂件中的rpath和interpreter字段。
rpath
全名run-time search path,是elf⽂件中⼀个字段,它指定了可执⾏⽂件执⾏时搜索so⽂件的第⼀优先位置,⼀般编译器默认将该字段设为空。elf⽂件中还有⼀个类似的字段runpath,其作⽤与rpath类似,
但搜索优先级稍低。搜索优先级:
rpath > LD_LIBRARY_PATH > runpath > ldconfig缓存 > 默认的/lib,/usr/lib等
如果你需要使⽤相对路径指定lib⽂件夹,可以使⽤ORIGIN变量,ld会将ORIGIN理解成可执⾏⽂件所在的路径。
gcc -Wl,-rpath='$ORIGIN/../lib'
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打包⼀份,随程序进⾏发布即可。
3.2 ⽅式2 直接修改⼆进制程序的rpath和interpreter
当你⽆法编译程序时,也可以通过其他⽅式修改rpath和interpreter。这种情况需要使⽤到⼀个⼯具patchelf,通过dnf install patchelf即可安装。你可以通过它修改elf⽂件的rpath和interpreter:
patchelf --set-rpath /my/lib your_program
patchelf --set-interpreter /my/lib/ld-linux.so.2 your_program
除了绝对路径,⼀种⽐较常见的⽅式是在部署前,使⽤pwd获取当前路径,使⽤相对路径指向本地lib。
patchelf --set-rpath `pwd`/../lib your_program
patchelf --set-interpreter `pwd`/../lib/ld-linux-x86-64.so.2 ./your_program

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。