build: add Linux and Windows build scripts with NSIS installer
build-linux.sh configures and builds via CMake. build-windows.sh builds in MSYS2/MINGW64, bundles Qt and transitive MinGW DLLs via windeployqt plus an ldd pass, and produces an NSIS installer (installer.nsi). Ignore the dist/ output and generated Setup.exe. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
767b0b50b0
commit
7a4f3f312b
4 changed files with 216 additions and 0 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -17,6 +17,10 @@ ui_*.h
|
||||||
qrc_*.cpp
|
qrc_*.cpp
|
||||||
*.moc
|
*.moc
|
||||||
|
|
||||||
|
# ---- Windows packaging ----
|
||||||
|
dist/
|
||||||
|
*-Setup.exe
|
||||||
|
|
||||||
# ---- Go server ----
|
# ---- Go server ----
|
||||||
server/umt-tmdb-proxy
|
server/umt-tmdb-proxy
|
||||||
server/*.exe
|
server/*.exe
|
||||||
|
|
|
||||||
35
build-linux.sh
Executable file
35
build-linux.sh
Executable file
|
|
@ -0,0 +1,35 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Build Ultimate Media Tracker on Linux (Qt6 + CMake).
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# ./build-linux.sh configure + build (Release)
|
||||||
|
# ./build-linux.sh clean wipe the build dir first
|
||||||
|
# BUILD_TYPE=Debug ./build-linux.sh
|
||||||
|
#
|
||||||
|
set -euo pipefail
|
||||||
|
cd "$(dirname "$0")"
|
||||||
|
|
||||||
|
BUILD_DIR="build"
|
||||||
|
BUILD_TYPE="${BUILD_TYPE:-Release}"
|
||||||
|
|
||||||
|
if [[ "${1:-}" == "clean" ]]; then
|
||||||
|
echo "==> Removing $BUILD_DIR"
|
||||||
|
rm -rf "$BUILD_DIR"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Prefer Ninja for a fresh configure; reuse the existing generator otherwise
|
||||||
|
# (passing -G on an already-configured dir errors out).
|
||||||
|
GEN=()
|
||||||
|
if [[ ! -f "$BUILD_DIR/CMakeCache.txt" ]] && command -v ninja >/dev/null 2>&1; then
|
||||||
|
GEN=(-G Ninja)
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "==> Configuring ($BUILD_TYPE)"
|
||||||
|
cmake -S . -B "$BUILD_DIR" "${GEN[@]}" -DCMAKE_BUILD_TYPE="$BUILD_TYPE"
|
||||||
|
|
||||||
|
echo "==> Building"
|
||||||
|
cmake --build "$BUILD_DIR" -j
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "==> Done. Binary: $BUILD_DIR/umt"
|
||||||
99
build-windows.sh
Executable file
99
build-windows.sh
Executable file
|
|
@ -0,0 +1,99 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Build + package Ultimate Media Tracker for Windows.
|
||||||
|
# Run from the project root inside the MSYS2 *MINGW64* shell.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# ./build-windows.sh configure + build + bundle (+ installer)
|
||||||
|
# ./build-windows.sh clean wipe build/dist first
|
||||||
|
#
|
||||||
|
# Produces:
|
||||||
|
# dist/ portable build (zip & ship this folder)
|
||||||
|
# UltimateMediaTracker-Setup.exe NSIS installer (if makensis is installed)
|
||||||
|
#
|
||||||
|
set -euo pipefail
|
||||||
|
cd "$(dirname "$0")"
|
||||||
|
|
||||||
|
BUILD_DIR="build-win"
|
||||||
|
DIST_DIR="dist"
|
||||||
|
EXE="umt.exe"
|
||||||
|
BUILD_TYPE="${BUILD_TYPE:-Release}"
|
||||||
|
|
||||||
|
# Must run in the MINGW64 environment so CMake finds Qt under /mingw64.
|
||||||
|
if [[ "${MSYSTEM:-}" != "MINGW64" ]]; then
|
||||||
|
echo "ERROR: run this from the MSYS2 MINGW64 shell (MSYSTEM=MINGW64)." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
WINDEPLOY="$(command -v windeployqt6 || command -v windeployqt || true)"
|
||||||
|
if [[ -z "$WINDEPLOY" ]]; then
|
||||||
|
echo "ERROR: windeployqt not found. Install with:" >&2
|
||||||
|
echo " pacman -S mingw-w64-x86_64-qt6-tools" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${1:-}" == "clean" ]]; then
|
||||||
|
echo "==> Removing $BUILD_DIR and $DIST_DIR"
|
||||||
|
rm -rf "$BUILD_DIR" "$DIST_DIR"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "==> Configuring ($BUILD_TYPE)"
|
||||||
|
# Set the generator only on a fresh dir; reusing one with -G errors out.
|
||||||
|
GEN=()
|
||||||
|
if [[ ! -f "$BUILD_DIR/CMakeCache.txt" ]]; then
|
||||||
|
GEN=(-G Ninja)
|
||||||
|
fi
|
||||||
|
cmake -S . -B "$BUILD_DIR" "${GEN[@]}" -DCMAKE_BUILD_TYPE="$BUILD_TYPE"
|
||||||
|
|
||||||
|
echo "==> Building"
|
||||||
|
cmake --build "$BUILD_DIR" -j
|
||||||
|
|
||||||
|
echo "==> Assembling $DIST_DIR"
|
||||||
|
rm -rf "$DIST_DIR"
|
||||||
|
mkdir -p "$DIST_DIR"
|
||||||
|
cp "$BUILD_DIR/$EXE" "$DIST_DIR/"
|
||||||
|
|
||||||
|
echo "==> Running windeployqt"
|
||||||
|
"$WINDEPLOY" --release --no-translations "$DIST_DIR/$EXE"
|
||||||
|
|
||||||
|
echo "==> Bundling MinGW runtime + transitive dependencies"
|
||||||
|
# windeployqt does not copy third-party MinGW DLLs (harfbuzz, freetype, png,
|
||||||
|
# pcre2, zlib, glib, libgcc/libstdc++/winpthread ...). Resolve them via ldd and
|
||||||
|
# repeat a few passes so transitive deps (incl. those of the deployed plugins)
|
||||||
|
# are all picked up.
|
||||||
|
( cd "$DIST_DIR"
|
||||||
|
for _ in $(seq 1 6); do
|
||||||
|
find . \( -name '*.exe' -o -name '*.dll' \) -print0 \
|
||||||
|
| xargs -0 -I{} ldd "{}" 2>/dev/null \
|
||||||
|
| grep -io '/mingw64/bin/[^ ]*\.dll' \
|
||||||
|
| sort -u \
|
||||||
|
| while read -r f; do
|
||||||
|
[ -e "./$(basename "$f")" ] || cp "$f" .
|
||||||
|
done
|
||||||
|
done
|
||||||
|
)
|
||||||
|
|
||||||
|
echo "==> Verifying dependencies"
|
||||||
|
if command -v ntldd >/dev/null 2>&1; then
|
||||||
|
missing="$(cd "$DIST_DIR" && ntldd -R "$EXE" 2>/dev/null | grep -i 'not found' || true)"
|
||||||
|
if [[ -n "$missing" ]]; then
|
||||||
|
echo "WARNING: unresolved dependencies remain:" >&2
|
||||||
|
echo "$missing" >&2
|
||||||
|
else
|
||||||
|
echo " all dependencies resolved."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo " (install mingw-w64-x86_64-ntldd to auto-verify)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v makensis >/dev/null 2>&1; then
|
||||||
|
echo "==> Building NSIS installer"
|
||||||
|
makensis installer.nsi
|
||||||
|
echo "==> Installer: UltimateMediaTracker-Setup.exe"
|
||||||
|
else
|
||||||
|
echo "NOTE: makensis not found; skipping installer."
|
||||||
|
echo " Install it with: pacman -S mingw-w64-x86_64-nsis"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "==> Done. Portable build in: $DIST_DIR/"
|
||||||
78
installer.nsi
Normal file
78
installer.nsi
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
; NSIS installer for Ultimate Media Tracker
|
||||||
|
;
|
||||||
|
; Build with: makensis installer.nsi
|
||||||
|
; Expects the packaged app in the dist\ folder (produced by build-windows.sh).
|
||||||
|
|
||||||
|
Unicode true
|
||||||
|
|
||||||
|
!define APPNAME "Ultimate Media Tracker"
|
||||||
|
!define COMPANY "UMT"
|
||||||
|
!define VERSION "1.0.0"
|
||||||
|
!define EXE "umt.exe"
|
||||||
|
!define SOURCEDIR "dist"
|
||||||
|
!define REGUNINST "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}"
|
||||||
|
|
||||||
|
!include "MUI2.nsh"
|
||||||
|
|
||||||
|
Name "${APPNAME}"
|
||||||
|
OutFile "UltimateMediaTracker-Setup.exe"
|
||||||
|
InstallDir "$PROGRAMFILES64\${APPNAME}"
|
||||||
|
InstallDirRegKey HKLM "Software\${APPNAME}" "InstallDir"
|
||||||
|
RequestExecutionLevel admin
|
||||||
|
|
||||||
|
VIProductVersion "${VERSION}.0"
|
||||||
|
VIAddVersionKey "ProductName" "${APPNAME}"
|
||||||
|
VIAddVersionKey "CompanyName" "${COMPANY}"
|
||||||
|
VIAddVersionKey "FileVersion" "${VERSION}"
|
||||||
|
VIAddVersionKey "FileDescription" "${APPNAME} Installer"
|
||||||
|
VIAddVersionKey "LegalCopyright" "${COMPANY}"
|
||||||
|
|
||||||
|
!define MUI_ICON "resources\icons\appicon.ico"
|
||||||
|
!define MUI_UNICON "resources\icons\appicon.ico"
|
||||||
|
|
||||||
|
!insertmacro MUI_PAGE_WELCOME
|
||||||
|
!insertmacro MUI_PAGE_DIRECTORY
|
||||||
|
!insertmacro MUI_PAGE_INSTFILES
|
||||||
|
!define MUI_FINISHPAGE_RUN "$INSTDIR\${EXE}"
|
||||||
|
!insertmacro MUI_PAGE_FINISH
|
||||||
|
|
||||||
|
!insertmacro MUI_UNPAGE_CONFIRM
|
||||||
|
!insertmacro MUI_UNPAGE_INSTFILES
|
||||||
|
|
||||||
|
; First language listed is the default.
|
||||||
|
!insertmacro MUI_LANGUAGE "German"
|
||||||
|
!insertmacro MUI_LANGUAGE "English"
|
||||||
|
|
||||||
|
Section "Install"
|
||||||
|
SetOutPath "$INSTDIR"
|
||||||
|
File /r "${SOURCEDIR}\*.*"
|
||||||
|
|
||||||
|
; Shortcuts
|
||||||
|
CreateDirectory "$SMPROGRAMS\${APPNAME}"
|
||||||
|
CreateShortcut "$SMPROGRAMS\${APPNAME}\${APPNAME}.lnk" "$INSTDIR\${EXE}" "" "$INSTDIR\${EXE}"
|
||||||
|
CreateShortcut "$DESKTOP\${APPNAME}.lnk" "$INSTDIR\${EXE}" "" "$INSTDIR\${EXE}"
|
||||||
|
|
||||||
|
; Uninstaller + Add/Remove Programs entry
|
||||||
|
WriteUninstaller "$INSTDIR\Uninstall.exe"
|
||||||
|
WriteRegStr HKLM "Software\${APPNAME}" "InstallDir" "$INSTDIR"
|
||||||
|
WriteRegStr HKLM "${REGUNINST}" "DisplayName" "${APPNAME}"
|
||||||
|
WriteRegStr HKLM "${REGUNINST}" "DisplayVersion" "${VERSION}"
|
||||||
|
WriteRegStr HKLM "${REGUNINST}" "DisplayIcon" "$INSTDIR\${EXE}"
|
||||||
|
WriteRegStr HKLM "${REGUNINST}" "Publisher" "${COMPANY}"
|
||||||
|
WriteRegStr HKLM "${REGUNINST}" "UninstallString" "$INSTDIR\Uninstall.exe"
|
||||||
|
WriteRegDWORD HKLM "${REGUNINST}" "NoModify" 1
|
||||||
|
WriteRegDWORD HKLM "${REGUNINST}" "NoRepair" 1
|
||||||
|
SectionEnd
|
||||||
|
|
||||||
|
Section "Uninstall"
|
||||||
|
Delete "$SMPROGRAMS\${APPNAME}\${APPNAME}.lnk"
|
||||||
|
RMDir "$SMPROGRAMS\${APPNAME}"
|
||||||
|
Delete "$DESKTOP\${APPNAME}.lnk"
|
||||||
|
|
||||||
|
; Removes the program files only. User library/settings live in
|
||||||
|
; %APPDATA%\UMT and are intentionally left untouched.
|
||||||
|
RMDir /r "$INSTDIR"
|
||||||
|
|
||||||
|
DeleteRegKey HKLM "${REGUNINST}"
|
||||||
|
DeleteRegKey HKLM "Software\${APPNAME}"
|
||||||
|
SectionEnd
|
||||||
Loading…
Add table
Add a link
Reference in a new issue