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.
144 lines
7.5 KiB
144 lines
7.5 KiB
#!/usr/bin/env bash |
|
# Чистый комплект из Windows-сборки и Inno Setup; ключи/БД/логи из build не копируются. |
|
set -euo pipefail |
|
|
|
SRC_DIR=$(cd "$(dirname "$0")" && pwd) |
|
BUILD_DIR="$SRC_DIR/build" |
|
RUNTIME_PREFIX="${MSYSTEM_PREFIX:-/ucrt64}" |
|
STAGE="" |
|
trap 'rc=$?; if [[ $rc != 0 ]]; then echo "ERROR: installer packaging failed (exit=$rc)" >&2; fi |
|
if [[ -n "$STAGE" ]]; then rm -rf -- "$STAGE" || echo "WARN: cannot remove installer staging directory: $STAGE" >&2; fi' EXIT |
|
|
|
[[ "${MSYSTEM:-}" = UCRT64 ]] || { echo "ERROR: Windows installer requires MSYS2 UCRT64" >&2; exit 1; } |
|
[[ $# = 0 || ( $# = 1 && $1 = --check ) ]] || { echo "ERROR: usage: bash package_win.sh [--check]" >&2; exit 1; } |
|
for tool in cygpath objdump pacman; do |
|
command -v "$tool" >/dev/null || { echo "ERROR: required packaging tool not found: $tool" >&2; exit 1; } |
|
done |
|
|
|
if [[ -n "${ISCC:-}" ]]; then |
|
ISCC=$(cygpath -u "$ISCC") |
|
else |
|
ISCC=$(command -v ISCC.exe || command -v iscc.exe || true) |
|
if [[ -z "$ISCC" ]]; then |
|
for version in 7 6; do |
|
for variable in 'ProgramFiles(x86)' PROGRAMFILES 'ProgramFiles'; do |
|
program_dir=$(printenv "$variable" || true) |
|
[[ -n "$program_dir" ]] || continue |
|
candidate=$(cygpath -u "$program_dir/Inno Setup $version/ISCC.exe") |
|
if [[ -f "$candidate" ]]; then ISCC=$candidate; break 2; fi |
|
done |
|
[[ -z "$ISCC" ]] || break |
|
done |
|
fi |
|
fi |
|
[[ -n "$ISCC" && -f "$ISCC" ]] || { |
|
echo 'ERROR: Inno Setup 6.3+ not found; install it or set ISCC to the full path of ISCC.exe' >&2 |
|
exit 1 |
|
} |
|
echo "INFO: installer compiler: $ISCC" |
|
[[ "${1:-}" != --check ]] || exit 0 |
|
|
|
for file in vibechat.exe chatgui_version.txt chatgui_qt_package.txt; do |
|
[[ -f "$BUILD_DIR/$file" ]] || { echo "ERROR: missing build output: $BUILD_DIR/$file" >&2; exit 1; } |
|
done |
|
APP_VERSION=$(tr -d '\r\n' < "$BUILD_DIR/chatgui_version.txt") |
|
[[ "$APP_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || { echo "ERROR: invalid application version: $APP_VERSION" >&2; exit 1; } |
|
QT_PACKAGE=$(tr -d '\r\n' < "$BUILD_DIR/chatgui_qt_package.txt") |
|
[[ "$QT_PACKAGE" = Qt5 || "$QT_PACKAGE" = Qt6 ]] || { echo "ERROR: invalid Qt package: $QT_PACKAGE" >&2; exit 1; } |
|
for file in "${QT_PACKAGE}Core.dll" "${QT_PACKAGE}Gui.dll" "${QT_PACKAGE}Network.dll" "${QT_PACKAGE}Widgets.dll" \ |
|
librlottie.dll platforms/qwindows.dll imageformats/qjpeg.dll imageformats/qwebp.dll; do |
|
[[ -f "$BUILD_DIR/$file" ]] || { echo "ERROR: missing runtime file: $BUILD_DIR/$file" >&2; exit 1; } |
|
done |
|
|
|
STAGE=$(mktemp -d "$BUILD_DIR/installer-stage.XXXXXX") |
|
PACKAGE_DIR="$STAGE/package" |
|
mkdir -p "$PACKAGE_DIR/licenses" "$STAGE/output" "$BUILD_DIR/installer" |
|
shopt -s nullglob nocasematch |
|
for file in LICENSE LICENSING THIRD_PARTY_NOTICES; do |
|
cp "$SRC_DIR/../../$file" "$PACKAGE_DIR/licenses/" |
|
done |
|
mkdir -p "$PACKAGE_DIR/licenses/rlottie" |
|
cp "$SRC_DIR/rlottie_src/COPYING" "$PACKAGE_DIR/licenses/rlottie/" |
|
cp -R "$SRC_DIR/rlottie_src/licenses" "$PACKAGE_DIR/licenses/rlottie/" |
|
|
|
# Проверяем архитектуру/полноту уже собранного комплекта, включая динамические Qt-плагины. |
|
SYSTEM_DIR=$(cygpath -u "${WINDIR:-C:\\Windows}/System32") |
|
source "$SRC_DIR/compiler_runtime.sh" |
|
declare -A LICENSE_PACKAGES=() |
|
declare -A INCLUDED=() |
|
FILES=(vibechat.exe platforms/qwindows.dll imageformats/qjpeg.dll imageformats/qwebp.dll) |
|
HAS_FFMPEG=0 |
|
for ((i = 0; i < ${#FILES[@]}; i++)); do |
|
relative=${FILES[i]} |
|
[[ -z "${INCLUDED[${relative,,}]:-}" ]] || continue |
|
INCLUDED[${relative,,}]=1 |
|
name=${relative##*/} |
|
if [[ "$name" = Qt[56]*.dll && "$name" != "$QT_PACKAGE"*.dll ]]; then |
|
echo "ERROR: mixed Qt runtime: $relative does not belong to $QT_PACKAGE" >&2 |
|
exit 1 |
|
fi |
|
file="$PACKAGE_DIR/$relative" |
|
mkdir -p "${file%/*}" |
|
cp "$BUILD_DIR/$relative" "$file" |
|
name=${file##*/} |
|
objdump -f "$file" > "$STAGE/headers.txt" |
|
binary_format=$(awk '/file format/ {print $NF}' "$STAGE/headers.txt") |
|
[[ "$binary_format" = pei-x86-64 ]] || { echo "ERROR: $name is not a Windows x64 binary: $binary_format" >&2; exit 1; } |
|
objdump -p "$file" > "$STAGE/imports.txt" |
|
while read -r dep; do |
|
[[ -n "$dep" ]] || continue |
|
if [[ -f "$BUILD_DIR/$dep" ]]; then FILES+=("$dep"); continue; fi |
|
case "$dep" in api-ms-win-*.dll|ext-ms-win-*.dll) continue ;; esac |
|
if [[ -f "$SYSTEM_DIR/$dep" && "$dep" != msvcp*.dll && "$dep" != vcruntime*.dll ]]; then continue; fi |
|
echo "ERROR: incomplete installer runtime: $name requires $dep" >&2 |
|
exit 1 |
|
done < <(awk '/DLL Name:/ {print $3}' "$STAGE/imports.txt") |
|
echo "INFO: verified installer runtime: ${file#"$PACKAGE_DIR/"}" |
|
|
|
# Лицензии внешних библиотек берём из пакетов той же UCRT64-сборки. |
|
[[ "$name" != vibechat.exe && "$name" != librlottie.dll ]] || continue |
|
if [[ -f "$SRC_DIR/ffmpeg/ffmpeg_build/install/bin/$name" ]] && ! chatgui_is_compiler_runtime_dll "$name"; then |
|
HAS_FFMPEG=1 |
|
continue |
|
fi |
|
runtime_file="$RUNTIME_PREFIX/bin/$name" |
|
if [[ "$file" = "$PACKAGE_DIR/platforms/"* || "$file" = "$PACKAGE_DIR/imageformats/"* ]]; then |
|
relative=${file#"$PACKAGE_DIR/"} |
|
runtime_file="$RUNTIME_PREFIX/share/qt${QT_PACKAGE#Qt}/plugins/$relative" |
|
[[ -f "$runtime_file" ]] || runtime_file="$RUNTIME_PREFIX/lib/qt${QT_PACKAGE#Qt}/plugins/$relative" |
|
fi |
|
[[ -f "$runtime_file" ]] || { echo "ERROR: cannot identify runtime source for $name" >&2; exit 1; } |
|
pkg=$(pacman -Qqo "$runtime_file") |
|
[[ -n "$pkg" ]] || { echo "ERROR: no package owns runtime file: $runtime_file" >&2; exit 1; } |
|
LICENSE_PACKAGES["$pkg"]=1 |
|
done |
|
for pkg in "${!LICENSE_PACKAGES[@]}"; do |
|
pacman -Qql "$pkg" > "$STAGE/package-files.txt" |
|
while IFS= read -r file; do |
|
[[ "$file" = */share/licenses/* && -f "$file" ]] || continue |
|
relative=${file#*/share/licenses/} |
|
mkdir -p "$PACKAGE_DIR/licenses/runtime/${relative%/*}" |
|
cp "$file" "$PACKAGE_DIR/licenses/runtime/$relative" |
|
done < "$STAGE/package-files.txt" |
|
echo "INFO: included runtime license notices: $pkg" |
|
done |
|
if [[ "$HAS_FFMPEG" = 1 ]]; then |
|
FFMPEG_SOURCE="$SRC_DIR/ffmpeg/ffmpeg_build/src" |
|
[[ -f "$FFMPEG_SOURCE/ffmpeg/COPYING.GPLv3" ]] || { echo "ERROR: FFmpeg source license notices missing: $FFMPEG_SOURCE" >&2; exit 1; } |
|
# Сохраняем уведомления FFmpeg и его встроенных статических кодеков. |
|
for file in "$FFMPEG_SOURCE/"*/COPYING* "$FFMPEG_SOURCE/"*/LICENSE* "$FFMPEG_SOURCE/"*/PATENTS; do |
|
[[ -f "$file" ]] || continue |
|
relative=${file#"$FFMPEG_SOURCE/"} |
|
mkdir -p "$PACKAGE_DIR/licenses/ffmpeg/${relative%/*}" |
|
cp "$file" "$PACKAGE_DIR/licenses/ffmpeg/$relative" |
|
done |
|
fi |
|
|
|
echo "INFO: compiling VibeChat $APP_VERSION installer (Qt package: $QT_PACKAGE)" |
|
# MSYS2 не должен преобразовывать ключи /D и /O; пути передаём явно в Windows-формате. |
|
MSYS2_ARG_CONV_EXCL='*' "$ISCC" "/DAppVersion=$APP_VERSION" "/DPackageDir=$(cygpath -w "$PACKAGE_DIR")" \ |
|
"/O$(cygpath -w "$STAGE/output")" "$(cygpath -w "$SRC_DIR/installer/vibechat.iss")" |
|
INSTALLER_NAME="VibeChat-$APP_VERSION-win64-setup.exe" |
|
[[ -s "$STAGE/output/$INSTALLER_NAME" ]] || { echo "ERROR: compiler did not produce $INSTALLER_NAME" >&2; exit 1; } |
|
mv -f "$STAGE/output/$INSTALLER_NAME" "$BUILD_DIR/installer/$INSTALLER_NAME" |
|
echo "INFO: installer created: $BUILD_DIR/installer/$INSTALLER_NAME"
|
|
|