Files
build_toochain/linux_shell/build_script/patch/patch.bash
T
2026-07-07 15:23:39 +08:00

373 lines
8.7 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]}" ../base/export.bash
false && source ../base/export.bash
insert_after_match() {
local file="$1"
local pattern="$2"
local insert_content="$3"
if [[ ! -f "$file" ]]; then
echo "File not found: $file"
return 75
fi
local tmp="${file}.tmp"
# 使用 awk 插入(比 sed 更稳) awk 是拓展正则表达式 \(是字面量
echo "insert_content ${insert_content}"
awk -v pat="$pattern" -v block="$insert_content" '
{
print
if ($0 ~ pat && inserted != 1) {
print block
inserted=1
}
}
END {
if (inserted == 1)
exit 0
else
exit 100
}
' "$file" >"$tmp"
rc=$?
if [[ $rc -eq 0 ]]; then
mv "$tmp" "$file"
echo "插入成功!"
return 0
else
rm -f "$tmp"
echo "插入失败没找到"
return 76
fi
}
_collect_files() {
local path_list="$1"
local exclude_list="$2"
local -n out_files="$3"
local -n out_skipped="$4"
local paths=()
local excludes=()
local path=""
local file=""
local ex=""
out_files=()
out_skipped=()
IFS=',' read -ra paths <<< "$path_list"
IFS=',' read -ra excludes <<< "$exclude_list"
for path in "${paths[@]}"; do
[[ -z "$path" ]] && continue
if [[ -f "$path" ]]; then
local skip=0
for ex in "${excludes[@]}"; do
[[ -z "$ex" ]] && continue
if [[ "$path" == "$ex" ]] || \
[[ "$(basename "$path")" == "$ex" ]] || \
[[ "$path" == $ex ]]; then
skip=1
break
fi
if [[ -d "$ex" ]]; then
[[ "$path" == "$ex" || "$path" == "$ex"/* ]] && skip=1 && break
fi
done
if [[ $skip -eq 1 ]]; then
out_skipped+=("$path")
else
out_files+=("$path")
fi
elif [[ -d "$path" ]]; then
while IFS= read -r -d '' file; do
local skip=0
for ex in "${excludes[@]}"; do
[[ -z "$ex" ]] && continue
if [[ "$file" == "$ex" ]] || \
[[ "$(basename "$file")" == "$ex" ]] || \
[[ "$file" == $ex ]]; then
skip=1
break
fi
if [[ -d "$ex" ]]; then
[[ "$file" == "$ex" || "$file" == "$ex"/* ]] && skip=1 && break
fi
done
if [[ $skip -eq 1 ]]; then
out_skipped+=("$file")
else
out_files+=("$file")
fi
done < <(find "$path" -type f -print0)
else
echo "WARNING: path not found, skip: $path"
fi
done
}
sed_in_tree() {
local path_list="$1"
local search_str="$2"
local replace_str="$3"
local exclude_list="$4"
local files=()
local skipped=()
_collect_files "$path_list" "$exclude_list" files skipped
[[ -z "$search_str" ]] && {
log_error "search_str is empty"
return 1
}
# ================= sed 替换规则说明 =================
# sed 替换基本格式:
# s<分隔符>pattern<分隔符>replacement<分隔符>flags
# --------------------------------------------------
# 一、分隔符(delimiter
#
# - 可以自定义为任意“单个字符”
# - 常见:/ | # @
# - 如果分隔符出现在 pattern 或 replacement 中,必须转义
#
# 示例:
# s|/home/user|/tmp|g # 推荐(避免转义 /)
#
# --------------------------------------------------
# 二、pattern(左边:正则表达式)
#
# 默认是 BRE(基本正则)
#
# 特殊字符:
# . 任意字符
# * 重复
# ^ 行首
# $ 行尾
# [ ] 字符集合
# \ 转义符
#
# 如果要匹配字面值,需要转义:
# a.b -> a\.b
#
# --------------------------------------------------
# 三、replacement(右边:替换内容)
#
# 特殊符号:
# & 代表“整个匹配内容”
# \1 第1个分组
# \2 第2个分组
# \ 转义符
#
# 示例:
# s/b/&X/ -> b 变成 bX
#
# 如果要替换成字面 &
# \&
#
# --------------------------------------------------
# 四、分隔符冲突
#
# 如果你用:
# s|xxx|yyy|
#
# 那么:
# | 出现在内容里必须写成 \|
#
# --------------------------------------------------
# 五、shell 层注意(非常重要)
#
# 在 bash 中:
# sed "s|$search|$replace|g"
#
# 实际有三层解析:
# 1. shell 变量展开
# 2. sed pattern(正则)
# 3. sed replacement(特殊符号)
#
# 风险:
# - pattern 被当正则(. * 等会生效)
# - replacement 中 & 会被替换
# - 分隔符冲突导致报错
#
# --------------------------------------------------
# 六、结论
#
# - sed 转义符是:\
# - 左边是正则,右边是替换语法
# - 分隔符可以自定义,但要避免冲突
#
# ==================================================
printf '%s\0' "${files[@]}" | xargs -0 sed -i "s|${search_str}|${replace_str}|g"
log_debug "-----------------------------------"
log_debug "$search_str】 替换为 【$replace_str"
log_debug "Files : ${#files[@]}"
log_debug "Files skipped : ${#skipped[@]}"
}
#gen_pth my.pth \
# "D:\wyc\env\...\python3.12" \
# "D:\wyc\env\...\lib-dynload"
gen_python_pth() {
local pth_file="$1"
shift
if [ -z "$pth_file" ] || [ "$#" -eq 0 ]; then
log_warn "Usage: gen_python_pth <output.pth> <path1> [path2 ...]" >&2
return 1
fi
local pth_dir
pth_dir="$(cd "$(dirname "$pth_file")" 2>/dev/null && pwd)"
if [ -z "$pth_dir" ]; then
log_error "Error: cannot resolve pth file directory: $pth_file" >&2
return 1
fi
local p resolved
# 先检查,全部通过后再写文件,避免生成半截内容
for p in "$@"; do
case "$p" in
/*|[A-Za-z]:[\\/]*)
# 绝对路径:Linux /xxx 或 Windows C:\xxx / C:/xxx
resolved="$p"
;;
*)
# 相对路径:相对于 .pth 文件所在目录
resolved="$pth_dir/$p"
;;
esac
if [ ! -d "$resolved" ]; then
log_error "Error: directory does not exist: $p" >&2
log_error " resolved path: $resolved" >&2
return 1
fi
done
: > "$pth_file" || {
log_error "Error: cannot write to $pth_file" >&2
return 1
}
for p in "$@"; do
echo "$p" >> "$pth_file"
done
log_debug "Generated $pth_file"
}
# /ae/bash/gcc/env/win_arm_kylin_930/sysroot/usr/lib/aarch64-linux-gnu/cmake
# sysroot/usr/lib/aarch64-linux-gnu/cmake
patch_system_qt5(){
local SYSROOT="${1}"
local CMAKE_DIR="${2}"
local qt_host_tool_dir="${3}"
check_directory_var qt_host_tool_dir
check_file_ex "传入的qt_host_tool_dir不对,不包含必须文件moc.exe" "${qt_host_tool_dir}/moc.exe"
local dest="${SYSROOT}/usr/lib/qt5/bin"
check_and_create_dir_var dest
cp -r "${qt_host_tool_dir}/"* "${dest}"
check_directory "${SYSROOT}"
check_directory "${CMAKE_DIR}"
local CMAKE_CURRENT_LIST_DIR="${CMAKE_DIR}/Qt5"
check_directory "${CMAKE_CURRENT_LIST_DIR}"
local exclude_list="${CMAKE_CURRENT_LIST_DIR}/Qt5Config.cmake"
local Qt5WidgetsConfigExtras="${CMAKE_DIR}/Qt5Widgets/Qt5WidgetsConfigExtras.cmake"
check_file_var Qt5WidgetsConfigExtras
sed_in_tree \
"${Qt5WidgetsConfigExtras}" \
'bin/uic"' \
'bin/uic.exe"' \
""
local Qt5CoreConfigExtras="${CMAKE_DIR}/Qt5Core/Qt5CoreConfigExtras.cmake"
check_file_var Qt5CoreConfigExtras
sed_in_tree \
"${Qt5CoreConfigExtras}" \
'bin/rcc"' \
'bin/rcc.exe"' \
""
sed_in_tree \
"${Qt5CoreConfigExtras}" \
'bin/moc"' \
'bin/moc.exe"' \
""
#
# sed_in_tree \
# "${Qt5CoreConfigExtras}" \
# 'bin/qmake"' \
# 'bin/qmake.exe"' \
# ""
local QT5_DIR_LIST=""
for d in "$CMAKE_DIR"/Qt5*; do
[[ -d "$d" ]] || continue
QT5_DIR_LIST+="${d},"
done
QT5_DIR_LIST="${QT5_DIR_LIST%,}"
sed_in_tree \
"${QT5_DIR_LIST}" \
'"/usr' \
'"${_psc_sys_root}/usr' \
"${exclude_list}"
local rel_path=$(realpath --relative-to="${CMAKE_CURRENT_LIST_DIR}" "${SYSROOT}")
insert_after_match \
"${CMAKE_DIR}/Qt5/Qt5Config.cmake" \
'get_filename_component[(]_qt5_install_prefix.*[)]' \
"
if(CMAKE_SYSROOT)
set(_psc_sys_root \"\${CMAKE_SYSROOT}\")
message(STATUS \"CMAKE_SYSROOT:psc_sys_root = \${_psc_sys_root} at \${CMAKE_CURRENT_LIST_FILE} \")
else()
set(_psc_sys_root \${CMAKE_CURRENT_LIST_DIR}/${rel_path})
message(STATUS \"psc_sys_root = \${_psc_sys_root} at \${CMAKE_CURRENT_LIST_FILE} \")
endif()
"
log_info "patch_system_qt end!"
}