Linux下可执行程序依赖库打包

目录

1 静态依赖打包

1.1 依赖库的打包

1.2 依赖库的过滤

2 动态依赖打包

2.1 gdb查看程序依赖库

2.2 依赖库的打包

2.3 依赖库的过滤

3 Qt程序的打包说明

3.1 Qt的运行依赖库目录调整

3.2 Qt工程的依赖库、插件的设置


1 静态依赖打包

        若执行程序不涉及到库的动态加载,则可以使用ldd命令查看其依赖库,并将依赖库进行打包。

1.1 依赖库的打包

        使用pack_static.sh即可完成打包。

        使用命令:./pack_static.sh ./TestApp ./depend

        参数1:待打包的执行程序;

        参数2:依赖库存放的目录;

        pack_static.sh的实现如下:

#!/bin/bash  
basepath=$(cd `dirname $0`; pwd)

#不需要打包的目录
filter_folder_list=(
    "/lib" 
    "/usr/lib"
)

case $# in
    "0")
    echo "\033[31m error param \033[0m"
    echo "\033[32m [exe_name] [pack_dir] eg:./pack.sh TestApp usr/local/depend \033[0m"
    exit 0
;;
    "1")
    echo "use default pack_dir"
;;
esac

#程序名称
exe_name=$1

#打包目录
pack_dir=${basepath}/depend

if [ $# -ge 2 ];then
    pack_dir=$2
fi

echo "pack_dir=${pack_dir}"

if [ ! -d ${pack_dir} ];then
    mkdir ${pack_dir}
fi

#处理打包
function process_depend()
{
    #过滤不需要打包的目录
    for _folder in ${filter_folder_list[@]}
    do
        result=$(echo $1 | grep "^${_folder}")  
        
        if [ -n "${result}" ];then
            return
        fi
    done
    
    cp $1 $pack_dir
}

#打包动态库
deplist=$(ldd $exe_name | awk  '{if (match($3,"/")){ printf("%s "),$3 } }')  

#过滤不需要打包的目录
for dep_file in $deplist
do   
    process_depend "${dep_file}"
done

1.2 依赖库的过滤

        若不想打包某些系统目录下的依赖库,则需要对pack_static.sh中的参数进行调整。

       如上图,在filter_folder_list中添加需要过滤的目录即可,这样在打包时就可以过滤对应目录下的库文件。

        注:一般情况下是不能够打包系统目录下面的库,尤其是系统库(如libc.so.6之类)。这些库需要实际运行环境下的版本,若进行了打包反而会导致运行异常。

2 动态依赖打包

        若执行程序的运行涉及到库的动态加载(如插件),则需要使用gdb运行,并在gdb的输出日志中提取待打包的依赖库。

2.1 gdb查看程序依赖库

         以TestApp为例,执行流程如下:

a) 启用gdb运行,开启并输出gdb信息;

    gdb ./TestApp

    set logging file ./1.txt

    set logging on

    run

 b) 待程序正常启动且运行一段时间后,使用ctrl+c打断运行,并输入命令查看依赖的动态库;

     info shared

 

c) 一直敲回车,待依赖库的内容不再更新为止;

 d) 退出gdb;

     quit

这样在输出文件1.txt中就可以看到刚才的调试信息,其中红色方框部分就是该程序依赖的库。

2.2 依赖库的打包

       使用pack_dynamic.sh即可完成打包。

       使用命令:./pack_dynamic.sh ./1.txt ./depend

       参数1:章节2.1中的gdb输出信息;

       参数2:依赖库存放的目录;

       pack_dynamic.sh的实现如下:

#!/bin/bash  
basepath=$(cd `dirname $0`; pwd)

#标记找到动态库对应的位置
s_tag="From To Syms Read Shared Object Library"
shared_flag=0

#记录Qt的安装目录
QT_PATH="/opt/Qt5.5.1/5.5/gcc_64/"

#不需要打包的目录
filter_folder_list=(
    "/lib" 
    "/usr/lib"
)

#提示信息
case $# in
    "0")
    echo "\033[31m error param \033[0m"
    echo "\033[32m [exe_name] [pack_dir] eg:./3_simple_pack_dynamic.sh ./1.txt usr/local/depend \033[0m"
    exit 0
;;
    "1")
    echo "use default pack_dir"
;;
esac

#gdb文件名称
gdb_output_file=$1

#打包目录
pack_dir=${basepath}/depend

