Building & Packaging
Distributing Python applications to end-users (especially in enterprise environments) can be challenging due to Python runtime requirements and dependency management. To solve this, PVE VDI Client provides automated scripts utilizing pyinstaller (for compiling the Python code into a standalone binary) and the WiX Toolset (for creating professional Windows MSI installers).
This section explains how to build the binaries yourself, which is necessary if you intend to fork the project, change hardcoded logic, or replace the default icons.
Building a Linux Binary
You can compile the Python script into a standalone Linux executable. This executable will contain the Python runtime and all necessary libraries (like proxmoxer and PySimpleGUI), meaning you can copy it to other Linux machines of the same architecture without installing Python packages.
Requirements
- A Linux build environment (Debian/Ubuntu recommended).
git,python3-pip,python3-tk(orpython3-tkinter).
Build Steps
-
Clone and Prep:
git clone https://github.com/joshpatten/PVE-VDIClient.git cd ./PVE-VDIClient/ chmod +x requirements.sh ./requirements.sh -
Install PyInstaller:
pip3 install pyinstaller -
Compile the Binary: Because the
proxmoxerlibrary does dynamic loading of backend requests, PyInstaller cannot always detect its dependencies automatically. We must explicitly declare them using--hidden-import.pyinstaller --onefile --noconsole --noconfirm \ --hidden-import proxmoxer.backends \ --hidden-import proxmoxer.backends.https \ --hidden-import proxmoxer.backends.https.AuthenticationError \ --hidden-import proxmoxer.core \ --hidden-import proxmoxer.core.ResourceException \ --hidden-import subprocess.TimeoutExpired \ --hidden-import subprocess.CalledProcessError \ --hidden-import requests.exceptions \ --hidden-import requests.exceptions.ReadTimeout \ --hidden-import requests.exceptions.ConnectTimeout \ --hidden-import requests.exceptions.ConnectionError \ vdiclient.py
Once PyInstaller finishes, the compiled, portable executable will be located at dist/vdiclient.
Building for Windows (Executable & MSI)
The project includes batch files to easily build a Windows executable and subsequently package it into a .msi installer. MSIs are the industry standard for Windows mass-deployment (via GPO/SCCM/Intune).
Windows Build Prerequisites
- Python 3.12 installed on Windows and added to your system
PATH. - WiX Toolset (v3.11) installed. WiX is the engine that generates MSI files from XML. Download it from wixtoolset.org.
- Install Python build requirements by running
requirements.batin the project root.
The Build Process
Execute the provided batch script from the project root in an administrative command prompt:
build_vdiclient.bat
What this script does behind the scenes:
- PyInstaller Compilation: It runs
pyinstalleragainstvdiclient.py, similar to the Linux build, but uses--noupxand attaches thevdiicon.icofile to the generated.exe. It outputs to a folder (dist\vdiclient), rather than a single file, to improve startup times. - Asset Staging: It copies required UI assets (
vdiclient.pngandvdiicon.ico) directly into thedist\vdiclientdistribution folder so the GUI can find them at runtime. - MSI Generation: It navigates into the
distdirectory and executes the customcreatemsi.pyscript, feeding itvdiclient.json.
Understanding createmsi.py and vdiclient.json
Creating MSI installers manually using WiX XML (.wxs) files is notoriously difficult and verbose. To simplify this, the project uses a custom Python script (dist/createmsi.py) that acts as an intelligent wrapper around the WiX compiler (candle.exe) and linker (light.exe).
vdiclient.json
This JSON file acts as the blueprint for the MSI installer. If you fork the project, you must edit this file.
upgrade_guid: A unique UUID. Crucial: If you fork this project for your company and change the product name, generate a new GUID here. This is how Windows determines if an installer is an upgrade to an existing app or an entirely new program.version: Must be incremented for Windows to apply upgrades over existing installations.parts: Instructs the script which directories to package. It targets thevdiclientfolder created by PyInstaller.license_file: Points toLicense.rtf, which is embedded directly into the MSI installation wizard.
createmsi.py
The script reads vdiclient.json, recursively scans the PyInstaller output directory, dynamically generates the massive WiX Source XML file (vdiclient.wxs), and invokes the WiX toolset. It handles complex MSI requirements like generating unique Component GUIDs, adding Start Menu shortcuts, setting Windows Registry uninstaller entries, and automatically embedding the Visual C++ redistributable merge modules (.msm) if required by Python.