#!/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_target_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