目录
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插件的依赖路径。