373 lines
8.7 KiB
Bash
373 lines
8.7 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]}" ../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!"
|
||
} |