URL: https://linuxfr.org/users/bluebird/journaux/reduire-la-taille-des-executables-generes-avec-pyinstaller Title: Réduire la taille des exécutables générés avec PyInstaller Authors: Philippe F Date: 2018年10月15日T14:52:58+02:00 License: CC By-SA Tags: windows, pyqt5, pyinstaller, s19, flatpak, python et qt Score: 26 En ce moment, je travaille à sortir un petit logiciel libre écrit en Python et PyQt. Le bébé est là: https://github.com/bluebird75/sxtool Il permet de manipuler les fichiers s19, s28 et s37. Ce sont des images binaires dans un format texte. Ce type d'image est utilisé dans l'embarqué pour charger du code binaire. Il arrive parfois qu'on ait envie après la génération dudit fichier de changer une valeur, de modifier une adresse, etc. Comme chaque ligne a un checksum, c'est parfois un peu fastidieux et c'est pour ça qu'un petit outil est pratique. Le soft est développé et pratiquement prêt à sortir. Comme je veux qu'il soit facile à installer, je vais en faire une version "packagée" pour Windows, c'est à dire un zip qui contient un .exe et deux-trois exemples. C'est nettement plus pratique à utiliser que d'installer Python et PyQt. Pour Linux, je me contenterai d'une installation par pip ou setup.py . En tout cas, pour Windows, j'utilise donc un "Python freezer", en occurrence PyInstaller version 3.4 . Je lance le bouzin et il me génère un beau répertoire avec un exécutable. Super ! Sauf qu'il y deux-trois autres trucs avec: $ sort -n du.out 36 ./sxtool/PyQt5/Qt/plugins/iconengines 56 ./sxtool/PyQt5/Qt/plugins/platformthemes 136 ./sxtool/PyQt5/Qt/plugins/styles 1352 ./sxtool/PyQt5/Qt/plugins/imageformats 3221 ./sxtool/PyQt5/Qt/translations 3484 ./sxtool/PyQt5/Qt/plugins/platforms 5068 ./sxtool/PyQt5/Qt/plugins 26989 ./sxtool/PyQt5/Qt/bin 35278 ./sxtool/PyQt5/Qt 44810 ./sxtool/PyQt5 86710 . 86710 ./sxtool $ find . | wc 128 128 3856 86 MOctets pour 128 fichiers ! C'est énorme ! On en parlait justement il y a quelques jours, plus ça va, plus les applications prennent de la place pour pas grand chose. Je ne serai pas celui qui livre une appli de la taille de Windows 95 juste pour éditer 3 lignes de fichier texte ! Voyons déjà ce que ça donne en détail. Merci au passage à git de fournir du, sort, uniq, find et wc sous Windows qui me permettent d'obtenir cette belle petite liste de taille en kilo-octet (les lignes blanches sont ajoutées par moi pour un groupement plus logique): ``` 1504 ./sxtool/sxtool.exe 4 ./sxtool/sxtool.exe.manifest 5780 ./sxtool/Qt5Core.dll 428 ./sxtool/Qt5DBus.dll 6192 ./sxtool/Qt5Gui.dll 1232 ./sxtool/Qt5Network.dll 3348 ./sxtool/Qt5Qml.dll 3548 ./sxtool/Qt5Quick.dll 324 ./sxtool/Qt5Svg.dll 148 ./sxtool/Qt5WebSockets.dll 5412 ./sxtool/Qt5Widgets.dll 60 ./sxtool/python3.dll 3756 ./sxtool/python37.dll 2428 ./sxtool/libcrypto-1_1-x64.dll 2452 ./sxtool/libGLESv2.dll 520 ./sxtool/libssl-1_1-x64.dll 972 ./sxtool/ucrtbase.dll 660 ./sxtool/MSVCP140.dll 88 ./sxtool/VCRUNTIME140.dll 4 ./sxtool/api-ms-win-core-console-l1-1-0.dll 4 ./sxtool/api-ms-win-core-datetime-l1-1-0.dll 4 ./sxtool/api-ms-win-core-debug-l1-1-0.dll 4 ./sxtool/api-ms-win-core-errorhandling-l1-1-0.dll 8 ./sxtool/api-ms-win-core-file-l1-1-0.dll 12 ./sxtool/api-ms-win-core-file-l1-2-0.dll 12 ./sxtool/api-ms-win-core-file-l2-1-0.dll 4 ./sxtool/api-ms-win-core-handle-l1-1-0.dll 4 ./sxtool/api-ms-win-core-heap-l1-1-0.dll 4 ./sxtool/api-ms-win-core-interlocked-l1-1-0.dll 4 ./sxtool/api-ms-win-core-libraryloader-l1-1-0.dll 16 ./sxtool/api-ms-win-core-localization-l1-2-0.dll 4 ./sxtool/api-ms-win-core-memory-l1-1-0.dll 4 ./sxtool/api-ms-win-core-namedpipe-l1-1-0.dll 4 ./sxtool/api-ms-win-core-processenvironment-l1-1-0.dll 8 ./sxtool/api-ms-win-core-processthreads-l1-1-0.dll 12 ./sxtool/api-ms-win-core-processthreads-l1-1-1.dll 4 ./sxtool/api-ms-win-core-profile-l1-1-0.dll 4 ./sxtool/api-ms-win-core-rtlsupport-l1-1-0.dll 4 ./sxtool/api-ms-win-core-string-l1-1-0.dll 4 ./sxtool/api-ms-win-core-synch-l1-1-0.dll 12 ./sxtool/api-ms-win-core-synch-l1-2-0.dll 4 ./sxtool/api-ms-win-core-sysinfo-l1-1-0.dll 12 ./sxtool/api-ms-win-core-timezone-l1-1-0.dll 4 ./sxtool/api-ms-win-core-util-l1-1-0.dll 16 ./sxtool/api-ms-win-crt-conio-l1-1-0.dll 16 ./sxtool/api-ms-win-crt-convert-l1-1-0.dll 12 ./sxtool/api-ms-win-crt-environment-l1-1-0.dll 16 ./sxtool/api-ms-win-crt-filesystem-l1-1-0.dll 16 ./sxtool/api-ms-win-crt-heap-l1-1-0.dll 12 ./sxtool/api-ms-win-crt-locale-l1-1-0.dll 24 ./sxtool/api-ms-win-crt-math-l1-1-0.dll 20 ./sxtool/api-ms-win-crt-multibyte-l1-1-0.dll 16 ./sxtool/api-ms-win-crt-process-l1-1-0.dll 16 ./sxtool/api-ms-win-crt-runtime-l1-1-0.dll 20 ./sxtool/api-ms-win-crt-stdio-l1-1-0.dll 20 ./sxtool/api-ms-win-crt-string-l1-1-0.dll 16 ./sxtool/api-ms-win-crt-time-l1-1-0.dll 12 ./sxtool/api-ms-win-crt-utility-l1-1-0.dll 28 ./sxtool/select.pyd 1052 ./sxtool/unicodedata.pyd 88 ./sxtool/_bz2.pyd 40 ./sxtool/_hashlib.pyd 252 ./sxtool/_lzma.pyd 76 ./sxtool/_socket.pyd 124 ./sxtool/_ssl.pyd 196 ./sxtool/pyexpat.pyd 768 ./sxtool/base_library.zip 2208 ./sxtool/PyQt5/QtCore.pyd 2292 ./sxtool/PyQt5/QtGui.pyd 4924 ./sxtool/PyQt5/QtWidgets.pyd 108 ./sxtool/PyQt5/sip.pyd 26989 ./sxtool/PyQt5/Qt/bin 4080 ./sxtool/PyQt5/Qt/bin/d3dcompiler_47.dll 16 ./sxtool/PyQt5/Qt/bin/libEGL.dll 2452 ./sxtool/PyQt5/Qt/bin/libGLESv2.dll 20436 ./sxtool/PyQt5/Qt/bin/opengl32sw.dll 1 ./sxtool/PyQt5/Qt/bin/qt.conf 36 ./sxtool/PyQt5/Qt/plugins/iconengines 36 ./sxtool/PyQt5/Qt/plugins/iconengines/qsvgicon.dll 1352 ./sxtool/PyQt5/Qt/plugins/imageformats 32 ./sxtool/PyQt5/Qt/plugins/imageformats/qgif.dll 40 ./sxtool/PyQt5/Qt/plugins/imageformats/qicns.dll 32 ./sxtool/PyQt5/Qt/plugins/imageformats/qico.dll 324 ./sxtool/PyQt5/Qt/plugins/imageformats/qjpeg.dll 28 ./sxtool/PyQt5/Qt/plugins/imageformats/qsvg.dll 28 ./sxtool/PyQt5/Qt/plugins/imageformats/qtga.dll 364 ./sxtool/PyQt5/Qt/plugins/imageformats/qtiff.dll 24 ./sxtool/PyQt5/Qt/plugins/imageformats/qwbmp.dll 476 ./sxtool/PyQt5/Qt/plugins/imageformats/qwebp.dll 3484 ./sxtool/PyQt5/Qt/plugins/platforms 816 ./sxtool/PyQt5/Qt/plugins/platforms/qminimal.dll 724 ./sxtool/PyQt5/Qt/plugins/platforms/qoffscreen.dll 548 ./sxtool/PyQt5/Qt/plugins/platforms/qwebgl.dll 1396 ./sxtool/PyQt5/Qt/plugins/platforms/qwindows.dll 56 ./sxtool/PyQt5/Qt/plugins/platformthemes 56 ./sxtool/PyQt5/Qt/plugins/platformthemes/qflatpak.dll 136 ./sxtool/PyQt5/Qt/plugins/styles 136 ./sxtool/PyQt5/Qt/plugins/styles/qwindowsvistastyle.dll 3221 ./sxtool/PyQt5/Qt/translations 160 ./sxtool/PyQt5/Qt/translations/qtbase_ar.qm 164 ./sxtool/PyQt5/Qt/translations/qtbase_bg.qm 176 ./sxtool/PyQt5/Qt/translations/qtbase_ca.qm 172 ./sxtool/PyQt5/Qt/translations/qtbase_cs.qm 172 ./sxtool/PyQt5/Qt/translations/qtbase_da.qm 192 ./sxtool/PyQt5/Qt/translations/qtbase_de.qm 1 ./sxtool/PyQt5/Qt/translations/qtbase_en.qm 164 ./sxtool/PyQt5/Qt/translations/qtbase_es.qm 176 ./sxtool/PyQt5/Qt/translations/qtbase_fi.qm 164 ./sxtool/PyQt5/Qt/translations/qtbase_fr.qm 188 ./sxtool/PyQt5/Qt/translations/qtbase_gd.qm 136 ./sxtool/PyQt5/Qt/translations/qtbase_he.qm 160 ./sxtool/PyQt5/Qt/translations/qtbase_hu.qm 160 ./sxtool/PyQt5/Qt/translations/qtbase_it.qm 128 ./sxtool/PyQt5/Qt/translations/qtbase_ja.qm 132 ./sxtool/PyQt5/Qt/translations/qtbase_ko.qm 152 ./sxtool/PyQt5/Qt/translations/qtbase_lv.qm 160 ./sxtool/PyQt5/Qt/translations/qtbase_pl.qm 176 ./sxtool/PyQt5/Qt/translations/qtbase_ru.qm 124 ./sxtool/PyQt5/Qt/translations/qtbase_sk.qm 156 ./sxtool/PyQt5/Qt/translations/qtbase_uk.qm 86710 ./sxtool 86711 . ``` Bon, il y a du pain sur la planche. Mon logiciel ne fait que des trucs très basiques : ouvrir un fichier texte, appliquer des opérations dessus et le sauver. Ah, et il utilise un système de config en xml (pardon, c'est pas moi qui l'ai codé). Et côté Qt, il utilise quelques widgets classiques: fenêtre, dialogues, vue sur une table. Pas de traduction, pas de plugin, pas d'icônes, pas d'images, pas de conversion, pas de 3D. Commençons par les trucs faciles: les modules Qt. Je n'utilise que Qt5Core, Qt5Widgets et Qt5Gui. PyInstaller l'a d'ailleurs bien compris car il n'embarque que QtCore.pyd, QtGui.pyd et QtGui.pyd. Par contre, il livre quand même l'ensemble des DLL de Qt. Exit donc: Qt5dbus.dll Qt5Network.dll Qt5Qml.dll Qt5Quick.dll Qt5Svg.dll Qt5WebSockets.dll . Qt tire aussi pas mal de fichiers de configs et plugins. Regardons de plus prêt: PyQt5/Qt/translations a l'air de contenir plein de traductions dont je ne me sers a priori pas du tout. Mon appli est en anglais dans un Windows français donc si ça doit merdouiller, j'imagine que je le verrai tout de suite. Allez, on vire ... et ça continue à marcher. Ouf. J'avoue que je fais un peu dans l'expérimental. Si j'arrive à lancer mon appli, c'est que elle a tout ce dont elle a besoin et ça valide mes choix. On verra un autre jour pour la théorie. Je n'utilise pas d'images ni d'icônes, et encore moins de SVG. Exit Qt/plugins/imageformats et iconengines . Je vérifie des fois que Qt l'utilise en interne mais non, ça passe nickel. C'est quoi ce répertoire PyQt5/Qt/bin . Je suis sur que j'ai pas besoin de lancer un autre exécutable. En fait, ça contient des dll et un fichier de conf: opengl32sw.dll d3dcompiler\_47.dll libGLESv2.dll libEGL.dll et qt.conf. Tout ça ressemble à des DLL dont auraient besoin des outils qui seraient dans bin. C'est pas mon cas, on dégage. Et sxtool se lance toujours, ça roule. C'est quoi ce platformthemes/qflatpak.dll ? Ca m'a tout l'air d'être un thème de rendu pour flatpak sous Gnome. Ca sert à rien sous Windows, non ? En plus, Qt a souvent des mode de secours pour quand il ne trouve pas ses plugins. Donc je suis pas inquiet, sxtool pourra s'en passer. Du côté de plugins/platforms/, je vais être plus prudent. Si j'en crois la documentation ça implémente des services fondamentaux de Qt sur une plate-forme donnée. C'est utilisé en embarqué pour définir par exemple les modules d'affichage (x11, wayland, framebuffer, etc). Si j'ai bien compris la documentation, je n'ai besoin que de l'un d'entre eux, celui de Windows, ou même d'aucuns si Qt a prévu quelque chose par défaut. Vérification faite, si je vire platforms/qwindows.dll , mon application ne se lance plus. Mais je peux virer tous les autres sans impact visible: qminimal.dll qwebgl.dll qoffscreen.dll . Il me reste un candidat à virer: PyQt5/Qt/plugins/styles/qwindowsvistastyle.dll . Mais là, je doute un peu. Le style Vista permet peut-être à mon application de ne pas ressembler à un windows 95 quand on la lance sur un autre ordinateur ? Je préfère le garder pour l'instant... Pour Qt, j'ai bien nettoyé. Résultat des courses: ``` $ du . 1396 ./PyQt5/Qt/plugins/platforms 136 ./PyQt5/Qt/plugins/styles 1536 ./PyQt5/Qt/plugins 1536 ./PyQt5/Qt 11068 ./PyQt5 43940 . ``` 50%, c'est déjà un beau chiffre! Passons à Python. Je vois pas mal de .pyd qui trainent à côté de sxtool.exe . A ma connaissance, je ne fais pas de compression, pas de hashage, pas de socket, pas de ssl et pas d'exploration de unicode. Exit donc: \_bz2.pyd \_hashlib.pyd \_lzma.pyd \_socket.pyd \_ssl.pyd select.pyd unicodedata.pyd. Je lance, ça marche toujours. Ouf. Il y a quelques DLL qui me semblent inutiles: libssl, libcrypto, libGLESv2.dll, étaient probablement liées à ce que j'ai déjà viré. Exit aussi. Il reste les trucs Microsoft: VCRUNTIME140.dll MSVCP140.dll. C'est des runtimes qui sont demandés lors de l'utilisation avec Qt. Mais ça sert vraiment à quelque chose ? Sur ma machine, je les vire et ça continue à marcher très bien. J'en profite pour virer aussi tous les api-ms-win-core-\*.dll api-ms-win-crt-\*.dll et ça marche encore. J'avoue que je fais de l'expérimental là. Il me semble que ce type de fichier peut servir lorsqu'on exécute dans un PC moins fourni en DLL existantes. Peut-être que ça ne marchera plus chez Mme Michou. En attendant Mme Michou, je suis content que ça fonctionne encore chez moi et je ferai plus de test sur d'autres PC non windows 7 si j'en trouve. Voyons où j'en suis: ``` $ du . [...] 34768 . ``` Pas mal ! Bilan de cette première passe, j'ai enlevé plein de fichiers et tout ceux qui restent sont indispensable pour mon application. Mais quand même, tout ça me semble encore bien gros. Si je veux gratter encore, il va me falloir réduire la taille des fichiers qui sont listés. Un très bon candidat se présente sous le forme de: base\_library.zip . Il s'agit des modules de la lib standard de Python dont PyInstaller a estimé que j'avais besoin. Il ne représente que 768k sur les 34Mo mais il a l'avantage est qu'il est très facile à modifier puisque c'est un zip. Regardons ce qu'il a dans le ventre (merci 7zip au passage): ``` $ "c:\Program Files7円-Zip7円z.exe" l sxtool\base_library.zip 7-Zip 18.05 (x64) : Copyright (c) 1999-2018 Igor Pavlov : 2018年04月30日 Scanning the drive for archives: 1 file, 784782 bytes (767 KiB) Listing archive: sxtool\base_library.zip -- Path = sxtool\base_library.zip Type = zip Physical Size = 784782 Date Time Attr Size Compressed Name ------------------- ----- ------------ ------------ ------------------------ 1980年01月01日 00:00:00 ..... 1272 1272 _bootlocale.pyc 1980年01月01日 00:00:00 ..... 15226 15226 sre_compile.pyc 1980年01月01日 00:00:00 ..... 5373 5373 reprlib.pyc 1980年01月01日 00:00:00 ..... 7485 7485 _weakrefset.pyc 1980年01月01日 00:00:00 ..... 1484 1484 encodings\iso2022_kr.pyc 1980年01月01日 00:00:00 ..... 2486 2486 encodings\cp1257.pyc 1980年01月01日 00:00:00 ..... 2496 2496 encodings\iso8859_6.pyc 1980年01月01日 00:00:00 ..... 8188 8188 encodings\cp737.pyc 1980年01月01日 00:00:00 ..... 4539 4539 encodings\utf_8_sig.pyc 1980年01月01日 00:00:00 ..... 2459 2459 encodings\iso8859_7.pyc 1980年01月01日 00:00:00 ..... 1469 1469 encodings\cp950.pyc 1980年01月01日 00:00:00 ..... 2466 2466 encodings\quopri_codec.pyc 1980年01月01日 00:00:00 ..... 1469 1469 encodings\johab.pyc 1980年01月01日 00:00:00 ..... 1657 1657 encodings\utf_16_be.pyc 1980年01月01日 00:00:00 ..... 2452 2452 encodings\iso8859_5.pyc 1980年01月01日 00:00:00 ..... 7497 7497 encodings\cp858.pyc 1980年01月01日 00:00:00 ..... 3970 3970 encodings\__init__.pyc 1980年01月01日 00:00:00 ..... 1706 1706 encodings\cp65001.pyc 1980年01月01日 00:00:00 ..... 2479 2479 encodings\cp1250.pyc 1980年01月01日 00:00:00 ..... 1484 1484 encodings\iso2022_jp.pyc 1980年01月01日 00:00:00 ..... 1488 1488 encodings\iso2022_jp_3.pyc 1980年01月01日 00:00:00 ..... 1471 1471 encodings\euc_kr.pyc 1980年01月01日 00:00:00 ..... 2550 2550 encodings\iso8859_11.pyc 1980年01月01日 00:00:00 ..... 1718 1718 encodings\mbcs.pyc 1980年01月01日 00:00:00 ..... 3308 3308 encodings\bz2_codec.pyc 1980年01月01日 00:00:00 ..... 6319 6319 encodings\aliases.pyc 1980年01月01日 00:00:00 ..... 2492 2492 encodings\cp1253.pyc 1980年01月01日 00:00:00 ..... 2459 2459 encodings\iso8859_13.pyc 1980年01月01日 00:00:00 ..... 1487 1487 encodings\shift_jisx0213.pyc 1980年01月01日 00:00:00 ..... 2456 2456 encodings\iso8859_15.pyc 1980年01月01日 00:00:00 ..... 1531 1531 encodings\oem.pyc 1980年01月01日 00:00:00 ..... 1483 1483 encodings\euc_jisx0213.pyc 1980年01月01日 00:00:00 ..... 2484 2484 encodings\cp1258.pyc 1980年01月01日 00:00:00 ..... 2433 2433 encodings\hex_codec.pyc 1980年01月01日 00:00:00 ..... 1488 1488 encodings\iso2022_jp_1.pyc 1980年01月01日 00:00:00 ..... 1772 1772 encodings\unicode_escape.pyc 1980年01月01日 00:00:00 ..... 2472 2472 encodings\mac_greek.pyc 1980年01月01日 00:00:00 ..... 2499 2499 encodings\mac_romanian.pyc 1980年01月01日 00:00:00 ..... 1471 1471 encodings\gb2312.pyc 1980年01月01日 00:00:00 ..... 8049 8049 encodings\cp862.pyc 1980年01月01日 00:00:00 ..... 7760 7760 encodings\mac_arabic.pyc 1980年01月01日 00:00:00 ..... 4856 4856 encodings\utf_16.pyc 1980年01月01日 00:00:00 ..... 1494 1494 encodings\iso2022_jp_2004.pyc 1980年01月01日 00:00:00 ..... 1483 1483 encodings\euc_jis_2004.pyc 1980年01月01日 00:00:00 ..... 2514 2514 encodings\cp856.pyc 1980年01月01日 00:00:00 ..... 1477 1477 encodings\shift_jis.pyc 1980年01月01日 00:00:00 ..... 2442 2442 encodings\cp1140.pyc 1980年01月01日 00:00:00 ..... 1477 1477 encodings\big5hkscs.pyc 1980年01月01日 00:00:00 ..... 1473 1473 encodings\gb18030.pyc 1980年01月01日 00:00:00 ..... 1465 1465 encodings\gbk.pyc 1980年01月01日 00:00:00 ..... 2482 2482 encodings\cp424.pyc 1980年01月01日 00:00:00 ..... 1782 1782 encodings\unicode_internal.pyc 1980年01月01日 00:00:00 ..... 8149 8149 encodings\cp1125.pyc 1980年01月01日 00:00:00 ..... 2451 2451 encodings\iso8859_1.pyc 1980年01月01日 00:00:00 ..... 2438 2438 encodings\cp273.pyc 1980年01月01日 00:00:00 ..... 2490 2490 encodings\iso8859_8.pyc 1980年01月01日 00:00:00 ..... 1487 1487 encodings\shift_jis_2004.pyc 1980年01月01日 00:00:00 ..... 1657 1657 encodings\utf_16_le.pyc 1980年01月01日 00:00:00 ..... 7860 7860 encodings\cp863.pyc 1980年01月01日 00:00:00 ..... 6440 6440 encodings\punycode.pyc 1980年01月01日 00:00:00 ..... 2477 2477 encodings\iso8859_14.pyc 1980年01月01日 00:00:00 ..... 2458 2458 encodings\iso8859_16.pyc 1980年01月01日 00:00:00 ..... 2488 2488 encodings\mac_cyrillic.pyc 1980年01月01日 00:00:00 ..... 2466 2466 encodings\kz1048.pyc 1980年01月01日 00:00:00 ..... 1488 1488 encodings\iso2022_jp_2.pyc 1980年01月01日 00:00:00 ..... 7860 7860 encodings\cp865.pyc 1980年01月01日 00:00:00 ..... 8193 8193 encodings\cp866.pyc 1980年01月01日 00:00:00 ..... 2503 2503 encodings\koi8_r.pyc 1980年01月01日 00:00:00 ..... 8157 8157 encodings\cp855.pyc 1980年01月01日 00:00:00 ..... 2960 2960 encodings\charmap.pyc 1980年01月01日 00:00:00 ..... 3248 3248 encodings\uu_codec.pyc 1980年01月01日 00:00:00 ..... 1469 1469 encodings\cp932.pyc 1980年01月01日 00:00:00 ..... 2528 2528 encodings\cp1006.pyc 1980年01月01日 00:00:00 ..... 2451 2451 encodings\iso8859_2.pyc 1980年01月01日 00:00:00 ..... 7860 7860 encodings\cp861.pyc 1980年01月01日 00:00:00 ..... 7904 7904 encodings\cp852.pyc 1980年01月01日 00:00:00 ..... 5747 5747 encodings\idna.pyc 1980年01月01日 00:00:00 ..... 3052 3052 encodings\rot_13.pyc 1980年01月01日 00:00:00 ..... 7896 7896 encodings\cp775.pyc 1980年01月01日 00:00:00 ..... 2478 2478 encodings\cp1256.pyc 1980年01月01日 00:00:00 ..... 2541 2541 encodings\tis_620.pyc 1980年01月01日 00:00:00 ..... 2186 2186 encodings\undefined.pyc 1980年01月01日 00:00:00 ..... 2452 2452 encodings\cp500.pyc 1980年01月01日 00:00:00 ..... 1469 1469 encodings\cp949.pyc 1980年01月01日 00:00:00 ..... 7509 7509 encodings\cp857.pyc 1980年01月01日 00:00:00 ..... 1792 1792 encodings\raw_unicode_escape.pyc 1980年01月01日 00:00:00 ..... 2549 2549 encodings\cp720.pyc 1980年01月01日 00:00:00 ..... 1467 1467 encodings\big5.pyc 1980年01月01日 00:00:00 ..... 2451 2451 encodings\iso8859_4.pyc 1980年01月01日 00:00:00 ..... 7866 7866 encodings\cp437.pyc 1980年01月01日 00:00:00 ..... 2491 2491 encodings\mac_iceland.pyc 1980年01月01日 00:00:00 ..... 2489 2489 encodings\mac_roman.pyc 1980年01月01日 00:00:00 ..... 2490 2490 encodings\mac_centeuro.pyc 1980年01月01日 00:00:00 ..... 2481 2481 encodings\cp1254.pyc 1980年01月01日 00:00:00 ..... 2456 2456 encodings\cp1026.pyc 1980年01月01日 00:00:00 ..... 1471 1471 encodings\euc_jp.pyc 1980年01月01日 00:00:00 ..... 7886 7886 encodings\cp869.pyc 1980年01月01日 00:00:00 ..... 1919 1919 encodings\latin_1.pyc 1980年01月01日 00:00:00 ..... 2479 2479 encodings\cp1252.pyc 1980年01月01日 00:00:00 ..... 2446 2446 encodings\base64_codec.pyc 1980年01月01日 00:00:00 ..... 1492 1492 encodings\iso2022_jp_ext.pyc 1980年01月01日 00:00:00 ..... 2500 2500 encodings\cp1255.pyc 1980年01月01日 00:00:00 ..... 2632 2632 encodings\mac_latin2.pyc 1980年01月01日 00:00:00 ..... 1550 1550 encodings\utf_32_be.pyc 1980年01月01日 00:00:00 ..... 2456 2456 encodings\iso8859_10.pyc 1980年01月01日 00:00:00 ..... 2451 2451 encodings\iso8859_9.pyc 1980年01月01日 00:00:00 ..... 3146 3146 encodings\zlib_codec.pyc 1980年01月01日 00:00:00 ..... 2479 2479 encodings\palmos.pyc 1980年01月01日 00:00:00 ..... 4749 4749 encodings\utf_32.pyc 1980年01月01日 00:00:00 ..... 2414 2414 encodings\koi8_t.pyc 1980年01月01日 00:00:00 ..... 1907 1907 encodings\ascii.pyc 1980年01月01日 00:00:00 ..... 2449 2449 encodings\cp875.pyc 1980年01月01日 00:00:00 ..... 7527 7527 encodings\cp850.pyc 1980年01月01日 00:00:00 ..... 2580 2580 encodings\cp874.pyc 1980年01月01日 00:00:00 ..... 2573 2573 encodings\ptcp154.pyc 1980年01月01日 00:00:00 ..... 1637 1637 encodings\utf_8.pyc 1980年01月01日 00:00:00 ..... 2452 2452 encodings\cp037.pyc 1980年01月01日 00:00:00 ..... 2498 2498 encodings\mac_croatian.pyc 1980年01月01日 00:00:00 ..... 8006 8006 encodings\cp864.pyc 1980年01月01日 00:00:00 ..... 1550 1550 encodings\utf_32_le.pyc 1980年01月01日 00:00:00 ..... 7845 7845 encodings\cp860.pyc 1980年01月01日 00:00:00 ..... 2489 2489 encodings\koi8_u.pyc 1980年01月01日 00:00:00 ..... 1463 1463 encodings\hz.pyc 1980年01月01日 00:00:00 ..... 2653 2653 encodings\hp_roman8.pyc 1980年01月01日 00:00:00 ..... 2476 2476 encodings\cp1251.pyc 1980年01月01日 00:00:00 ..... 1578 1578 encodings\utf_7.pyc 1980年01月01日 00:00:00 ..... 2492 2492 encodings\mac_turkish.pyc 1980年01月01日 00:00:00 ..... 2432 2432 encodings\mac_farsi.pyc 1980年01月01日 00:00:00 ..... 2458 2458 encodings\iso8859_3.pyc 1980年01月01日 00:00:00 ..... 34578 34578 locale.pyc 1980年01月01日 00:00:00 ..... 13923 13923 operator.pyc 1980年01月01日 00:00:00 ..... 6474 6474 abc.pyc 1980年01月01日 00:00:00 ..... 4267 4267 copyreg.pyc 1980年01月01日 00:00:00 ..... 6314 6314 sre_constants.pyc 1980年01月01日 00:00:00 ..... 13827 13827 re.pyc 1980年01月01日 00:00:00 ..... 19536 19536 traceback.pyc 1980年01月01日 00:00:00 ..... 28965 28965 _collections_abc.pyc 1980年01月01日 00:00:00 ..... 3432 3432 io.pyc 1980年01月01日 00:00:00 ..... 19133 19133 weakref.pyc 1980年01月01日 00:00:00 ..... 8997 8997 types.pyc 1980年01月01日 00:00:00 ..... 21380 21380 sre_parse.pyc 1980年01月01日 00:00:00 ..... 14385 14385 heapq.pyc 1980年01月01日 00:00:00 ..... 3812 3812 linecache.pyc 1980年01月01日 00:00:00 ..... 13789 13789 warnings.pyc 1980年01月01日 00:00:00 ..... 23837 23837 functools.pyc 1980年01月01日 00:00:00 ..... 23770 23770 enum.pyc 1980年01月01日 00:00:00 ..... 228 228 collections\abc.pyc 1980年01月01日 00:00:00 ..... 46633 46633 collections\__init__.pyc 1980年01月01日 00:00:00 ..... 1832 1832 keyword.pyc 1980年01月01日 00:00:00 ..... 33921 33921 codecs.pyc ------------------- ----- ------------ ------------ ------------------------ 1980年01月01日 00:00:00 767304 767304 150 files ``` Ce qui saute au yeux... c'est cette histoire de date. D'où on est en 1980 ? M'est avis que le zipper de PyInstaller (qui est probablement celui de Python) ne conserve pas les dates de modification des fichiers par défaut. Ensuite, il y a beaucoup de fichier décrivant des encodages. De mémoire, ces encodages sont chargés dynamiquement quand on les demande. Ce qui veut dire que je pourrais en virer quelques uns si je n'en ai pas besoin. Vérifions le fichier Python37\\Lib\\encodings\\\_\_init\_\_.py: [...] def search_function(encoding): # Import the module: # [...] for modname in modnames: try: # Import is absolute to prevent the possibly malicious import of a # module with side-effects that is not in the 'encodings' package. mod = __import__('encodings.' + modname, fromlist=_import_tail, level=0) C'est bien ce que je pensais. Quand on réclame un encodage, le module correspondant est importé à la demande. Donc, je peux ne garder que ceux dont j'ai besoin. A coup d'essai, erreur et répétition, je peux faire fonctionner mon application en ne gardant que: 1980年01月01日 00:00:00 ..... 6319 6319 encodings\aliases.pyc 1980年01月01日 00:00:00 ..... 1907 1907 encodings\ascii.pyc 1980年01月01日 00:00:00 ..... 1919 1919 encodings\latin_1.pyc 1980年01月01日 00:00:00 ..... 1792 1792 encodings\raw_unicode_escape.pyc 1980年01月01日 00:00:00 ..... 1772 1772 encodings\unicode_escape.pyc 1980年01月01日 00:00:00 ..... 1782 1782 encodings\unicode_internal.pyc 1980年01月01日 00:00:00 ..... 1637 1637 encodings\utf_8.pyc 1980年01月01日 00:00:00 ..... 4539 4539 encodings\utf_8_sig.pyc 1980年01月01日 00:00:00 ..... 3970 3970 encodings\__init__.pyc Ca me parait assez raisonnable. Ce sont les encodages standard les plus utilisés. Par contre, je ne sais pas si mon application pourra lire un fichier sur un Windows configuré en Japonais... On verra. Au pire, ces japonisants pourront utiliser l'installation par pip qui embarque bien tout ce qu'il faut... ou bien me faire un bug report et je remettrai tout ça. ``` $ "C:\Program Files7円-Zip7円z.exe" d base_library.zip -r base64_codec.pyc big5.pyc big5hkscs.pyc bz2_codec.pyc charmap.pyc cp*.pyc euc_*.pyc gb*.pyc hex_codec.pyc hp_roman8.pyc hz.pyc idna .pyc iso*.pyc johab.pyc koi8_*.pyc kz1048.pyc mac_*.pyc mbcs.pyc oem.pyc palmos.pyc ptcp154.pyc punycode.pyc quopri_codec.pyc rot_13.py shift_jis*.pyc tis_620.pyc undefined.pyc utf_7.pyc utf_1*.pyc utf_3*.pyc uu_codec.pyc zlib_codec.pyc 7-Zip 18.05 (x64) : Copyright (c) 1999-2018 Igor Pavlov : 2018年04月30日 Open archive: base_library.zip Path = base_library.zip Type = zip Physical Size = 784782 Updating archive: base_library.zip Delete data from archive: 116 files, 369278 bytes (361 KiB) Keep old data in archive: 34 files, 398026 bytes (389 KiB) Add new data to archive: 0 files, 0 bytes Files read from disk: 0 Archive size: 401682 bytes (393 KiB) Everything is Ok ``` Je suis donc passé de 784 koctets à 400 koctets. C'est toujours ça de pris. Pour les autres modules Python, ils sont pas très nombreux. En interne, je n'utilise que: functools io optparse os sys traceback unittest xml.dom.minidom xml.sax Tous les autres modules sont des dépendances internes de la machinerie Python. Je fais quand même le test, je vire un .pyc au hasard. De fait, mon appli ne se lance plus. Alors, où en est-on niveau taille ? ``` $ du -a 396 ./sxtool/base_library.zip 196 ./sxtool/pyexpat.pyd 1396 ./sxtool/PyQt5/Qt/plugins/platforms/qwindows.dll 1396 ./sxtool/PyQt5/Qt/plugins/platforms 136 ./sxtool/PyQt5/Qt/plugins/styles/qwindowsvistastyle.dll 136 ./sxtool/PyQt5/Qt/plugins/styles 1536 ./sxtool/PyQt5/Qt/plugins 1536 ./sxtool/PyQt5/Qt 2208 ./sxtool/PyQt5/QtCore.pyd 2292 ./sxtool/PyQt5/QtGui.pyd 4924 ./sxtool/PyQt5/QtWidgets.pyd 108 ./sxtool/PyQt5/sip.pyd 11068 ./sxtool/PyQt5 60 ./sxtool/python3.dll 3756 ./sxtool/python37.dll 5780 ./sxtool/Qt5Core.dll 6192 ./sxtool/Qt5Gui.dll 5412 ./sxtool/Qt5Widgets.dll 1504 ./sxtool/sxtool.exe 4 ./sxtool/sxtool.exe.manifest 34396 ./sxtool ``` Et une fois compressé, ça donne: ``` 10260 ./sxtool-1.1.zip ``` Ça nous fait donc 10 MOctets à télécharger, et 34 Moctets une fois installé. Ca reste trop à mon goût mais je commence à manquer d'idées facile à mettre en place. Ce qui prend beaucoup de place, c'est clairement les DLL Qt et les bindings Qt en pyd. Pour les DLL Qt, il y a surement moyen de faire mieux. Ces DLLs provienennt de l'installation par défaut de PyQt, qui doivent embarquer un Qt configuré avec un maximum d'options. Surement qu'en le recompilant à la mano et en virant toutes les options, ça doit être plus petit. J'avoue que j'ai un peu la flemme pour aujourd'hui. L'étape d'après serait de voir s'il est possible dans un module Qt de ne pas tout embarquer. C'est une petit application, je n'utilise que très peu de Qt: QtCore: * Qt, pyqtSignal, QFont, QRegExpValidator, QMetaObject, QRegExp, QCoreApplication, QSize, QRect QtWidgets: * QAbstractItemView, QAction, QActionGroup, qApp, QApplication, QCheckBox, QComboBox, QDialog, QDialogButtonBox, QFileDialog, QGridLayout * QGroupBox, QHBoxLayout, QHeaderView, QInputDialog, QLabel, QLineEdit, QMainWindow, QMenu, QMenuBar, QMessageBox, QPushButton, QRadioButton * QSizePolicy, QSpinBox, QTableWidget, QTableWidgetItem, QVBoxLayout, QWidget QtGui: * QFont, QRegExpValidator Si je pouvais configurer Qt et PyQt pour n'embarquer que ces modules là et leurs dépendances, je suis sur que je passerai sous les 10 Moctets. Il y a quand même 203 classes dans QtWidgets et j'en utilise 29. Maintenant que c'est dit, j'ai jamais entendu parlé d'un outil ou tutorial qui ferait ça. Et ça doit pas être aussi simple que ça en a l'air. Je vais m'arrêter là pour aujourd'hui. Mon bilan de réduction est de 60% moyennant environ 2h de boulot. Je suis content, mais si je suppute que je vais devoir remettre les runtime MSVP4 et les autres lib. Ca fait réfléchir quand même. Je me souviens d'une époque lointaine où quand on lançait Py2exe, on passait ensuite deux jours à rajouter une par une toutes les DLLs nécessaires et on se prenait la tête à coup de dlldepend. Il fallait quand même être un power-developer. Et encore, c'était déjà une grosse simplification de l'usage par rapport a cx_freeze. PyInstaller fait clairement bien le boulot aujoud'hui puisque cette étape n'est plus nécessaire. La vie du développeur est simplifiée, mais est-ce qu'elle n'est pas devenue trop simple ? Ca veut dire qu'un développeur qui n'a pas envie de se prendre la tête comme je l'ai fait va livrer les 86 Moctets de binaire. Donc 60% de trucs inutiles. J'aimerai bien jeter un coup d'œil de prêt au clavier Android pour voir si on est dans la même situation...