技术解析

编写了一个小脚本,方便在不同版本 Linux 转移 c/c++程序,无需重新编译。
0
2021-06-21 03:15:41
idczone

编写了一个小脚本,方便在不同版本 linux 转移 c/c++程序,无需重新编译。

依赖 patchelf 这个小工具,可从各个软件源上安装。

使用场景:我司 linux 开发环境有很多,debian 系和 redhat 系 系统的库都不能兼容,有时候想把在 ubuntu 上编译的一个程序放到 centos 上跑就要重新编译一下,很麻烦,于是写了下面这个小脚本,使用很简单,假设要打包的程序名叫 testexe,只需patchelf.sh testexe,会生成一个 testexe.tar.gz 的包包含了这个程序所需的所有 so 动态库,把这个包放到 centos 下解压,会解压出 testexe 和它的所有依赖的 so,so 文件单独放在__lib 开头的文件夹,这个 testexe 会在__lib*的文件夹里找它的动态库而不会在 /usr/下面找。原理很简单

#!/bin/sh
#echo "脚本$0"
#echo "第一个参数$1"
which patchelf > /dev/null 2>&1
if [ $? -ne 0 ]; then
    echo "需要安装 patchelf,使用:"
    echo "sudo yum install patchelf 或"
    echo "sudo apt-get install patchelf"
    exit 1
fi
if [ -z "$1" ]
then
    echo "请输入可执行程序名"
    exit 1
fi
if  !(file "$1" | grep -q "GNU/Linux")
then
    echo "$1 不是是可执行文件"
    exit 1
fi
PwdDir=`pwd`
if [ -w . ];then
    echo "将在当前目录:"$PwdDir"产生打包文件"
else
    echo "当前目录不可写"
fi
PackBuildDir=$PwdDir/__PackBuildDir__
mkdir $PackBuildDir
cp $1 $PackBuildDir
ExeName=${1##*/}
CopyExePath=$PackBuildDir/$ExeName

echo "打包的 exe 是:" $ExeName
LibDirName="__libs_"$ExeName"__"


mkdir $PackBuildDir/$LibDirName

for i in `ldd $1| awk -F ' ' '{print $3}'|grep '.so'`; do
cp -n "$i" $PackBuildDir/$LibDirName
done
cp /lib64/ld-linux-x86-64.so.2 $PackBuildDir/$LibDirName
#改变库加载路径
patchelf --set-rpath ./$LibDirName --force-rpath $CopyExePath
patchelf --set-interpreter ./$LibDirName/ld-linux-x86-64.so.2 $CopyExePath

#打包
cd $PackBuildDir
tar -zcvf $PwdDir/$ExeName.tar.gz ./$ExeName ./$LibDirName

cd $PwdDir
rm -rf $PackBuildDir


exit 0


why not docker

docker

zypper 表示路过...

我更想问这么折腾,为何不用静态链接?

楼上已经讲出了最根本的问题:为什么不用静态链接?

glibc 静态链接坑特别多。。。还有一些第三方库要静态链接也比较麻烦

另外其实这样打包也不是很稳,glibc 在使用名字查询等函数时,会 dlopen 一个硬编码的 so 文件。。然后在其他系统上可能会有冲突。。。
我折腾的一个方法是把这些 nss 相关的库也一并复制了,然后用 chroot 等方法去跑。。。
https://github.com/codehz/nsroot/wiki/Binary-Packager-for-archlinux

是的,我就是 glic 和 phread 静态链接搞不定才用这种方法的

ld-linux-x86-64.so.2 在我这里是个软连接 连接到当前目录下

数据地带为您的网站提供全球顶级IDC资源
在线咨询
专属客服