From 3633793972d6a353a7c5e05c63f97e3957ed6a9e Mon Sep 17 00:00:00 2001 From: "alexei.dolgolyov" Date: Sun, 22 Mar 2026 03:40:06 +0300 Subject: [PATCH] fix: extract tkinter from Python installer via 7z, fix NSIS icon path - Replace nuget approach (doesn't contain tkinter) with extracting from the official Python amd64.exe installer using 7z - Remove MUI_ICON/MUI_UNICON (no .ico file available, use NSIS default) - Add p7zip-full to CI dependencies --- .gitea/workflows/release.yml | 2 +- build-dist-windows.sh | 113 ++++++++++++++++++++--------------- installer.nsi | 2 - 3 files changed, 65 insertions(+), 52 deletions(-) diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index 6776bfb..ccc4f48 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -63,7 +63,7 @@ jobs: - name: Install system dependencies run: | sudo apt-get update - sudo apt-get install -y --no-install-recommends zip libportaudio2 nsis + sudo apt-get install -y --no-install-recommends zip libportaudio2 nsis p7zip-full - name: Cross-build Windows distribution run: | diff --git a/build-dist-windows.sh b/build-dist-windows.sh index 611ab97..c310463 100644 --- a/build-dist-windows.sh +++ b/build-dist-windows.sh @@ -86,72 +86,87 @@ fi echo " Patched $(basename "$PTH_FILE")" # ── Bundle tkinter into embedded Python ─────────────────────── -# Embedded Python doesn't include tkinter. We download it from the -# official Windows Python nuget package (same version) which contains -# the _tkinter.pyd, tkinter/ package, and Tcl/Tk DLLs. +# Embedded Python doesn't include tkinter. We extract it from the +# official Windows installer (amd64.exe) which contains all components +# as MSI cab files. echo "[3b/8] Bundling tkinter for screen overlay support..." -# Python minor version for nuget package (e.g., 3.11.9 -> 3.11) -PYTHON_MINOR="${PYTHON_VERSION%.*}" - -# Download the full Python nuget package (contains all stdlib + DLLs) -NUGET_URL="https://www.nuget.org/api/v2/package/python/${PYTHON_VERSION}" -NUGET_PKG="$BUILD_DIR/python-nuget.zip" -if [ ! -f "$NUGET_PKG" ]; then - curl -sL "$NUGET_URL" -o "$NUGET_PKG" +# Download the Windows installer (not the embed zip — the full one) +INSTALLER_URL="https://www.python.org/ftp/python/${PYTHON_VERSION}/python-${PYTHON_VERSION}-amd64.exe" +INSTALLER_PATH="$BUILD_DIR/python-installer.exe" +if [ ! -f "$INSTALLER_PATH" ]; then + curl -sL "$INSTALLER_URL" -o "$INSTALLER_PATH" fi -NUGET_DIR="$BUILD_DIR/python-nuget" -rm -rf "$NUGET_DIR" -mkdir -p "$NUGET_DIR" -unzip -qo "$NUGET_PKG" -d "$NUGET_DIR" +# The installer is a bundle of MSI/CAB files. We can extract with 7z or +# msiextract. The tkinter components are in the 'tcltk' feature. +TK_EXTRACT="$BUILD_DIR/tk-extract" +rm -rf "$TK_EXTRACT" +mkdir -p "$TK_EXTRACT" -# Copy _tkinter.pyd (the C extension) -TKINTER_PYD=$(find "$NUGET_DIR" -name "_tkinter.pyd" | head -1) -if [ -n "$TKINTER_PYD" ]; then - cp "$TKINTER_PYD" "$PYTHON_DIR/" - echo " Copied _tkinter.pyd" -else - echo " WARNING: _tkinter.pyd not found in nuget package" -fi +if command -v 7z &>/dev/null; then + # Extract all cab files from the installer + 7z x -o"$TK_EXTRACT/installer" "$INSTALLER_PATH" -y >/dev/null 2>&1 || true -# Copy tkinter Python package from the stdlib zip or Lib/ -# The nuget package has Lib/tkinter/ -TKINTER_PKG=$(find "$NUGET_DIR" -type d -name "tkinter" | head -1) -if [ -n "$TKINTER_PKG" ]; then - mkdir -p "$PYTHON_DIR/Lib" - cp -r "$TKINTER_PKG" "$PYTHON_DIR/Lib/tkinter" - echo " Copied tkinter/ package" -else - echo " WARNING: tkinter package not found in nuget package" -fi + # Find and extract the tcltk cab + for cab in "$TK_EXTRACT/installer"/tcltk*.msi "$TK_EXTRACT/installer"/tcltk*; do + [ -f "$cab" ] || continue + 7z x -o"$TK_EXTRACT/tcltk" "$cab" -y >/dev/null 2>&1 || true + done -# Copy Tcl/Tk DLLs (tcl86t.dll, tk86t.dll, etc.) -for dll in tcl86t.dll tk86t.dll; do - DLL_PATH=$(find "$NUGET_DIR" -name "$dll" | head -1) - if [ -n "$DLL_PATH" ]; then - cp "$DLL_PATH" "$PYTHON_DIR/" - echo " Copied $dll" + # Find and extract the lib cab (contains tkinter Python package) + for cab in "$TK_EXTRACT/installer"/lib*.msi "$TK_EXTRACT/installer"/lib*; do + [ -f "$cab" ] || continue + 7z x -o"$TK_EXTRACT/lib" "$cab" -y >/dev/null 2>&1 || true + done + + # Copy _tkinter.pyd + TKINTER_PYD=$(find "$TK_EXTRACT" -name "_tkinter.pyd" 2>/dev/null | head -1) + if [ -n "$TKINTER_PYD" ]; then + cp "$TKINTER_PYD" "$PYTHON_DIR/DLLs/" 2>/dev/null || cp "$TKINTER_PYD" "$PYTHON_DIR/" + echo " Copied _tkinter.pyd" + else + echo " WARNING: _tkinter.pyd not found" fi -done -# Copy Tcl/Tk data directories (tcl8.6, tk8.6) -for tcldir in tcl8.6 tk8.6; do - TCL_PATH=$(find "$NUGET_DIR" -type d -name "$tcldir" | head -1) - if [ -n "$TCL_PATH" ]; then - cp -r "$TCL_PATH" "$PYTHON_DIR/$tcldir" - echo " Copied $tcldir/" + # Copy Tcl/Tk DLLs + for dll in tcl86t.dll tk86t.dll zlib1.dll; do + DLL_PATH=$(find "$TK_EXTRACT" -name "$dll" 2>/dev/null | head -1) + if [ -n "$DLL_PATH" ]; then + cp "$DLL_PATH" "$PYTHON_DIR/" + echo " Copied $dll" + fi + done + + # Copy tkinter Python package + TKINTER_PKG=$(find "$TK_EXTRACT" -type d -name "tkinter" 2>/dev/null | head -1) + if [ -n "$TKINTER_PKG" ]; then + mkdir -p "$PYTHON_DIR/Lib" + cp -r "$TKINTER_PKG" "$PYTHON_DIR/Lib/tkinter" + echo " Copied tkinter/ package" fi -done + + # Copy tcl/tk data directories + for tcldir in tcl8.6 tk8.6; do + TCL_PATH=$(find "$TK_EXTRACT" -type d -name "$tcldir" 2>/dev/null | head -1) + if [ -n "$TCL_PATH" ]; then + cp -r "$TCL_PATH" "$PYTHON_DIR/$tcldir" + echo " Copied $tcldir/" + fi + done + + echo " tkinter bundled successfully" +else + echo " WARNING: 7z not found — skipping tkinter bundling (install p7zip-full)" +fi # Add Lib to ._pth so tkinter package is importable if ! grep -q '^Lib$' "$PTH_FILE"; then echo 'Lib' >> "$PTH_FILE" fi -rm -rf "$NUGET_DIR" -echo " tkinter bundled successfully" +rm -rf "$TK_EXTRACT" # ── Download pip and install into embedded Python ──────────── diff --git a/installer.nsi b/installer.nsi index ce2ce22..fec7dca 100644 --- a/installer.nsi +++ b/installer.nsi @@ -30,8 +30,6 @@ SetCompressor /SOLID lzma ; ── Modern UI Configuration ───────────────────────────────── !define MUI_ABORTWARNING -!define MUI_ICON "server\src\wled_controller\static\icon-192.png" -!define MUI_UNICON "server\src\wled_controller\static\icon-192.png" ; ── Pages ───────────────────────────────────────────────────