Files
build_toochain/linux_shell/build_script/base/deploy.bash
T
2026-08-13 09:31:12 +08:00

402 lines
13 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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