#!/usr/bin/env bash # Fabrique le binaire Windows autonome (.exe) de JoinDomainGUI DEPUIS LINUX, # en pilotant un Python Windows embarque dans un prefixe Wine dedie. # # PyInstaller ne cross-compile pas : on execute donc un vrai PyInstaller Windows # sous Wine. Le .exe produit est un binaire Windows natif. # # Prerequis : wine (>= 8), curl, unzip. set -euo pipefail cd "$(dirname "$0")/.." PYTHON_VERSION="${PYTHON_VERSION:-3.12.10}" # Depuis Qt 6.10, Qt6Core.dll est lie a l'ICU fourni par Windows (icuuc.dll dans # System32, present depuis Win10 1703). Wine ne fournit pas cette DLL : PySide6 # y devient inimportable, et le hook PySide6 de PyInstaller -- qui importe QtCore # pour localiser les plugins Qt -- echoue alors SILENCIEUSEMENT et produit un # .exe depourvu de plugin de plateforme ("could not initialize Qt platform # plugin windows" au lancement). On contraint donc cette build a Qt 6.9. PYSIDE6_CONSTRAINT="${PYSIDE6_CONSTRAINT:-PySide6<6.10}" WINEPREFIX="${WINEPREFIX:-$PWD/.build-wine}" export WINEPREFIX export WINEARCH=win64 export WINEDEBUG="${WINEDEBUG:--all}" PY_DIR="$WINEPREFIX/drive_c/python" WPY="c:\\python\\python.exe" CACHE=".build-wine-cache" command -v wine >/dev/null || { echo "wine est requis (apt install wine)" >&2; exit 1; } mkdir -p "$CACHE" if [ ! -d "$WINEPREFIX" ]; then echo ">> Initialisation du prefixe Wine ($WINEPREFIX)" wineboot --init >/dev/null 2>&1 wineserver -w fi if [ ! -f "$PY_DIR/python.exe" ]; then ZIP="$CACHE/python-$PYTHON_VERSION-embed-amd64.zip" [ -f "$ZIP" ] || curl -fL --retry 3 -o "$ZIP" \ "https://www.python.org/ftp/python/$PYTHON_VERSION/python-$PYTHON_VERSION-embed-amd64.zip" echo ">> Installation de Python $PYTHON_VERSION (Windows) dans le prefixe" rm -rf "$PY_DIR" mkdir -p "$PY_DIR" unzip -q "$ZIP" -d "$PY_DIR" # La distribution "embeddable" desactive site-packages : on le reactive # pour que pip et les paquets installes soient importables. sed -i 's/^#import site/import site/' "$PY_DIR"/python*._pth fi if [ ! -f "$PY_DIR/Scripts/pip.exe" ]; then GETPIP="$CACHE/get-pip.py" [ -f "$GETPIP" ] || curl -fL --retry 3 -o "$GETPIP" https://bootstrap.pypa.io/get-pip.py echo ">> Installation de pip" cp "$GETPIP" "$PY_DIR/get-pip.py" wine "$WPY" c:\\python\\get-pip.py --no-warn-script-location fi # pip sous Wine est lent (plusieurs minutes pour le wheel PySide6) : on ne # reinstalle que si requirements.txt ou la contrainte ont change (FORCE_DEPS=1 # pour forcer). DEPS_STAMP="$PY_DIR/.deps-stamp" WANT_HASH="$(cat requirements.txt <(echo "$PYSIDE6_CONSTRAINT") | sha256sum | cut -d' ' -f1)" if [ "${FORCE_DEPS:-0}" = "1" ] || [ "$(cat "$DEPS_STAMP" 2>/dev/null)" != "$WANT_HASH" ]; then echo ">> Installation des dependances Windows (peut prendre plusieurs minutes)" printf '%s\n' "$PYSIDE6_CONSTRAINT" > "$PY_DIR/constraints.txt" # Desinstallation prealable : pip ne retrograde pas toujours un paquet deja # installe qui viole une contrainte nouvellement ajoutee. wine "$WPY" -m pip uninstall -q -y PySide6 PySide6-Essentials PySide6-Addons shiboken6 >/dev/null 2>&1 || true wine "$WPY" -m pip install -q --no-warn-script-location \ -c c:\\python\\constraints.txt -r requirements.txt pyinstaller echo "$WANT_HASH" > "$DEPS_STAMP" else echo ">> Dependances Windows a jour (FORCE_DEPS=1 pour les reinstaller)" fi # Garde-fou : si PySide6 ne s'importe pas ici, le hook PyInstaller ne collectera # aucun plugin Qt et produira un .exe casse sans le signaler. Echouer tot. echo ">> Verification de PySide6 sous Wine" if ! wine "$WPY" -c "import PySide6.QtWidgets" 2>&1; then echo "ERREUR : PySide6 n'est pas importable sous Wine — le .exe produit serait" >&2 echo " depourvu de plugins Qt. Verifiez PYSIDE6_CONSTRAINT." >&2 exit 1 fi echo ">> Compilation du .exe" wine "$WPY" -m PyInstaller \ --noconfirm \ --onefile \ --windowed \ --name JoinDomainGUI \ --distpath dist/windows \ --workpath build/windows \ --specpath build/windows \ main.py wineserver -w # Garde-fou : sans qwindows.dll, l'application refuse de demarrer sous Windows. if ! grep -qi 'qwindows.dll' build/windows/JoinDomainGUI/PKG-00.toc; then echo "ERREUR : le plugin de plateforme qwindows.dll est absent du binaire." >&2 exit 1 fi echo echo "Binaire produit : dist/windows/JoinDomainGUI.exe" echo "Lancement : clic droit -> Executer en tant qu'administrateur"