RkBlog

Hardware, programming and astronomy tutorials and reviews.

Budowanie binarnych aplikacji Mac OS X za pomocą py2app

Py2app to narzędzie do budowania ze skryptów Pythona gotowych do użycia aplikacji Mac OS X. Instalacja py2app jest prosta i sprowadza się do
sudo easy_install py2app

Budowanie aplikacji

W katalogu z naszym skryptem, aplikacją napisaną w Pythonie musimy stworzyć plik konfiguracyjny dla py2app, zazwyczaj setup.py. Oto szkielet takiego pliku:
from setuptools import setup

APP = ['NAZWA_SKRYPTU.py']
OPTIONS = {'argv_emulation': True, 'includes': ['zewnętrzna biblioteka'],}

setup(
    app=APP,
    options={'py2app': OPTIONS},
    setup_requires=['py2app'],
)
Gdzie NAZWA_SKRYPTU to nazwa głównego pliku naszej aplikacji (który uruchamia aplikację). Także jeżeli używamy z jakiś bibliotek nie wchodzących w skład Pythona to musimy podajć ich nazwy w includes. By zbudować aplikację w konsoli w katalogu skryptu wykonaj polecenie:
python setup.py py2app
Po czym w katalogu dist powstanie gotowa aplikacja. Można (a raczej wypada) wejść do jej zawartości ("Show package contents") i edytować wyświetlaną nazwę (Contents/Info.plist), czy też podmienić ikonę (Contents/Resources/PythonApplet.icns). Warto też sprawdzić czy gotowa aplikacja nie jest zbyt duża - czy nie zostały dołączone zbędne modułu (wtedy do OPTIONS można dodać listę excludes z bibliotekami do wykluczenia).
Stosując systemowego Pythona zbudowane zostaną pakiety działające tylko na tej samej wersji systemu (pakiet zbudowany pod Leopardem nie ruszy na Tigerze). By zbudować całkowicie niezależne aplikacje należy użyć "zewnętrznej" instalacji Pythona - np. z MacPortów lub Finka (plus w ich repozytoriach mamy wiele bibliotek Pythona). Budując aplikacje względem zewnętrznej instalacji Pythona należy podać pełną ścieżkę do jego pliku wykonywalnego (np. /sw/bin/python setup.py py2app)

Budowanie gotowych aplikacji PyQt4

W przypadku PyQt4 to sprawa jest trochę skomplikowana. Można skorzystać z systemowego Pythona, lub też skorzystać np. z MacPortów. W przypadku systemowego Pythona będzie parę problemów z budowaniem. Po pierwsze musimy zainstalować Qt - może być DMG dostępne na stronie QtSoftware, następnie skompilować i zainstalować w kolejności: SIP i PyQt4 (z riverbankcomputing.co.uk):
Qt Software oferuje dwa rodzaje obrazów DMG. Wersja SDK to biblioteki Intel-only, wersja "Libraries" jest Universal. Zastosowanie Uniwersalnego DMG da w efekcie Uniwersalną aplikację, lecz jej rozmiar będzie dwa razy większy. Tak więc zaleca się stosowanie obrazu SDK.
python configure.py
make # jeżeli kompilacja nie rozpoczęła się
sudo make install
Plus wszystkie inne potrzebne nam biblioteki. Gdy nasza aplikacja działa ze źródeł to można budować aplikację, oto przykładowa konfiguracja:
from setuptools import setup
 
APP = ['run.py']
OPTIONS = {'argv_emulation': True, 'includes': ['sip', 'PyQt4', 'PyQt4.QtCore', 'PyQt4.QtGui', 'simplejson'],
			'excludes': ['PyQt4.QtDesigner', 'PyQt4.QtNetwork', 'PyQt4.QtOpenGL', 'PyQt4.QtScript', 'PyQt4.QtSql', 'PyQt4.QtTest', 'PyQt4.QtWebKit', 'PyQt4.QtXml', 'PyQt4.phonon']}
 
setup(
    app=APP,
    options={'py2app': OPTIONS},
    setup_requires=['py2app'],
)
W tym przykładzie aplikacja PyQt wykorzystuje tylko QtCore i QtGui, oraz simplejson. Pozostałe komponenty PyQt należy jawnie wykluczyć, gdyż inaczej trafią do gotowej aplikacji znacząco zwiększając jej rozmiar. Po zbudowaniu aplikacja nie będzie działać, a rzuci wyjątkiem:
ImportError: '/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/lib-dynload/PyQt4/QtCore.so' not found
Musimy edytować Contents/Resources/__boot__.py i do funkcji def _run(*scripts): (na samym końcu pliku) dodać po importach wiersz:
sys.path = [os.path.join(os.environ['RESOURCEPATH'], 'lib', 'python2.5', 'lib-dynload')] + sys.path
I gotowe. Aplikacja powinna działać. Dodatkowo powinniśmy usunąć z Contents/Frameworks/* wersje *_debug bibliotek QtCore i QtGui (jako że nie są potrzebne, a zajmują sporo miejsca). Biblioteki te są w podkatalogach "Versions", np. /Contents/Frameworks/QtGui.framework/Versions/4. Po spakowaniu moja aplikacja zajmowała 12MB (około 9MB na Windowsie zbudowany za pomocą Py2exe).

W przypadku MacPortów instalujemy przez nie PyQt4, py2app, macholib, modulegraph, altgraph (wraz automatycznie z ich zależnościami). Kompilacja ze źródeł wszystkiego trochę niestety potrwa. Po instalacji można zbudować aplikację, która powinna działać bez konieczności przeprowadzania żadnych modyfikacji. Różnica w konfiguracji to dołączenie PyQt4._qt (wynikowa aplikacja może mieć większy rozmiar niż gdy budowana względem systemowego Pythona):
from setuptools import setup
 
APP = ['run.py']
OPTIONS = {'argv_emulation': True, 'includes': ['sip', 'PyQt4._qt', 'simplejson', 'PyQt4.QtCore', 'PyQt4.QtGui'],
			'excludes': ['PyQt4.QtDesigner', 'PyQt4.QtNetwork', 'PyQt4.QtOpenGL', 'PyQt4.QtScript', 'PyQt4.QtSql', 'PyQt4.QtTest', 'PyQt4.QtWebKit', 'PyQt4.QtXml', 'PyQt4.phonon']}
 
setup(
    app=APP,
    options={'py2app': OPTIONS},
    setup_requires=['py2app'],
)
Szczegółowo opisuje to Aral Balkan na swoim blogu.
RkBlog

PyQt, 10 June 2009, Piotr Maliński

Comment article