402 lines
13 KiB
Bash
402 lines
13 KiB
Bash
#!/bin/bash
|
||
# shellcheck disable=SC2155
|
||
if ! type "include" > /dev/null 2>&1; then
|
||
include() {
|
||
. "$(cd "$(dirname "$1")" && pwd)/${2}";
|
||
};
|
||
fi
|
||
include "${BASH_SOURCE[0]}" ../pragma_once.bash
|
||
if ! pragma_once ${BASH_SOURCE[0]}; then return 0; fi
|
||
include "${BASH_SOURCE[0]}" ./global_rely/export.bash
|
||
# shellcheck source=./global_rely/export.bash
|
||
|
||
|
||
|
||
|
||
mkdir_with_symlink() {
|
||
local dest_dir="$1" # 要处理的目标目录
|
||
local install_root="$2" # 安装根目录
|
||
is_absolute_directory "$dest_dir" || {
|
||
echo "mkdir_with_rlink dest_dir=${dest_dir}"
|
||
exit 1
|
||
}
|
||
is_absolute_directory "$install_root" || {
|
||
echo "install_root=${install_root}"
|
||
exit 1
|
||
}
|
||
local target="${install_root}${dest_dir}"
|
||
if is_absolute_directory "$target"; then
|
||
#echo "$target 文件夹已存在,取消mkdir_symlink!"
|
||
return 0
|
||
fi
|
||
local current_path=""
|
||
local dir_parts=()
|
||
IFS='/' read -ra dir_parts <<<"$dest_dir"
|
||
dir_parts=("${dir_parts[@]:1}") #(因为根目录是空字符串)
|
||
local dir_name
|
||
for dir_name in "${dir_parts[@]}"; do
|
||
current_path="$current_path/$dir_name"
|
||
local target_dir_path="${install_root}${current_path}"
|
||
if [ -L "$current_path" ]; then
|
||
local extern_rlink_target_path=$(readlink -f "$current_path")
|
||
local rlink_path="${target_dir_path}"
|
||
local rlink_dir_path="$(dirname "${rlink_path}")"
|
||
local rlink_target_path="$install_root$extern_rlink_target_path"
|
||
if [ ! -L "$rlink_path" ] || [ "$(readlink -f "$rlink_path")" != "$rlink_path" ]; then
|
||
mkdir_with_symlink "$extern_rlink_target_path" "$install_root"
|
||
get_relative_path "$rlink_dir_path" "$rlink_target_path"
|
||
ln -sf "$_ret_" "$rlink_path"
|
||
[ -n "$_cur_log_path_" ] && echo "=======dir symlink======= ln -sf $_ret_ $rlink_path " >>"$_cur_log_path_"
|
||
fi
|
||
elif [ ! -e "$target_dir_path" ]; then
|
||
mkdir -p "$target_dir_path"
|
||
fi
|
||
done
|
||
}
|
||
|
||
cp_with_symlink() {
|
||
local dest_file="$1" # 源文件路径
|
||
local install_root="$2"
|
||
is_absolute_file "$dest_file" || {
|
||
echo "[cp_with_symlink error] dest_file=${dest_file} is not absolute file!"
|
||
exit 1
|
||
}
|
||
is_absolute_directory "$install_root" || {
|
||
echo "[cp_with_symlink error] install_root=${install_root} is not absolute directory!"
|
||
exit 1
|
||
}
|
||
local target="${install_root}${dest_file}"
|
||
if is_absolute_file "$target"; then
|
||
echo "$target 文件已存在,取消cp_symlink!"
|
||
return 0
|
||
fi
|
||
local dest_dir
|
||
dest_dir=$(dirname "$dest_file")
|
||
mkdir_with_symlink "${dest_dir}" "$install_root"
|
||
|
||
local ret
|
||
ret=$target
|
||
if [ -L "$dest_file" ]; then
|
||
local extern_rlink_path="$dest_file"
|
||
local extern_rlink_target_path=$(readlink -f "$dest_file")
|
||
cp_with_symlink "${extern_rlink_target_path}" "$install_root"
|
||
ret=$_ret_
|
||
local rlink_target_path="${install_root}${extern_rlink_target_path}"
|
||
local rlink_path="${install_root}${extern_rlink_path}"
|
||
local rlink_path_dir="$(dirname "$rlink_path")"
|
||
get_relative_path "$rlink_path_dir" "$rlink_target_path"
|
||
ln -sf "$_ret_" "$rlink_path"
|
||
[ -n "$_cur_log_path_" ] && echo "=file_symlink= ln -sf $_ret_ $rlink_path " >>"$_cur_log_path_"
|
||
else
|
||
cp "${dest_file}" "${target}"
|
||
echo "cp ${dest_file} ==> ${target}"
|
||
fi
|
||
|
||
_ret_=$ret
|
||
return 0
|
||
}
|
||
|
||
# $1 传入一个数组,用于拷贝他们的依赖
|
||
# $2 拷贝依赖的根目录
|
||
copy_dependencies() {
|
||
#local abs_exe_path=$(realpath "$1")
|
||
local install_root="$2"
|
||
declare -A path_seen
|
||
declare -A error_line_skipped
|
||
declare -A rely_dir
|
||
local ldd_log="${install_root}/deploy_ldd.txt"
|
||
local run_path_log="${install_root}/deploy_run_path.txt"
|
||
local illegal_line="${install_root}/illegal_line.txt"
|
||
extract_absolute_paths() {
|
||
rely_dir=()
|
||
local abs_exe_path="$1"
|
||
local lines
|
||
mapfile -t lines < <(ldd "$abs_exe_path")
|
||
local result=()
|
||
echo "abs_exe_path == $abs_exe_path" >>"${ldd_log}"
|
||
for line in "${lines[@]}"; do
|
||
echo "line == $line" >>"${ldd_log}"
|
||
if [[ -z "$line" ]]; then
|
||
continue
|
||
fi
|
||
if [[ "$line" =~ ^[[:space:]]*/lib64/ld-linux-x86-64 ]]; then
|
||
continue
|
||
fi
|
||
if [[ "$line" =~ ^[[:space:]]*linux-vdso.so ]]; then
|
||
continue
|
||
fi
|
||
if [[ "$line" =~ ^[[:space:]]*statically\ linked ]]; then
|
||
continue
|
||
fi
|
||
if [[ -n "${error_line_skipped[$line]}" ]]; then
|
||
continue
|
||
fi
|
||
local fields
|
||
IFS=' ' read -r -a fields <<<"$line"
|
||
local num_fields=${#fields[@]}
|
||
if [ "${num_fields}" != 4 ]; then
|
||
echo "${abs_exe_path} == ${line} 判断属性数量错误! num_fields == ${num_fields}" >>"$illegal_line"
|
||
error_line_skipped["$line"]=1
|
||
continue
|
||
fi
|
||
if [[ "${fields[2]}" == "not" && "${fields[3]}" == "found" ]]; then
|
||
echo "严重错误! ${abs_exe_path} 找不到$abs_exe_path的依赖: ${line}" | tee -a "$illegal_line"
|
||
#read -n 1 # 等待用户按下一个键
|
||
#exit 1
|
||
fi
|
||
if [ "${fields[1]}" != "=>" ]; then
|
||
echo "${abs_exe_path} == 判断是否第二个是=> ${fields[1]} != '>'" >>"$illegal_line"
|
||
error_line_skipped["$line"]=1 # 记录已跳过的行
|
||
continue
|
||
fi
|
||
if [[ "${fields[2]}" =~ ^/ ]]; then
|
||
local path_with_rlink="${fields[2]}"
|
||
local dir_path_with_rlink=$(dirname "${path_with_rlink}")
|
||
if [[ -z "${rely_dir["$dir_path_with_rlink"]}" ]]; then
|
||
rely_dir["$dir_path_with_rlink"]=1
|
||
fi
|
||
if [[ -z "${path_seen[$path_with_rlink]}" ]]; then
|
||
result+=("${path_with_rlink}")
|
||
path_seen["$path_with_rlink"]=1
|
||
fi
|
||
fi
|
||
done
|
||
local rely_dir_path
|
||
local runpath_list=""
|
||
declare -A seen_paths
|
||
for rely_dir_path in "${!rely_dir[@]}"; do
|
||
get_relative_origin_path "$(dirname "${abs_exe_path}")" "${rely_dir_path}"
|
||
path="${_ret_}"
|
||
if [[ -n "$path" && -z "${seen_paths[$path]}" ]]; then
|
||
seen_paths[$path]=1
|
||
runpath_list+="${path}:"
|
||
fi
|
||
done
|
||
runpath_list="${runpath_list%:}"
|
||
if [[ "${runpath_list}" ]]; then
|
||
patchelf --set-rpath "${runpath_list}" "${install_root}${abs_exe_path}"
|
||
fi
|
||
echo "${abs_exe_path} == ${runpath_list} " >>"${run_path_log}"
|
||
_ret_="$(
|
||
IFS=:
|
||
echo "${result[*]}"
|
||
)"
|
||
}
|
||
_cp_rely() {
|
||
local abs_exe_path="$1"
|
||
local install_root="$2"
|
||
mkdir -p "${install_root}"
|
||
chmod 777 "${install_root}"
|
||
cp_with_symlink "${abs_exe_path}" "${install_root}"
|
||
extract_absolute_paths "${abs_exe_path}"
|
||
local tobe_install_list
|
||
local tobe_install
|
||
IFS=':' read -ra tobe_install_list <<<"$_ret_"
|
||
for tobe_install in "${tobe_install_list[@]}"; do
|
||
if [ -e "$tobe_install" ]; then
|
||
_cp_rely "$tobe_install" "$install_root"
|
||
fi
|
||
done
|
||
}
|
||
|
||
_cur_log_path_="cp_reply_log.txt"
|
||
|
||
paths=$1
|
||
IFS=':' read -r -a path_array <<<"$paths"
|
||
for path in "${path_array[@]}"; do
|
||
local abs_exe_path
|
||
if [ -d "$path" ]; then
|
||
local executable_files=$(find "$path" -type f -executable)
|
||
while IFS= read -r abs_exe_path; do
|
||
_cp_rely "$abs_exe_path" "$install_root"
|
||
done <<<"$executable_files"
|
||
elif [ -f "$path" ]; then
|
||
abs_exe_path=$(realpath "$path")
|
||
_cp_rely "$abs_exe_path" "$install_root"
|
||
else
|
||
echo "ERROR WARING _cp_rely 路径无效或不存在: $path" >>"${_cur_log_path_}"
|
||
echo "ERROR WARING _cp_rely 路径无效或不存在: $path"
|
||
exit 1
|
||
fi
|
||
done
|
||
}
|
||
|
||
# 获取一个名称为了不重复 让目录尾数递加
|
||
get_no_repeat_dir() {
|
||
local install_root="$1"
|
||
local original_install_root="$install_root"
|
||
local counter=1
|
||
while [ -e "$install_root" ]; do
|
||
install_root="${original_install_root}_${counter}" # 在原目录名后加上数字
|
||
((counter++)) # 增加计数器
|
||
done
|
||
_ret_="$install_root"
|
||
}
|
||
|
||
copy_qt_plugin() {
|
||
local target_dir="$1"
|
||
local qt_plugin_dir="$2"
|
||
|
||
# 设置默认的 Qt 插件目录
|
||
local default_qt_plugin_dirs=(
|
||
"/home/env/Qt5.14.2/5.14.2/gcc_64/plugins"
|
||
"/usr/lib/x86_64-linux-gnu/qt5/plugins/"
|
||
"/usr/lib/qt/plugins/"
|
||
"/usr/local/Qt-*/plugins/"
|
||
)
|
||
|
||
# 如果没有提供 qt_plugin_dir,尝试使用默认目录
|
||
if [ -z "$qt_plugin_dir" ]; then
|
||
for dir in "${default_qt_plugin_dirs[@]}"; do
|
||
# 使用通配符来查找可能的目录
|
||
for plugin_dir in $dir; do
|
||
if [ -d "$plugin_dir" ]; then
|
||
qt_plugin_dir="$plugin_dir"
|
||
break 2 # 找到一个有效的目录,退出循环
|
||
fi
|
||
done
|
||
done
|
||
fi
|
||
|
||
# 检查最终选择的源目录是否存在
|
||
if [ ! -d "$qt_plugin_dir" ]; then
|
||
echo "错误: 源目录 ${qt_plugin_dir} 不存在。"
|
||
return 1
|
||
fi
|
||
|
||
# 创建目标目录并复制插件
|
||
mkdir -p "$target_dir"
|
||
cp -r "$qt_plugin_dir" "$target_dir/"
|
||
|
||
echo "成功复制 Qt 插件到 ${target_dir}。"
|
||
return 0
|
||
}
|
||
|
||
# 第一个参数可执行文件或库绝对路径
|
||
# 发布的目录绝对路径 (不一定是真实的 同名会把名+1)
|
||
deploy() {
|
||
local executable="$1"
|
||
get_no_repeat_dir "$2"
|
||
local install_root=${_ret_}
|
||
echo "deploy "
|
||
echo "executable $1"
|
||
echo "no_repeat install_root $install_root"
|
||
echo "install_root $2"
|
||
mkdir -p "$install_root"
|
||
chmod 777 "$install_root"
|
||
local extern_exe_path=$(realpath "${executable}")
|
||
local extern_exe_dir=$(dirname "${extern_exe_path}")
|
||
local exe_path="${install_root}${extern_exe_path}"
|
||
local exe_dir="${install_root}${extern_exe_dir}"
|
||
copy_dependencies "${extern_exe_path}" "${install_root}"
|
||
ln -sf ".$extern_exe_path" "$install_root/$(basename "$extern_exe_path")"
|
||
compress_directory_tar_gz "$install_root" "$(dirname "$2")" "$(basename "$2").tar.gz"
|
||
}
|
||
|
||
# ln -sf /home/user/myapp/target_dir /home/user/myapp/my_link
|
||
# 思路把需要的库拷贝到 qt lib底下 然后建立软连接
|
||
# /home/env/Qt5.14.2/5.14.2/gcc_64
|
||
# bin doc include lib mkspecs phrasebooks plugins qml translations
|
||
deploy_qt() {
|
||
local executable="$1"
|
||
get_no_repeat_dir "$2"
|
||
local install_root=${_ret_}
|
||
local extern_qt_dir="$3"
|
||
local qt_plugin_dir="$4"
|
||
echo "deploy_qt "
|
||
echo "executable $executable"
|
||
echo "install_root $install_root"
|
||
echo "extern_qt_dir $extern_qt_dir"
|
||
echo "qt_plugin_dir $qt_plugin_dir"
|
||
mkdir -p "$install_root"
|
||
chmod 777 "$install_root"
|
||
local extern_exe_path=$(realpath "${executable}")
|
||
local extern_exe_dir=$(dirname "${extern_exe_path}")
|
||
local extern_qt_platform_dir="${qt_plugin_dir}/platforms"
|
||
local exe_path="${install_root}${extern_exe_path}"
|
||
local exe_dir="${install_root}${extern_exe_dir}"
|
||
local qt_dir="${install_root}${extern_qt_dir}"
|
||
local qt_platform_dir="${install_root}${extern_qt_platform_dir}"
|
||
|
||
copy_dependencies "${executable}:${extern_qt_platform_dir}" "${install_root}"
|
||
ln -sf ".$extern_exe_path" "$install_root/$(basename "$extern_exe_path")"
|
||
get_relative_path "${extern_exe_dir}" "${extern_qt_platform_dir}"
|
||
ln -sf "${_ret_}" "${exe_dir}/platforms"
|
||
|
||
|
||
|
||
local linker_path=$(which ldd)
|
||
|
||
if [ -z "$linker_path" ]; then
|
||
echo "链接器路径未找到。"
|
||
exit 1
|
||
else
|
||
echo "链接器路径 ${linker_path}"
|
||
fi
|
||
|
||
# 使用 cp 拷贝链接器到目标目录
|
||
cp_with_symlink "$linker_path" "${install_root}"
|
||
|
||
|
||
ln -sf ".$linker_path" "$install_root/$(basename "$linker_path")"
|
||
echo "链接器已拷贝到 ${install_root} 1111 ${_ret_}"
|
||
|
||
|
||
compress_directory_tar_gz "$install_root" "$(dirname "$2")" "$(basename "$2").tar.gz"
|
||
}
|
||
|
||
# 此函数获取系统链接器配置文件里写的路径
|
||
get_etc_ld_so_config_paths() {
|
||
local ld_paths=()
|
||
while read -r line; do
|
||
# 排除注释行
|
||
if [[ -n "$line" && "$line" != \#* && -d "$line" ]]; then
|
||
ld_paths+=("$line")
|
||
fi
|
||
done < <(grep -v '^#' /etc/ld.so.conf)
|
||
local conf_file
|
||
for conf_file in /etc/ld.so.conf.d/*; do
|
||
while read -r line; do
|
||
if [[ -n "$line" && "$line" != \#* && -d "$line" ]]; then
|
||
ld_paths+=("$line")
|
||
fi
|
||
done < <(grep -v '^#' "$conf_file")
|
||
done
|
||
local combined_paths=""
|
||
for path in "${ld_paths[@]}"; do
|
||
combined_paths+="${path}:"
|
||
done
|
||
combined_paths="${combined_paths%:}"
|
||
|
||
_ret_="$combined_paths"
|
||
echo "系统配置文件找库路径:$combined_paths" >>"${_cur_log_path_}"
|
||
}
|
||
|
||
set_all_runpath() {
|
||
local dir="$1" # 根目录
|
||
get_etc_ld_so_config_paths
|
||
list_append_element "$_ret_" "/lib64:/usr/lib64"
|
||
if [ -n "$LD_LIBRARY_PATH" ]; then
|
||
list_prepend_element "$_ret_" "$LD_LIBRARY_PATH"
|
||
fi
|
||
local base_path_list="$_ret_"
|
||
printf "set_all_runpath base_path_list== \n%s\n" "$base_path_list" | tr ':' '\n'
|
||
_set_all_runpath() {
|
||
local dir="$1" # 根目录
|
||
local prefix="$2" # 当前深度
|
||
prefix=${prefix:-"\$ORIGIN"}
|
||
list_prepend_all_element "$base_path_list" "$prefix"
|
||
local item
|
||
for item in "$dir"/*; do
|
||
if [ -d "$item" ]; then
|
||
_set_all_runpath "$item" "${prefix}/.."
|
||
elif [[ "$item" == *.so* ]]; then
|
||
$(echo "")
|
||
#patchelf --set-rpath "$_ret_" "$item"
|
||
fi
|
||
done
|
||
}
|
||
_set_all_runpath "$dir"
|
||
}
|
||
|
||
return 0 |