PyInstaller ne suit que les bibliotheques liees : il embarquait winpty.dll et
conpty.dll, mais ignorait les deux executables que pywinpty lance en
sous-processus pour creer la pseudo-console. Resultat, l'application se
lancait normalement mais tous les terminaux se fermaient instantanement
("Deconnecte (Terminal ferme)") — un defaut invisible en mode script, ou les
fichiers sont presents dans l'environnement virtuel.
- OpenConsole.exe : hote du backend ConPTY (celui utilise par defaut)
- winpty-agent.exe : requis par le repli WinPTY
Ils sont localises dans le paquet installe au moment du build, donc la recette
reste valable sur n'importe quel poste. Verifie sur l'executable produit :
OpenConsole.exe et powershell.exe apparaissent bien comme processus enfants.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
80 lines
2.4 KiB
Python
80 lines
2.4 KiB
Python
# -*- mode: python ; coding: utf-8 -*-
|
|
"""Recette PyInstaller : construit un dossier portable dans dist/PySSH Client/.
|
|
|
|
Choix "onedir" (dossier) plutot que "onefile" : avec PySide6, un executable unique
|
|
doit decompresser ~200 Mo a chaque lancement, ce qui ajoute plusieurs secondes
|
|
d'attente a chaque demarrage. Le dossier demarre instantanement et se copie tout
|
|
aussi bien sur une cle USB.
|
|
"""
|
|
|
|
import os
|
|
import winpty
|
|
|
|
block_cipher = None
|
|
|
|
# pywinpty s'appuie sur deux executables auxiliaires que PyInstaller n'embarque pas
|
|
# tout seul (il ne suit que les DLL liees) : OpenConsole.exe pour le backend ConPTY,
|
|
# winpty-agent.exe pour le repli WinPTY. Sans eux, la pseudo-console se ferme
|
|
# instantanement au demarrage et les terminaux restent vides.
|
|
_winpty_dir = os.path.dirname(winpty.__file__)
|
|
_winpty_helpers = [
|
|
(os.path.join(_winpty_dir, name), "winpty")
|
|
for name in ("OpenConsole.exe", "winpty-agent.exe")
|
|
if os.path.exists(os.path.join(_winpty_dir, name))
|
|
]
|
|
|
|
a = Analysis(
|
|
["main.py"],
|
|
pathex=[],
|
|
binaries=[],
|
|
# la feuille de style est lue au runtime : elle doit voyager avec l'application
|
|
datas=[("resources/theme.qss", "resources")] + _winpty_helpers,
|
|
hiddenimports=["winpty"],
|
|
hookspath=[],
|
|
hooksconfig={},
|
|
runtime_hooks=[],
|
|
# modules inutiles ici : les exclure allege sensiblement le resultat
|
|
excludes=[
|
|
"tkinter", "PySide6.QtQml", "PySide6.QtQuick", "PySide6.QtQuick3D",
|
|
"PySide6.QtWebEngineCore", "PySide6.QtWebEngineWidgets", "PySide6.Qt3DCore",
|
|
"PySide6.QtMultimedia", "PySide6.QtCharts", "PySide6.QtDataVisualization",
|
|
"PySide6.QtBluetooth", "PySide6.QtPositioning", "PySide6.QtSensors",
|
|
],
|
|
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="PySSH Client",
|
|
debug=False,
|
|
bootloader_ignore_signals=False,
|
|
strip=False,
|
|
upx=False,
|
|
console=False, # application graphique : pas de fenetre de console
|
|
disable_windowed_traceback=False,
|
|
argv_emulation=False,
|
|
target_arch=None,
|
|
codesign_identity=None,
|
|
entitlements_file=None,
|
|
icon="resources/app.ico",
|
|
)
|
|
|
|
coll = COLLECT(
|
|
exe,
|
|
a.binaries,
|
|
a.zipfiles,
|
|
a.datas,
|
|
strip=False,
|
|
upx=False,
|
|
upx_exclude=[],
|
|
name="PySSH Client",
|
|
)
|