Samowystarczalne aplikacje Pythona cz. 2
W poprzednim wpisie opisałem jak w prosty sposób z plików .py (.pyw) zbudować samowystarczalne aplikacje Pythona. Podałem zalety i wady tego rozwiązania. Najpoważniejszą wadą jest dość duży rozmiar aplikacji. Poza tym zamiast plików zip, których zawartość należy rozpakować, lepszy byłby instalator exe, który zainstaluje aplikację i np. utworzy na pulpicie skrót do programu.
W tym wpisie skorzystamy z narzędzi cx_freeze, upx oraz NSIS. Pierwszy z nich działa podobnie do py2exe, drugi posłuży do znacznego zredukowania rozmiarów plików, a trzeci do utworzenia instalatora.
Spolszczenie interfejsu
Załóżmy, że napisaliśmy aplikację z interfejsem graficznym wykorzystującym PySide lub PyQt4. Aby dokonać spolszczenia interfejsu skopiujmy plik qt_pl.qm z katalogu [code]C:\Python27\Lib\site-packages\PyQt4\translations[/code] do folderu zawierającego główny plik naszej aplikacji, np. main.pyw.
Plik main.pyw może mieć postać:
# -*- coding: utf-8 -*- import sys from PySide.QtCore import QTranslator from PySide.QtGui import QApplication from my_form import MyForm app = QApplication(sys.argv) mytranslator = QTranslator() mytranslator.load('qt_pl') app.installTranslator(mytranslator) myapp = MyForm() myapp.show() app.exec_()
Po zastosowaniu klasy QTranslator i załadowaniu pliku qt_pl.qm otrzymujemy program z polskim interfejsem.
setup.py
Przechodzimy do napisania skryptu setup.py. Przykładowy plik może wyglądać tak:
# -*- coding: utf-8 -*- from cx_Freeze import setup, Executable exe = Executable( script = "main.pyw", base = "Win32GUI", icon = "my_icon.ico", compress = True, appendScriptToExe = True, appendScriptToLibrary = False, copyDependentFiles = True ) setup( name = "Samowystarczalny", version = "1.0", description = "Samowystarczalna aplikacja Pythona", author = "Krystian", author_email = "my_email@my_email.my", executables = [exe], options = { 'build_exe' : { 'excludes' : [], 'packages' : ["encodings"], 'include_files' : ["qt_pl.qm"], 'compressed' : True, 'create_shared_zip' : False, } } )
Opis użytych poleceń oraz ogólną zasadę działania cx_freeze znajdziemy w (niedawno odświeżonej) dokumentacji.
Budowa aplikacji
Uruchamiamy wiersz poleceń (cmd) i przechodzimy do folderu z plikiem głównym main.pyw, plikiem setup.py oraz plikami qt_pl.qm, my_icon.ico i wydajemy polecenie:
setup.py build
W wyniku działania polecenia otrzymujemy folder build/exe.win32-2.7.
Kompresja upx
Nietrudno zauważyć, że największe pliki w folderze build to pliki biblioteki Qt. Do ich zmniejszenia wykorzystamy program upx.
Po pobraniu i rozpakowaniu programu wydajemy kolejno polecenia:
upx --ultra-brute QtCore4.dll upx --ultra-brute QtGui4.dll upx --ultra-brute PySide.QtCore.pyd upx --ultra-brute PySide.QtGui.pyd
uwzględniając właściwą ścieżkę do programu upx oraz kompresowanych plików.
Opcja ultra-brute daje najlepsze rezultaty, chociaż na efekt końcowy będziemy musieli chwilę poczekać. Otrzymane w ten sposób pliki warto "zachować na później" i w miarę potrzeby nadpisywać oryginalne pliki tymi o dużo mniejszym rozmiarze.
Utworzenie instalatora
Na koniec przydałoby się stworzenie instalatora dla naszego programu. W tym celu można skorzystać z NSIS.
Spakujmy do formatu zip zawartość katalogu build/exe.win32-2.7 (zawartość, a nie katalog exe.win32-2.7!!!) nadając mu wybraną przez nas nazwę, np. Samowystarczalny.zip.
Następnie uruchamiamy NSIS:
Interesuje nas opcja Installer based on ZIP file.
Wskazujemy plik zip, definiujemy domyślą lokalizację instalowanego programu i wciskamy "Generate". W wyniku działania programu otrzymujemy wygodny instalator w postaci pojedynczego pliku exe.
Utworzenie deinstalatora, skrótów do programu itd. wymaga modyfikacji plików znajdujących się w folderze [code]C:\Program Files (x86)\NSIS\Contrib\zip2exe[/code] i nie jest przedmiotem tego wpisu. Zainteresowanych odsyłam do dokumentacji programu NSIS lub tutoriali dostępnych w internecie.
Poniżej przedstawię jedynie zawartość pliku modern.nsh.
;Change this file to customize zip2exe generated installers with a modern interface !include "MUI.nsh" !insertmacro MUI_PAGE_DIRECTORY !insertmacro MUI_PAGE_INSTFILES !insertmacro MUI_LANGUAGE "Polish"