From b6fc21c9681dcb57247b40787837de4b76bf0dd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20Br=C3=BCbach?= Date: Thu, 1 Oct 2026 18:05:30 +0200 Subject: [PATCH] [CI] Fail the build when the installer is missing a Qt runtime DLL The Windows payload is assembled by globbing every *.dll out of the build output directories, so nothing but luck decides whether a module the client links statically - Qt6Multimedia.dll, Qt6QuickWidgets.dll - reaches the installer at all. A module that is left out is invisible until a user installs an update and the client then refuses to start, with "The code execution cannot proceed because Qt6Multimedia.dll was not found" or a missing procedure entry point in a Qt6QuickWidgets.dll carried over from the previous version. Derive the required list from SERVATRICE_QT_MODULES, COCKATRICE_QT_MODULES and ORACLE_QT_MODULES, the same module lists the targets are actually built against, so it cannot drift from what the binaries need, and write it next to the CMake cache as required-qt-runtime.txt. Add the platform plugin, without which the client cannot start at all. Assert it in the existing 7-Zip pass that already rejects build-tree artifacts, comparing exact relative paths so a same-named file in the wrong directory does not satisfy a requirement, and normalizing the archive's own separators so it does not matter which one NSIS chose. Missing manifest, missing entry or missing 7-Zip-independent failures all stop the build rather than warn, which is the whole point: the previous check already failed hard for artifacts, and a warning here is what let a broken package ship. --- .ci/compile.sh | 34 +++++++++++++++++++++++++++++++++- CMakeLists.txt | 24 ++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/.ci/compile.sh b/.ci/compile.sh index f20432893..c8c1e539b 100755 --- a/.ci/compile.sh +++ b/.ci/compile.sh @@ -345,13 +345,45 @@ if [[ $MAKE_PACKAGE ]]; then else echo "Inspecting $package" # Fail the build if the installer contains any path left behind by the MSBuild or - # Qt AUTOMOC tooling (build-tree artifacts must live in the build dir, not the install) + # Qt AUTOMOC tooling (build-tree artifacts must live in the build dir, not in the install) if "$seven_zip" l "$package" | grep -E "_autogen|\.dir[\\/]|\.tlog|(^|[\\/])x64[\\/]|(^|[\\/])\.qt[\\/]|(^|[\\/])\.qsb[\\/]|(^|[\\/])\.lupdate[\\/]|CMakeFiles"; then echo "::error file=$0::Installer contains build-tree artifacts" exit 1 fi echo "Installer content is clean" + + # Fail the build if the installer is missing a Qt runtime the applications + # link against. The DLLs reach the package by globbing every *.dll out of + # the build output directories, so a module the client links statically + # (Qt6Multimedia.dll, Qt6QuickWidgets.dll) can be left out without anything + # else noticing, and the only symptom is a client that refuses to start + # after an update. required-qt-runtime.txt is written by the top level + # CMakeLists.txt from the same module list the targets are built against. + if [[ ! -f required-qt-runtime.txt ]]; then + echo "::error file=$0::required-qt-runtime.txt not found in the build dir, cannot verify the Qt runtime" + exit 1 + fi + # Normalize the archive's own separators to / so the entries below can be + # compared as exact relative paths, and use -xF so a '.' in a DLL name is + # never a wildcard. + installer_paths="$("$seven_zip" l -slt "$package" | sed -n 's/^Path = //p' | sed 's|\\|/|g')" + missing="" + checked=0 + while IFS= read -r entry; do + if [[ -z $entry || $entry == \#* ]]; then + continue + fi + checked=$((checked + 1)) + if ! grep -qxF "$entry" <<<"$installer_paths"; then + missing+=" $entry" + fi + done