From c4217a8aa6139584aa214e5bbf0337395741ef22 Mon Sep 17 00:00:00 2001 From: evgeny Date: Tue, 6 Oct 2026 15:44:58 +0200 Subject: [PATCH] Verify runtime dependencies and deploy matching Qt plugins every build --- tools/chatgui/build.sh | 45 +++++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/tools/chatgui/build.sh b/tools/chatgui/build.sh index be5f7678..7a57bace 100755 --- a/tools/chatgui/build.sh +++ b/tools/chatgui/build.sh @@ -13,6 +13,7 @@ log "" SRC_DIR="$(cd "$(dirname "$0")" && pwd)" BUILD_DIR="$SRC_DIR/build" +RUNTIME_PREFIX="${MSYSTEM_PREFIX:-/ucrt64}" log "Source: $SRC_DIR" log "Build: $BUILD_DIR" @@ -29,7 +30,7 @@ fi # Старые DLL приложения в build могут мешать запуску cc1/cc1plus после обновления MSYS2. source "$SRC_DIR/compiler_runtime.sh" if [ "${MSYSTEM:-}" = UCRT64 ]; then - chatgui_refresh_compiler_runtime "$BUILD_DIR" /ucrt64/bin 2>&1 | tee -a "$LOG_FILE" + chatgui_refresh_compiler_runtime "$BUILD_DIR" "$RUNTIME_PREFIX/bin" 2>&1 | tee -a "$LOG_FILE" log "Preparing bundled rlottie..." cmake -S "$SRC_DIR/rlottie_src" -B "$SRC_DIR/rlottie_build" -G Ninja \ -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON 2>&1 | tee -a "$LOG_FILE" || { @@ -69,7 +70,8 @@ case "$QT_PACKAGE" in esac log " Runtime package: $QT_PACKAGE" MAIN_DLLS=( - "Qt${QT_MAJOR}Core.dll" "Qt${QT_MAJOR}Gui.dll" "Qt${QT_MAJOR}Network.dll" "Qt${QT_MAJOR}Widgets.dll" "platforms/qwindows.dll" + "Qt${QT_MAJOR}Core.dll" "Qt${QT_MAJOR}Gui.dll" "Qt${QT_MAJOR}Network.dll" "Qt${QT_MAJOR}Widgets.dll" + "platforms/qwindows.dll" "imageformats/qjpeg.dll" "libstdc++-6.dll" "libgcc_s_*.dll" "libwinpthread-1.dll" "librlottie.dll" "zlib1.dll" "libcrypto-*.dll" ) if [ -d "$FFMPEG_BIN" ]; then @@ -83,11 +85,11 @@ for d in "${MAIN_DLLS[@]}"; do break fi done -if [ "$DLLS_PRESENT" -eq 1 ]; then - log " SKIP: main runtime DLLs already present; recursive dependency scan skipped" -else +[ "$DLLS_PRESENT" -ne 1 ] || log " Main runtime DLLs present; verifying their dependencies" +# Проверяем зависимости на каждом запуске: основные DLL не гарантируют полный комплект. +{ WINDEPLOYQT="" - for candidate in "/ucrt64/bin/windeployqt${QT_MAJOR}.exe" "/ucrt64/bin/windeployqt-qt${QT_MAJOR}.exe" /ucrt64/bin/windeployqt.exe; do + for candidate in "$RUNTIME_PREFIX/bin/windeployqt${QT_MAJOR}.exe" "$RUNTIME_PREFIX/bin/windeployqt-qt${QT_MAJOR}.exe" "$RUNTIME_PREFIX/bin/windeployqt.exe"; do [ -x "$candidate" ] || continue tool_version=$("$candidate" --version 2>&1) || { log " WARN: cannot query $candidate: $tool_version"; continue; } if [[ "$tool_version" =~ (^|[[:space:]])${QT_MAJOR}\.[0-9]+ ]]; then WINDEPLOYQT="$candidate"; break; fi @@ -106,6 +108,22 @@ else log " WARN: matching $QT_PACKAGE windeployqt not found; copying dependencies directly" fi + # Основные Qt DLL и динамические плагины всегда берём из выбранного комплекта. + for component in Core Gui Network Widgets; do + qt_dll="Qt${QT_MAJOR}${component}.dll" + cp "$RUNTIME_PREFIX/bin/$qt_dll" "$BUILD_DIR/" || { log " ERROR: cannot deploy $qt_dll from $RUNTIME_PREFIX/bin"; exit 1; } + done + for plugin in platforms/qwindows.dll imageformats/qjpeg.dll; do + plugin_source="" + for dir in "$RUNTIME_PREFIX/share/qt${QT_MAJOR}/plugins" "$RUNTIME_PREFIX/lib/qt${QT_MAJOR}/plugins"; do + [ -f "$dir/$plugin" ] && { plugin_source="$dir/$plugin"; break; } + done + [ -n "$plugin_source" ] || { log " ERROR: $QT_PACKAGE plugin missing: $plugin"; exit 1; } + mkdir -p "$BUILD_DIR/${plugin%/*}" + cp "$plugin_source" "$BUILD_DIR/$plugin" || { log " ERROR: cannot deploy $plugin_source"; exit 1; } + log " OK: $plugin (from $plugin_source)" + done + # Резолвим НЕ-Qt зависимости (FFmpeg, mingw-runtime): windeployqt копирует только Qt. # FFmpeg ищем ПЕРВЫМ в $FFMPEG_BIN: exe линкован именно под кастомный билд, # а pacman-ffmpeg той же мажорной версии в /ucrt64/bin дал бы неверный набор кодеков. @@ -116,14 +134,14 @@ else for src in "$FFMPEG_BIN/"*.dll; do # Общий runtime берём из установленного UCRT64, а кодеки — из собственной сборки FFmpeg. if chatgui_is_compiler_runtime_dll "${src##*/}"; then - src="/ucrt64/bin/${src##*/}" + src="$RUNTIME_PREFIX/bin/${src##*/}" fi cp "$src" "$BUILD_DIR/" || { log " ERROR: failed to copy $src"; exit 1; } log " OK: $(basename "$src") (from $src)" done log " Resolving non-Qt dependencies recursively..." # Проверяем также уже скопированные DLL: наличие файла не гарантирует наличие его зависимостей. - todo=("$BUILD_DIR/vibechat.exe" "$BUILD_DIR/"*.dll) + todo=("$BUILD_DIR/vibechat.exe" "$BUILD_DIR/"*.dll "$BUILD_DIR/platforms/"*.dll "$BUILD_DIR/imageformats/"*.dll) declare -A scanned=() MISSING=0 # Большой вывод objdump передаём через файл, чтобы не зависеть от here-string и pipe в MSYS2. @@ -167,9 +185,9 @@ else esac if [ ! -f "$BUILD_DIR/$dep" ]; then dep_src="" - dep_dirs=("$FFMPEG_BIN" /ucrt64/bin "$SRC_DIR/rlottie_build") + dep_dirs=("$FFMPEG_BIN" "$RUNTIME_PREFIX/bin" "$SRC_DIR/rlottie_build") if chatgui_is_compiler_runtime_dll "$dep"; then - dep_dirs=(/ucrt64/bin) + dep_dirs=("$RUNTIME_PREFIX/bin") fi for dir in "${dep_dirs[@]}"; do if [ -f "$dir/$dep" ]; then @@ -190,11 +208,6 @@ else done shopt -u nocasematch nullglob [ "$MISSING" -eq 0 ] || { log " ERROR: runtime DLL deployment incomplete"; exit 1; } - # Qt platform plugin (loaded dynamically, not in import table) - mkdir -p "$BUILD_DIR/platforms" - for d in "/ucrt64/share/qt${QT_MAJOR}/plugins" "/ucrt64/lib/qt${QT_MAJOR}/plugins"; do - cp "$d/platforms/qwindows.dll" "$BUILD_DIR/platforms/" 2>/dev/null && break - done # Проверяем тот же основной комплект после копирования. log " Verifying main runtime DLLs..." MISSING=0 @@ -206,7 +219,7 @@ else if [ "$MISSING" -eq 1 ]; then log " ERROR: required runtime DLLs missing"; exit 1 fi -fi +} cp "$SRC_DIR/setup_firewall.bat" "$BUILD_DIR/" 2>/dev/null && log " OK: setup_firewall.bat" || log " WARN: setup_firewall.bat not found" log ""