This document outlines the process, challenges, and solutions encountered when packaging the XPDRB application into a standalone executable using various tools.
The X-Plane Dataref Bridge (XPDRB) is a Python/PyQt6 application that interfaces with X-Plane flight simulator. It requires special handling during packaging due to its dependencies on serial communication libraries, PyQt6, qasync for asynchronous operations, and complex array dataref handling.
The most common issue during packaging was the "No module named 'qasync'" error, which occurs because packaging tools sometimes fail to detect all dependencies automatically, especially when dealing with complex modules like serial, hid, and PyQt6 components.
The application needed to expand array datarefs (e.g., LED_STATE[0], LED_STATE[1], ..., LED_STATE[7]) into individual elements in the Live Monitor UI, which required special handling in both the data model and UI layers.
The application uses pyserial for communication with Arduino devices, which requires proper inclusion of all serial backends (serialwin32, win32, serialutil, threaded) to function correctly on Windows.
pip install pyinstaller
pyinstaller --onefile --windowed --icon=resources/icon.ico --hidden-import=serial --hidden-import=serial.tools --hidden-import=serial.tools.list_ports --hidden-import=PyQt6 --hidden-import=PyQt6.QtCore --hidden-import=PyQt6.QtGui --hidden-import=PyQt6.QtWidgets --hidden-import=qasync main.pyIssues with PyInstaller:
- Had trouble detecting qasync module properly
- Large executable size (~38MB)
- Sometimes failed to include all necessary serial backends
pip install nuitka
python -m nuitka --onefile --windows-disable-console --include-package=serial --include-package=PyQt6 --include-package=qasync --windows-icon-from-ico=resources/icon.ico main.pyIssues with Nuitka:
- Compatibility problems with Python 3.14
- Linking errors with PyQt6 modules
- Experimental support for newer Python versions
import sys
from cx_Freeze import setup, Executable
build_exe_options = {
"packages": [
'serial',
'serial.tools',
'serial.tools.list_ports',
'serial.serialwin32',
'serial.win32',
'serial.serialutil',
'serial.threaded',
'qasync',
'PyQt6',
],
"includes": [
'serial.serialutil',
'serial.threaded',
'serial.urlhandler',
'serial.urlhandler.protocol_socket',
'serial.urlhandler.protocol_rfc2217',
'serial.urlhandler.protocol_loop',
'serial.urlhandler.protocol_alt',
'serial.urlhandler.protocol_cp2110',
'serial.urlhandler.protocol_hwgrep',
'serial.urlhandler.protocol_spy',
],
"excludes": [],
"optimize": 0,
}
# For Windows GUI application without console
base = None
if sys.platform == "win32":
base = "gui" # Use 'gui' for Windows GUI applications
setup(
name="X-Plane Dataref Bridge",
version="1.0",
description="X-Plane Dataref Bridge",
options={"build_exe": build_exe_options},
executables=[Executable("main.py", base=base, icon="resources/icon.ico",
target_name="X-Plane Dataref Bridge.exe")]
)python setup_cx.py buildAdvantages of cx_Freeze:
- Better automatic dependency detection
- More reliable inclusion of PyQt6 components
- Proper handling of qasync module
- More predictable behavior with complex Python applications
-
Added array size parsing helper in
core/dataref_manager.py:get_array_size_from_type()method to extract array size from type strings (e.g., 'float[8]' -> 8)get_expanded_datarefs()method to return datarefs with arrays expanded into per-element entries
-
Enhanced Output Panel in
gui/output_panel.py:- Added
_parse_array_size()method to parse array sizes from type strings - Modified
_add_output_row()to detect array datarefs and expand them into individual elements - Updated
_subscribe_if_appropriate()to handle array subscriptions properly - Enhanced
_update_datarefs_table_values()to route updates to correct array elements - Updated
on_dataref_update()to handle array element updates - Modified restoration logic to handle array expansion when loading profiles
- Added
-
Proper Subscription Handling:
- For array elements, the system subscribes to the base array once but displays all elements separately in the UI
- Updates are properly routed to individual array elements in the UI
Always explicitly include complex dependencies like:
- Serial communication modules (
serial,serial.tools,serial.tools.list_ports) - PyQt6 components (
PyQt6.QtCore,PyQt6.QtGui,PyQt6.QtWidgets) - Async modules (
qasync) - Hardware interface modules (
hid)
- Detect array sizes using regex pattern:
r'\[(\d+)\]' - Expand arrays into individual elements in the UI (e.g.,
LED_STATE[0],LED_STATE[1]) - Route updates to the correct array element based on the dataref name pattern
- Maintain proper subscription to the base array while displaying individual elements
- Use appropriate base for Windows GUI applications (
"gui"in cx_Freeze) - Include Windows-specific serial backends (
serial.serialwin32,serial.win32) - Handle platform-specific file paths and dependencies
- Clean previous builds before creating new executables
- Use
--cleanflag when available to ensure fresh builds - Test executables on clean systems without Python installed
- Verify all functionality works in the packaged application
The application was successfully packaged using cx_Freeze with the following characteristics:
- Standalone executable with all dependencies included
- Proper handling of array dataref expansion
- Reliable serial communication with Arduino devices
- Full PyQt6 GUI functionality preserved
- qasync module correctly included for async operations
- The executable is located in
build\exe.win-amd64-3.14\X-Plane Dataref Bridge.exe - Includes all necessary libraries and dependencies
- Runs on Windows systems without requiring Python installation
- Maintains all original functionality including array expansion features
- Size is approximately 38MB with all dependencies included
-
If encountering "No module named 'qasync'":
- Ensure qasync is included in the packages list in the setup script
- Verify the module is installed in your Python environment before building
-
If serial communication fails:
- Check that all serial backends are properly included in the build
- Verify that
serial.serialwin32,serial.win32, andserial.serialutilare accessible
-
If array expansion doesn't work:
- Ensure the
_parse_array_sizemethod is correctly implemented - Verify that array elements are properly routed in the UI update methods
- Ensure the
-
For GUI-related issues:
- Confirm that PyQt6 modules are properly included
- Check that the correct base is used for GUI applications