You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

203 lines
8.8 KiB

#!/bin/bash
set -eo pipefail
LOG_FILE="build_win.log"
> "$LOG_FILE"
log() { echo "$1"; echo "$1" >> "$LOG_FILE"; }
log "================================"
log "ChatGUI Build Script (MSYS2 UCRT64)"
log "================================"
log ""
SRC_DIR="$(cd "$(dirname "$0")" && pwd)"
BUILD_DIR="$SRC_DIR/build"
log "Source: $SRC_DIR"
log "Build: $BUILD_DIR"
log ""
if [ -f "$BUILD_DIR/CMakeCache.txt" ]; then
OLD_GEN=$(grep 'CMAKE_GENERATOR:' "$BUILD_DIR/CMakeCache.txt" 2>/dev/null | cut -d= -f2)
if [ "$OLD_GEN" != "Ninja" ]; then
log "Generator changed ($OLD_GEN -> Ninja), cleaning build dir..."
rm -rf "$BUILD_DIR"
fi
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"
fi
log "[1/4] Configuring CMake (generator: Ninja)..."
cmake -S "$SRC_DIR" -B "$BUILD_DIR" -G Ninja 2>&1 | tee -a "$LOG_FILE"
test ${PIPESTATUS[0]} -eq 0 || { log "CMake configure FAILED"; exit 1; }
log ""
JOBS=$(nproc 2>/dev/null || echo 4)
log "[2/4] Building (parallel: $JOBS jobs)..."
cmake --build "$BUILD_DIR" -j"$JOBS" 2>&1 | tee -a "$LOG_FILE"
test ${PIPESTATUS[0]} -eq 0 || { log "Build FAILED"; exit 1; }
log ""
log "[3/4] Deploying runtime DLLs..."
RLOTTIE_DLL="$SRC_DIR/rlottie_build/librlottie.dll"
[ -f "$RLOTTIE_DLL" ] || { log " ERROR: librlottie.dll not found: $RLOTTIE_DLL"; exit 1; }
cp "$RLOTTIE_DLL" "$BUILD_DIR/librlottie.dll" || {
log " ERROR: cannot copy $RLOTTIE_DLL -> $BUILD_DIR/librlottie.dll"; exit 1;
}
log " OK: librlottie.dll (from $RLOTTIE_DLL; copied to $BUILD_DIR/librlottie.dll)"
FFMPEG_BIN="$SRC_DIR/ffmpeg/ffmpeg_build/install/bin"
MAIN_DLLS=(
"Qt[56]Core.dll" "Qt[56]Gui.dll" "Qt[56]Network.dll" "Qt[56]Widgets.dll" "platforms/qwindows.dll"
"libstdc++-6.dll" "libgcc_s_*.dll" "libwinpthread-1.dll" "librlottie.dll" "zlib1.dll" "libcrypto-*.dll"
)
if [ -d "$FFMPEG_BIN" ]; then
MAIN_DLLS+=("avcodec-*.dll" "avformat-*.dll" "avutil-*.dll" "swscale-*.dll" "swresample-*.dll")
fi
DLLS_PRESENT=1
for d in "${MAIN_DLLS[@]}"; do
if ! compgen -G "$BUILD_DIR/$d" >/dev/null; then
log " Main DLL missing: $d; deploying runtime DLLs"
DLLS_PRESENT=0
break
fi
done
if [ "$DLLS_PRESENT" -eq 1 ]; then
log " SKIP: main runtime DLLs already present; recursive dependency scan skipped"
else
WINDEPLOYQT="/ucrt64/bin/windeployqt"
if [ -x "$WINDEPLOYQT" ]; then
log " Running $WINDEPLOYQT..."
"$WINDEPLOYQT" --no-translations --no-compiler-runtime "$BUILD_DIR/vibechat.exe" 2>&1 | tee -a "$LOG_FILE"
RC=${PIPESTATUS[0]}
if [ $RC -eq 0 ]; then
log " OK: windeployqt completed"
else
log " WARN: windeployqt failed (exit $RC)"
fi
else
log " WARN: $WINDEPLOYQT not found (install: pacman -S mingw-w64-ucrt-x86_64-qt5-tools)"
fi
# Резолвим НЕ-Qt зависимости (FFmpeg, mingw-runtime): windeployqt копирует только Qt.
# FFmpeg ищем ПЕРВЫМ в $FFMPEG_BIN: exe линкован именно под кастомный билд,
# а pacman-ffmpeg той же мажорной версии в /ucrt64/bin дал бы неверный набор кодеков.
OBJDUMP="objdump"; [ -n "${MSYSTEM_PREFIX:-}" ] && OBJDUMP="$MSYSTEM_PREFIX/bin/objdump"
command -v "$OBJDUMP" >/dev/null 2>&1 || { log " ERROR: $OBJDUMP not found"; exit 1; }
shopt -s nocasematch nullglob
# Обновляем весь комплект FFmpeg, включая DLL, не импортируемые напрямую приложением.
for src in "$FFMPEG_BIN/"*.dll; do
# Общий runtime берём из установленного UCRT64, а кодеки — из собственной сборки FFmpeg.
if chatgui_is_compiler_runtime_dll "${src##*/}"; then
src="/ucrt64/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)
declare -A scanned=()
MISSING=0
# Большой вывод objdump передаём через файл, чтобы не зависеть от here-string и pipe в MSYS2.
IMPORT_DUMP=$(mktemp) || {
log " ERROR: cannot create temporary file for DLL inspection"
exit 1
}
trap 'rm -f -- "$IMPORT_DUMP" || log " WARN: cannot remove temporary import dump: $IMPORT_DUMP"' EXIT
for ((i = 0; i < ${#todo[@]}; i++)); do
src="${todo[i]}"
key="${src,,}"
[ -n "${scanned[$key]:-}" ] && continue
scanned[$key]=1
CHECK_STARTED=$SECONDS
"$OBJDUMP" -p "$src" > "$IMPORT_DUMP" 2>&1 || {
RC=$?
log " ERROR: cannot inspect $src (exit=$RC, elapsed=$((SECONDS - CHECK_STARTED))s): $(cat "$IMPORT_DUMP")"
MISSING=$((MISSING + 1))
continue
}
PARSE_STARTED=$SECONDS
import_list=$(awk '/DLL Name:/ {print $3}' "$IMPORT_DUMP" 2>&1) || {
RC=$?
log " ERROR: cannot parse imports for $src (exit=$RC, elapsed=$((SECONDS - PARSE_STARTED))s): $import_list"
MISSING=$((MISSING + 1))
continue
}
while read -r dep; do
[ -z "$dep" ] && continue
case "$dep" in
kernel32.dll|msvcrt.dll|msvcp140.dll|vcruntime140.dll|ucrtbase.dll|\
user32.dll|gdi32.dll|gdi32full.dll|shell32.dll|shlwapi.dll|advapi32.dll|\
ole32.dll|oleaut32.dll|comdlg32.dll|comctl32.dll|ws2_32.dll|wsock32.dll|\
iphlpapi.dll|netapi32.dll|dnsapi.dll|winmm.dll|imm32.dll|version.dll|\
setupapi.dll|crypt32.dll|bcrypt.dll|bcryptprimitives.dll|ncrypt.dll|dbghelp.dll|imagehlp.dll|kernelbase.dll|\
rpcrt4.dll|psapi.dll|powrprof.dll|cfgmgr32.dll|userenv.dll|secur32.dll|\
uxtheme.dll|dwmapi.dll|d3d11.dll|dxgi.dll|opengl32.dll|glu32.dll|\
wtsapi32.dll|mpr.dll|ntdll.dll|avicap32.dll|msimg32.dll|wldap32.dll|gdiplus.dll|usp10.dll|\
dwrite.dll|winspool.drv|api-ms-win-*)
continue ;;
esac
if [ ! -f "$BUILD_DIR/$dep" ]; then
dep_src=""
dep_dirs=("$FFMPEG_BIN" /ucrt64/bin "$SRC_DIR/rlottie_build")
if chatgui_is_compiler_runtime_dll "$dep"; then
dep_dirs=(/ucrt64/bin)
fi
for dir in "${dep_dirs[@]}"; do
if [ -f "$dir/$dep" ]; then
dep_src="$dir/$dep"
break
fi
done
if [ -z "$dep_src" ]; then
log " ERROR: $src requires $dep; not found in FFmpeg, UCRT64 or rlottie directories"
MISSING=$((MISSING + 1))
continue
fi
cp "$dep_src" "$BUILD_DIR/" || { log " ERROR: failed to copy $dep_src"; exit 1; }
log " OK: $dep (from $dep_src; required by $src)"
fi
todo+=("$BUILD_DIR/$dep")
done <<< "$import_list"
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/qt5/plugins /ucrt64/lib/qt5/plugins; do
cp "$d/platforms/qwindows.dll" "$BUILD_DIR/platforms/" 2>/dev/null && break
done
# Проверяем тот же основной комплект после копирования.
log " Verifying main runtime DLLs..."
MISSING=0
for d in "${MAIN_DLLS[@]}"; do
if ! compgen -G "$BUILD_DIR/$d" >/dev/null; then
log " WARN: $d MISSING in build dir"; MISSING=1
fi
done
if [ "$MISSING" -eq 1 ]; then
log " WARN: some main runtime DLLs missing — app may not start"
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 ""
log "[4/4] Verifying..."
EXE="$BUILD_DIR/vibechat.exe"
if [ -f "$EXE" ]; then
SIZE=$(du -h "$EXE" | cut -f1)
log " OK: vibechat.exe ($SIZE)"
log ""
log "================================"
log "Build SUCCESS"
log "================================"
log "Executable: $EXE"
else
log " FAIL: vibechat.exe not found"
exit 1
fi