diff --git a/tools/chatgui/build.sh b/tools/chatgui/build.sh index 7ac09655a..57e85f185 100755 --- a/tools/chatgui/build.sh +++ b/tools/chatgui/build.sh @@ -79,16 +79,8 @@ test ${PIPESTATUS[0]} -eq 0 || { log "Build FAILED"; exit 1; } log "" log "[3/4] Deploying runtime DLLs..." DEPLOY_STARTED=$SECONDS -RUNTIME_CACHE="$BUILD_DIR/.runtime-cache" -RUNTIME_COPIED=0 RUNTIME_CURRENT=0 RUNTIME_SCANNED=0 RUNTIME_HITS=0 -declare -A RUNTIME_SOURCES=() RUNTIME_STAMPS=() source "$SRC_DIR/runtime_cache.sh" -OBJDUMP="objdump"; [ -n "${MSYSTEM_PREFIX:-}" ] && OBJDUMP="$MSYSTEM_PREFIX/bin/objdump" -OBJDUMP=$(command -v "$OBJDUMP") || { log " ERROR: objdump not found"; exit 1; } -CACHE_POLICY=$(sha256sum "$SRC_DIR/build.sh" "$SRC_DIR/runtime_cache.sh" "$SRC_DIR/compiler_runtime.sh" | sha256sum) || { - log " ERROR: cannot fingerprint deployment scripts"; exit 1; -} -CACHE_POLICY+="|$(stat -Lc '%n|%s|%y|%z' -- "$OBJDUMP")" || { log " ERROR: cannot stat $OBJDUMP"; exit 1; } +runtime_cache_init IMPORT_DUMP=$(mktemp) || { log " ERROR: cannot create temporary import dump"; exit 1; } trap 'rm -f -- "$IMPORT_DUMP" || log " WARN: cannot remove temporary import dump: $IMPORT_DUMP"' EXIT # Повторная сборка восстанавливает DLL, даже если EXE не перелинковывался. @@ -132,7 +124,7 @@ done [ "$DLLS_PRESENT" -ne 1 ] || log " Main runtime DLLs present; verifying their dependencies" # Проверяем зависимости на каждом запуске: основные DLL не гарантируют полный комплект. { - runtime_imports "$BUILD_DIR/vibechat.exe" + runtime_inspect "$BUILD_DIR/vibechat.exe" EXE_IMPORTS="$import_list" QT_SOURCES=() declare -A QT_PLUGIN_SOURCES=() @@ -237,7 +229,7 @@ done continue fi fi - runtime_imports "$src" || { MISSING=$((MISSING + 1)); continue; } + runtime_inspect "$src" || { MISSING=$((MISSING + 1)); continue; } fi while read -r dep; do [ -z "$dep" ] && continue diff --git a/tools/chatgui/runtime_cache.sh b/tools/chatgui/runtime_cache.sh index 13305c7d7..8b4cf186c 100644 --- a/tools/chatgui/runtime_cache.sh +++ b/tools/chatgui/runtime_cache.sh @@ -1,7 +1,21 @@ #!/bin/bash -# Кеш раскладки Windows DLL: метаданные копий и PE-импорты. Подключается из build.sh. +# Общий кеш build.sh/package_win.sh: метаданные копий, формат PE и импорты. # CACHE_POLICY меняется при изменении скриптов/objdump; ошибки не публикуют готовую запись. +# Обоим скриптам нужны одинаковые objdump и версия кеша. IMPORT_DUMP задаёт вызывающий код. +runtime_cache_init() { + RUNTIME_CACHE="$BUILD_DIR/.runtime-cache" + RUNTIME_COPIED=0 RUNTIME_CURRENT=0 RUNTIME_SCANNED=0 RUNTIME_HITS=0 + declare -gA RUNTIME_SOURCES=() RUNTIME_STAMPS=() + OBJDUMP="${MSYSTEM_PREFIX:+$MSYSTEM_PREFIX/bin/}objdump" + OBJDUMP=$(command -v "$OBJDUMP") || { log " ERROR: objdump not found"; return 1; } + CACHE_POLICY=$(sha256sum "$SRC_DIR/build.sh" "$SRC_DIR/package_win.sh" "$SRC_DIR/runtime_cache.sh" \ + "$SRC_DIR/compiler_runtime.sh" | sha256sum) || { + log " ERROR: cannot fingerprint runtime scripts"; return 1; + } + CACHE_POLICY+="|$(stat -Lc '%n|%s|%y|%z' -- "$OBJDUMP")" || { log " ERROR: cannot stat $OBJDUMP"; return 1; } +} + runtime_cache_write() { local cache_file="$1" cache_data="$2" if ! mkdir -p "${cache_file%/*}" || ! printf '%s\n' "$cache_data" > "$cache_file.tmp" || @@ -50,10 +64,10 @@ runtime_copy() { log " Updated: ${copy_dst#"$BUILD_DIR/"} (from $copy_src)" } -# Возвращает список через import_list; вызывать без subshell, чтобы сохранить счётчики. +# Возвращает binary_format, binary_stamp и import_list; вызывать без subshell, чтобы сохранить счётчики. # Завершающая строка отличает полноценную запись с пустыми импортами от оборванной. -runtime_imports() { - local import_src="$1" import_stamp import_cached="" import_header import_started=$SECONDS import_rc +runtime_inspect() { + local import_src="$1" import_stamp import_cached="" import_header import_started=$SECONDS import_rc inspection local import_cache="$RUNTIME_CACHE/imports/${1#"$BUILD_DIR/"}" # runtime_copy уже проверил метаданные этой копии; не запускаем stat второй раз. import_stamp=${RUNTIME_STAMPS[${import_src,,}]:-} @@ -62,10 +76,13 @@ runtime_imports() { log " ERROR: cannot stat PE file: $import_src"; return 1; } fi + binary_stamp="$import_stamp" import_header="$CACHE_POLICY|$import_stamp" [ ! -f "$import_cache" ] || import_cached=$(< "$import_cache") - if [[ "$import_cached" == "$import_header"$'\n'*$'\nEND' ]]; then - import_list=${import_cached#*$'\n'} + if [[ "$import_cached" == "$import_header"$'\nFORMAT '*$'\n'*$'\nEND' ]]; then + inspection=${import_cached#*$'\nFORMAT '} + binary_format=${inspection%%$'\n'*} + import_list=${inspection#*$'\n'} import_list=${import_list%$'\nEND'} RUNTIME_HITS=$((RUNTIME_HITS + 1)) return 0 @@ -75,9 +92,20 @@ runtime_imports() { log " ERROR: cannot inspect $import_src (exit=$import_rc, elapsed=$((SECONDS - import_started))s): $(cat "$IMPORT_DUMP")" return 1 } - import_list=$(awk '/DLL Name:/ {print $3}' "$IMPORT_DUMP") || { - log " ERROR: cannot parse PE imports: $import_src"; return 1; + # objdump -p уже выводит file format; отдельный objdump -f не нужен. + inspection=$(awk '{sub(/\r$/, "")} /file format/ {format=$NF} /DLL Name:/ {imports=imports $3 "\n"} + END {if (format == "") exit 1; printf "%s\n%s", format, imports}' "$IMPORT_DUMP") || { + log " ERROR: cannot parse PE format/imports: $import_src"; return 1; } - runtime_cache_write "$import_cache" "$import_header"$'\n'"$import_list"$'\nEND' || return 1 + binary_format=${inspection%%$'\n'*} + import_list="" + [[ "$inspection" != *$'\n'* ]] || import_list=${inspection#*$'\n'} + import_stamp=$(stat -Lc '%n|%s|%y|%z' -- "$import_src") || { + log " ERROR: cannot stat inspected PE file: $import_src"; return 1; + } + if [ "$binary_stamp" != "$import_stamp" ]; then + log " ERROR: PE file changed during inspection: $import_src; rebuild and retry"; return 1; + fi + runtime_cache_write "$import_cache" "$import_header"$'\nFORMAT '"$binary_format"$'\n'"$import_list"$'\nEND' || return 1 RUNTIME_SCANNED=$((RUNTIME_SCANNED + 1)) }