Loading...
Loading...
Packaging and distributing Qt Python applications — PyInstaller, Briefcase, and platform-specific build configurations. Use when distributing a PySide6 or PyQt6 app as a standalone executable, creating installers, configuring macOS bundles, Windows executables, or Linux AppImages. Trigger phrases: "package app", "PyInstaller", "distribute", "deploy", "standalone executable", "installer", "bundle app", "briefcase", "Windows build", "macOS build", "AppImage", "one-file"
npx skill4agent add l3digital-net/claude-code-plugins qt-packaging# Remove ALL system-level PySide6 installs from the build machine
pip uninstall pyside6 pyside6_essentials pyside6_addons shiboken6 -y
# Verify only venv version remains
python -c "import PySide6; print(PySide6.__file__)"
# Must show a path inside .venv/, not /usr/lib or system site-packages--onefile--onefiledist/MyApp/--onefileuv add --dev pyinstallerpyinstaller --name MyApp \
--windowed \
--icon resources/icons/app.ico \
src/myapp/__main__.py# MyApp.spec
block_cipher = None
a = Analysis(
["src/myapp/__main__.py"],
pathex=[],
binaries=[],
datas=[
("src/myapp/resources", "resources"), # (src, dest inside bundle)
],
hiddenimports=[
"PySide6.QtSvg", # SVG support
"PySide6.QtSvgWidgets", # SVG widgets
"PySide6.QtXml", # required by some Qt modules
],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=["tkinter", "matplotlib"],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
[],
exclude_binaries=True,
name="MyApp",
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=False,
console=False, # True for CLI apps
disable_windowed_traceback=False,
argv_emulation=False, # macOS: use True for drag-and-drop files
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon="resources/icons/app.ico",
)
coll = COLLECT(
exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=False,
upx_exclude=[],
name="MyApp",
)pyinstaller MyApp.spechiddenimportshiddenimports = [
"PySide6.QtSvg", "PySide6.QtSvgWidgets",
"PySide6.QtPrintSupport", # required by QTextEdit on some platforms
"PySide6.QtDBus", # Linux
].pydatasrc_resources__init__.py.msi.dmg.AppImagepip install briefcase
briefcase create # create platform package
briefcase build # compile
briefcase run # run from package
briefcase package # create installer[tool.briefcase]
project_name = "MyApp"
bundle = "com.myorg.myapp"
version = "1.0.0"
url = "https://myorg.com"
license = "MIT"
author = "My Name"
author_email = "me@myorg.com"
[tool.briefcase.app.myapp]
formal_name = "My Application"
description = "Description here"
icon = "resources/icons/app" # no extension — briefcase uses platform-appropriate format
sources = ["src/myapp"]
requires = ["PySide6>=6.6"]windeployqt# Run from the Qt SDK tools directory (or add to PATH)
windeployqt dist/MyApp/MyApp.exeqwindows.dllwindeployqt# Sign the executable (requires a code signing certificate)
signtool sign /fd SHA256 /a /tr http://timestamp.digicert.com dist/MyApp.exe.app# Ad-hoc signing (no developer ID)
codesign --force --deep --sign - dist/MyApp.app
# With developer ID
codesign --force --deep --sign "Developer ID Application: Name (TEAM_ID)" dist/MyApp.app
# Notarization (required for Gatekeeper)
xcrun notarytool submit dist/MyApp.zip --apple-id me@example.com --team-id TEAM_ID# Build one-directory first, then package as AppImage
# Use https://github.com/AppImage/AppImageKit
appimagetool dist/MyApp/ MyApp-x86_64.AppImage# .github/workflows/build.yml
jobs:
build-windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- run: pip install pyinstaller PySide6
- run: pyinstaller MyApp.spec
- uses: actions/upload-artifact@v4
with:
name: windows-build
path: dist/MyApp/qt.qpa.plugin: Could not find the Qt platform pluginPySide6/Qt/plugins/platforms/PySide6.QtSvghiddenimportsPath(__file__).parentsys._MEIPASSargv_emulation=True