if [ $# -ge 2 ];then
    pack_dir=$2
fi

echo "pack_dir=${pack_dir}"

if [ ! -d ${pack_dir} ];then
    mkdir ${pack_dir}
fi

#处理Qt的依赖库(Qt库对存放目录有要求)
function process_qt_depend()
{
    folder_name=${1#*$QT_PATH}
    folder_name=${folder_name%/*}
    folder_name=${pack_dir}/${folder_name}

    if [ ! -d ${folder_name} ];then
        mkdir -p ${folder_name}
    fi

    cp $1 $folder_name
}

#处理依赖库
function process_depend()
{
    if [ -z $1 ];then    
        return
    fi

    #转换为绝对路径
    real_dll_file=$(readlink -f $1)

    #过滤不需要打包的目录
    for _folder in ${filter_folder_list[@]}
    do
        result=$(echo $real_dll_file | grep "^${_folder}")  
        
        if [ -n "${result}" ];then
            return
        fi
    done

    #处理Qt的依赖库
    result=$(echo $real_dll_file | grep "^${QT_PATH}")

    if [ -z "${result}" ];then
        cp $real_dll_file $pack_dir
    else
        process_qt_depend "${real_dll_file}"
    fi    
}

#分析gdb输出日志中的动态库
cat $gdb_output_file | while read line;
do
    result=$(echo $line | grep "${s_tag}")
    
    if [ -n "${result}" ];then
        shared_flag=1
    fi

    if [ ${shared_flag} -eq 1 ];then
        #提取最后一列
        dll_file=$(echo $line | awk  '{if (match($NF,"^/")){ printf("%s "),$NF } }')
        process_depend $dll_file
    fi
done


2.3 依赖库的过滤

        若不想打包某些系统目录下的依赖库,则需要对pack_dynamic中的参数进行调整。

        如上图,在filter_folder_list中添加需要过滤的目录即可,这样在打包时就可以过滤对应目录下的库文件。 

3 Qt程序的打包说明

       Qt程序对库的目录以及工程的设置有要求,具体的说明如下。

3.1 Qt的运行依赖库目录调整

       Qt的运行依赖插件和其核心库有目录上的要求。

 

       类似于libQt5Core.so.5.5.1,需要放到lib文件夹下,插件则需要放在plugins下对应的目录中。

       上述脚本可以按照该目录将qt的依赖库进行打包,若Qt的安装目录和示例中不一样,请安装实际的路径进行调整。

3.2 Qt工程的依赖库、插件的设置

  •        rpath的设置

       在CMakeLists.txt中,增加以下设置就可以设置执行程序的依赖库路径。

       set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,-rpath=./:./depend/:./depend/plugins/:./depend/lib")

       插件依赖目录的设置

       在main.cpp中,增加以下代码可以设置qt插件的依赖路径。

   

  • 0
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是一个可以打包Qt可执行程序并拷贝依赖的脚本,同时支持x86和arm架构: ``` #!/bin/bash # 设置目标平台和架构 ARCH=$1 if [ "$ARCH" != "x86" ] && [ "$ARCH" != "arm" ]; then echo "Invalid architecture. Please choose x86 or arm." exit 1 fi # 设置Qt的路径和版本号 QT_PATH=/opt/Qt/5.15.2 QT_VERSION=5.15.2 # 设置项目名称和路径 PROJECT_NAME=MyApp PROJECT_DIR=/path/to/project # 设置编译选项 QMAKE_CXXFLAGS="-fPIC -std=c++11" QMAKE_LFLAGS="-static-libgcc -static-libstdc++ -Wl,-rpath-link,'$$ORIGIN'" # 创建构建目录 BUILD_DIR=$PROJECT_DIR/build-$ARCH if [ ! -d "$BUILD_DIR" ]; then mkdir "$BUILD_DIR" fi # 生成Makefile cd "$BUILD_DIR" if [ "$ARCH" = "x86" ]; then $QT_PATH/$QT_VERSION/gcc_64/bin/qmake "$PROJECT_DIR/$PROJECT_NAME.pro" -spec linux-g++-64 else $QT_PATH/$QT_VERSION/android_armv7/bin/qmake "$PROJECT_DIR/$PROJECT_NAME.pro" -spec android-g++ "CONFIG+=arm" fi # 编译可执行程序 make if [ $? -ne 0 ]; then echo "Build failed." exit 1 fi # 拷贝依赖 if [ "$ARCH" = "x86" ]; then # 拷贝Qt cp $QT_PATH/$QT_VERSION/gcc_64/lib/libQt5Core.so.5 $BUILD_DIR cp $QT_PATH/$QT_VERSION/gcc_64/lib/libQt5Gui.so.5 $BUILD_DIR cp $QT_PATH/$QT_VERSION/gcc_64/lib/libQt5Widgets.so.5 $BUILD_DIR cp $QT_PATH/$QT_VERSION/gcc_64/lib/libQt5Network.so.5 $BUILD_DIR else # 拷贝Qt cp $QT_PATH/$QT_VERSION/android_armv7/lib/libQt5Core.so.5 $BUILD_DIR cp $QT_PATH/$QT_VERSION/android_armv7/lib/libQt5Gui.so.5 $BUILD_DIR cp $QT_PATH/$QT_VERSION/android_armv7/lib/libQt5Widgets.so.5 $BUILD_DIR cp $QT_PATH/$QT_VERSION/android_armv7/lib/libQt5Network.so.5 $BUILD_DIR # 拷贝Android依赖 cp $QT_PATH/$QT_VERSION/android_armv7/plugins/platforms/libqtforandroid.so $BUILD_DIR cp $QT_PATH/$QT_VERSION/android_armv7/plugins/bearer/libqandroidbearer.so $BUILD_DIR fi # 拷贝可执行程序 cp "$BUILD_DIR/$PROJECT_NAME" "$PROJECT_DIR" echo "Build successful." exit 0 ``` 在脚本中,您需要设置以下参数: - ARCH:目标平台和架构,可以选择x86或者arm。 - QT_PATH:Qt的安装路径。 - QT_VERSION:Qt的版本号。 - PROJECT_NAME:项目名称。 - PROJECT_DIR:项目路径。 - QMAKE_CXXFLAGS:编译选项。 - QMAKE_LFLAGS:链接选项。 脚本执行完毕后,可执行程序依赖会被拷贝到项目路径下。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值