Python Scripte mit PyInstaller als .exe verteilen
Wozu der Aufwand?
Es kommt der Tag, an dem man seine Python Scripte ausserhalb seiner Entwicklungsumgebung einsetzen möchte. Von anderen Programmiersprachen kennt man die Möglichkeit, die Programme zu compilieren und diese unter Windows als ausführbare .exe oder .dll Dateien zu verteilen.
Compilieren im eigentlichen Sinn lässt sich ein Python Script nicht. Man kann jedoch Python Scripte auch in .exe verwandeln und diese verteilen. Der Grund dafür kann sein, daß man nicht überall eine installierte Python-Umgebung voraussetzen möchte oder auch um seinen Quellcode gegen neugierige Blicke oder Änderungen zu schützen. In diesen .exe-Dateien wird dann neben dem Script noch eine Python-Laufzeitumgebung und benötigte Bibliotheken mit eingepackt, so daß alle benötigten Bestandteile dabei sind und das Programm sofort auf dem Zielrechner ausführbar ist.
Welche Möglichkeiten gibt es?
Es gibt mehrere Möglichkeiten, aus Python Scripten solche ausführbaren Programme zu erstellen:- PyInstaller (Für Linux und Windows, alle Python-Versionen seit 1.5, wird noch aktiv entwickelt, kann eine einzelne Datei erstellen)
- py2exe (wird oft und gerne benutzt, hat mir persönlich aber ein paar Einschränkungen, die man beim Programmieren beachten muss, hat Schwierigkeiten mit manchen Bibliotheken)
- McMillan's Installer (aus dem PyInstaller entstand)
Beispielhafte Anwendung mit PyInstaller
1. PyInstaller herunterladen und entpacken
PyInstaller gibt es als .zip Archiv für Windows auf der Projekthomepage zum Download. Aktuell beim Verfassen dieses Artikels ist die Version 1.2. Die herunter geladene Archivdatei pyinstaller_1.2.zip entpackt man in einem Pfad seiner Wahl. Ich gehe im Folgenden davon aus, daß dies C:\Python24\PyInstaller_1.2\ ist.2. PyInstaller konfigurieren
PyInstaller muss vor der ersten Verwendung auf dem System konfiguriert werden. Damit stellt PyInstaller fest welche Version von Python verwendet werden soll, welche Optionen verfügbar sind, ob Zlib, Unicode oder UPX verfügbar sind und ein paar Dinge mehr. Das ist allerdings recht einfach, da PyInstaller selbst diese Konfiguration vornimmt.
- C:\> cd C:\Python24\PyInstaller_1.2\
- C:\Python24\PyInstaller_1.2> Configure.py
- I: computing EXE_dependencies
- I: Finding TCL/TK...
- I: found TCL/TK version 8.4
- I: testing for Zlib...
- I: ... Zlib available
- I: ... resource update available
- I: Testing for Unicode support...
- I: ... Unicode available
- I: testing for UPX...
- I: ...UPX unavailable
- I: computing PYZ dependencies...
- C:\Python24\pyinstaller_1.2>
Damit ist die Konfiguration abgeschlossen. PyInstaller ist jetzt bereit, auf diesem System ausführbare Dateien zu erstellen.
3. Spec-File erstellen
Eine .spec-Datei beschreibt das später zu erstellende Programm. Das Testprogramm ist eine einfache helloworld.py im Ordner C:\Test\:- #!/usr/bin/env python
- print "hello world!"
Für dieses einfache Programm wird nun die .spec-Datei erstellt:
- C:\Test> C:\Python24\PyInstaller_1.2\Makespec.py helloworld.py
- wrote C:\test\helloworld.spec
- now run Build.py to build the executable
Danach steht im gleichen Ordner zusätzlich unsere .spec-Datei, die Anweisungen für den eigentlichen PyInstaller enthält:
- a = Analysis([os.path.join(HOMEPATH,'support\\_mountzlib.py'), os.path.join(HOMEPATH,'support\\useUnicode.py'), 'helloworld.py'],
- pathex=['C:\\test'])
- pyz = PYZ(a.pure)
- exe = EXE(pyz,
- a.scripts,
- exclude_binaries=1,
- name='buildhelloworld/helloworld.exe',
- debug=False,
- strip=False,
- upx=False,
- console=True )
- coll = COLLECT( exe,
- a.binaries,
- strip=False,
- upx=False,
- name='disthelloworld')
Diese Datei kann nun auch bearbeitet werden um zum Beispiel weitere Ressourcen hinzuzufügen, zum Beispiel config-Dateien, Icons, Bilder und sonstige Dateien die für den späteren Betrieb notwendig sind.
Makespec.py kennt diverse Optionen um den Prozess zu beeinflussen, wovon man jedoch in den meisten Fällen nur einige benötigt:
- -F, --onefile
- Erstellt eine einzelne Datei, die alles beinhaltet.
- -D, --onedir
- Erstellt ein Verzeichnis mit allen benötigten Dateien (default).
- -w, --windowed, --noconsole
- Das zu erstellende Programm wird als Windows Programm gestartet
- ohne eine Konsole dafür zu öffnen.
- Erstellt die .spec-Datei im angegebenen Verzeichnis. Wenn nicht
- angegeben und das aktuelle Verzeichnis ist das PyInstaller-
- Verzeichnis, wird ein Unterverzeichnis angelegt und dort die
- .spec Datei hineingeschrieben. Steht man in einem anderen
- Verzeichnis, so wird die .spec-Datei in das aktuelle Verzeichnis
- geschrieben.
- --icon=<file.ico>
- Fügt dem zu erstellenden Programm das Icon FILE.ICO hinzu.
- --icon=<file.exe,n>
- Fügt dem zu erstellenden Programm das N-te Icon aus FILE.EXE
- hinzu.
- -n NAME, --name=NAME
- Gibt dem Programm einen Namen. Wenn dieser Name nicht angegeben
- wird bekommt das zu erstellende Programm den Namen des ersten
- angegebenen Scripts.
4. Ausführbare .exe erstellen
Zu diesem letzten Schritt zieht man nun die Build.py aus dem PyInstaller-Ordner heran und füttert sie mit der oben erstellten .spec-Datei:- C:\test> c:\Python24\pyinstaller_1.2\Build.py helloworld.spec
- checking Analysis
- building Analysis because out0.toc non existent
- running Analysis out0.toc
- Analyzing: c:\Python24\pyinstaller_1.2\support\_mountzlib.py
- Analyzing: c:\Python24\pyinstaller_1.2\support\useUnicode.py
- Analyzing: helloworld.py
- Warnings written to C:\test\warnhelloworld.txt
- checking PYZ
- rebuilding out1.toc because out1.pyz is missing
- building PYZ out1.toc
- checking PKG
- rebuilding out3.toc because out3.pkg is missing
- building PKG out3.pkg
- checking ELFEXE
- rebuilding out2.toc because helloworld.exe missing
- building ELFEXE out2.toc
- checking COLLECT
- building out4.toc because out4.toc missing
- building COLLECT out4.toc
Nach diesem Schritt existieren zwei weitere Verzeichnisse unterhalb von C:\Test\:
C:\Test\buildhelloworld\ (wurde benutzt um die Dateien zusammenzuführen)
C:\Test\disthelloworld\ (enthält jetzt das weiterzugebende Programm inklusive aller benötigten Bestandteile)
Den Inhalt des Ordners disthelloworld kann man nun weitergeben und auf jedem Windows-System ausführen.
Kommentare
Ansicht der Kommentare: Linear | Verschachtelt
Marco am :
ist diese Exe-Fassung bei allen Python Skripten möglich? Also z.B. auch bei jenen, die eine GUI verwenden?
Ciao,
M
Marco am :
ja, geht auch bei gui-verwendung genauso. dann verwendet man allerdings --noconsole als option, damit man nicht immer ein terminalfenster im hintergrund hat.
Marco am :
Und noch was: Gibt es denn einen großen Performance-Unterschied, zwischen .exe und dem direkt ausgeführten Skript?
Sorry für die Fragerei, aber ich suche gerade nach einer neuen Programmiersprache und irgendwie bin ich zur Zeit bei Python hängengeblieben.
Marco am :
- einen performance-unterschied zwischen .exe und der .py gibt es nicht. wenn mans beschleunigen will sollte man auf psyco oder einen anderen python-interpreter zurückgreifen.
python ist eine gute wahl für viele dinge .
Philipp am :
Thomas am :
erstmal vielen Dank für dieses Tutorial. Es hat mir bei der Benutzung des Programmes sehr geholfen. Jetzt stehe ich inzwischen nur vor dem Problem, dass ich bei dem Erstellen einer --onefile auch gleich noch das icon von Tkinter mit integrieren will. In einem US-Forum habe ich dazu den Beitrag eines der Entwickler gelesen:"If you specify it as icon (--icon to Makespec), it means you want it as icon
of the executable.(wie in deiner Beschreibung)
If you just want to add it as an additional data file (genau das was ich bräuchte), read the manual about
that."
Tja, und da stand ich jetzt und habe "that" zusammen mit meinem Bruder fast 5 Stunden lang versucht im Manual die passende Option oder was auch immer, herauszufinden. Wenn du also einen Tipp hättest, wie ich das bewerkstelligen könnte, wäre ich dir sehr dankbar.
Gruß Thomas
Marco am :
Chris am :
Ich suche nach einer Möglichkeit aus Python Code eine "normale" Windows DLL zu erstellen, mit PyInstaller hab ich bisher nur COM-DLL´s erstellen können. Gibt es dazu auch eine Möglichkeit?
Ciao
Chris
Norbert Klamann am :
Ich habe pyinstaller runtergeladen und es kann die Exe bauen. Das Drumherum ist superfett, ich habe allerdings nicht komprimiert.
Ich werde später noch einige Ressourcen wie Textdateien für Meldungen brauchen. Mal schauen, wie das klappt.
Hat jemand Erfahrungen, wie man aus dem ganzen dann ein Installer-Skript macht ?
Gruss und Danke für den Aufschrieb !
Norbert
Markus am :
danke für die ausführliche Beschreibung! Ich habe lange danach gesucht, wollte meine Scripte in EXE-Files umwandeln
Bei mir gibt es allerdings schon im ersten Schritt, nämlich dem ausführen der Configure.py Datei einen Fehler! Ich habe es nicht per Eingabeaufforderung wie du gemacht, sondern einfach Configure.py geöffnet und ausgeführt, dabei gab es drei Fehler, die mit einem "W" anstatt einem "I" begannen...
Das ist der Text, der rauskam(siehe zum Fehler Zeile 2 f.)
I: computing EXE_dependencies
W: Cannot determine your Windows or System directories
W: Please add them to your PATH if .dlls are not found
W: or install starship.python.net/skippy/win32/Downloads.html
I: Finding TCL/TK...
I: found TCL/TK version 8.4
I: testing for Zlib...
I: ... Zlib available
I: Testing for ability to set icons, version resources...
I: ... resource update unavailable - No module named win32api
I: Testing for Unicode support...
I: ... Unicode available
I: testing for UPX...
I: ...UPX unavailable
I: computing PYZ dependencies...
Weißt du, was das für ein Fehler sein könnte?
Gruß Markus
Marco am :
Markus am :
danke für die ausführliche Beschreibung! Ich habe lange danach gesucht, wollte meine Scripte in EXE-Files umwandeln.
Bei mir gibt es allerdings schon im ersten Schritt, nämlich dem ausführen der Configure.py Datei einen Fehler! Ich habe es nicht per Eingabeaufforderung wie du gemacht, sondern einfach Configure.py geöffnet und ausgeführt, dabei gab es drei Fehler, die mit einem "W" anstatt einem "I" begannen...
Das ist der Text, der rauskam(siehe zum Fehler Zeile 2 f.)
I: computing EXE_dependencies
W: Cannot determine your Windows or System directories
W: Please add them to your PATH if .dlls are not found
W: or install starship.python.net/skippy/win32/Downloads.html
I: Finding TCL/TK...
I: found TCL/TK version 8.4
I: testing for Zlib...
I: ... Zlib available
I: Testing for ability to set icons, version resources...
I: ... resource update unavailable - No module named win32api
I: Testing for Unicode support...
I: ... Unicode available
I: testing for UPX...
I: ...UPX unavailable
I: computing PYZ dependencies...
Weißt du, was das für ein Fehler sein könnte?
Gruß Markus
Markus am :
Wusste nicht, dass man das instalieren muss *peinlich*
Hat jemand einen passenden Link, da ich nicht weiß, welche Extrensions das genau sind? Das wäre super!
Gruß Markus
Marco am :
http://starship.python.net/skippy/win32/Downloads.html
Markus am :
ich habe mir die Extensions installiert von win32, jetzt läuft die Configure.py Datei auch wunderbar durch, aber nun gibt es ein Problem mit dem Erstellen der .spec-Datei!
Wenn ich bei Eingabeaufforderung sage:
>Makespec.py helloworld
dann passiert.. rein garnichts! Es wird weder gesagt "wrote spec" oder etwas in der Art, das einzige, er öffnet die Makespec.py und fragt mich, mit was ich die öffnen will (ich sage dann natürlich Python)!??
Hat da jemand eine Idee, warum das nicht klappt?
Liebe Grüße Markus
Markus am :
ich habe versucht das Icon meines Programmes einzufügen und es hat im IDLE auch funktioniert, aber wenn ich es zum Exe-file mache, dann startet das ganze Programm erst gar nicht...
Lösche ich die Zeile mit dem Icon-Ersetzen, dann klappt es wieder -.- Also definitiv hängt das mit den Icons zusammen.
Die fehlermeldungen, die in der Warn stehen sind diese hier:
W: no module named posix (conditional import by os)
W: no module named optik.__all__ (top-level import by optparse)
W: no module named fcntl (top-level import by tempfile)
W: no module named readline (delayed, conditional import by cmd)
W: no module named readline (delayed import by pdb)
W: no module named pwd (delayed, conditional import by posixpath)
W: no module named MacOS (top-level import by Tkinter)
W: no module named org (top-level import by pickle)
W: no module named _imaging_gif (top-level import by GifImagePlugin)
W: no module named posix (delayed, conditional import by iu)
W: no module named fcntl (conditional import by subprocess)
W: no module named org (top-level import by copy)
W: no module named _emx_link (conditional import by os)
W: no module named optik.__version__ (top-level import by optparse)
W: no module named Carbon (conditional import by tempfile)
W: __all__ is built strangely at line 0 - __future__ (C:\Programme\Python\lib\__future__.pyc)
W: delayed conditional __import__ hack detected at line 0 - doctest (C:\Programme\Python\lib\doctest.pyc)
W: delayed exec statement detected at line 0 - doctest (C:\Programme\Python\lib\doctest.pyc)
W: delayed __import__ hack detected at line 0 - encodings (C:\Programme\Python\lib\encodings\__init__.pyc)
W: delayed conditional __import__ hack detected at line 0 - Image (C:\Programme\Python\lib\site-packages\PIL\Image.pyc)
W: delayed exec statement detected at line 0 - Tkinter (C:\Programme\Python\lib\lib-tk\Tkinter.pyc)
W: __all__ is built strangely at line 0 - optparse (C:\Programme\Python\PyInstaller-1.3\optparse.pyc)
W: __all__ is built strangely at line 0 - dis (C:\Programme\Python\lib\dis.pyc)
W: delayed eval hack detected at line 0 - os (C:\Programme\Python\lib\os.pyc)
W: delayed conditional __import__ hack detected at line 0 - unittest (C:\Programme\Python\lib\unittest.pyc)
W: delayed conditional __import__ hack detected at line 0 - unittest (C:\Programme\Python\lib\unittest.pyc)
W: __all__ is built strangely at line 0 - tokenize (C:\Programme\Python\lib\tokenize.pyc)
W: delayed conditional exec statement detected at line 0 - iu (C:\Programme\Python\PyInstaller-1.3\iu.pyc)
W: delayed conditional exec statement detected at line 0 - iu (C:\Programme\Python\PyInstaller-1.3\iu.pyc)
W: delayed exec statement detected at line 0 - bdb (C:\Programme\Python\lib\bdb.pyc)
W: delayed eval hack detected at line 0 - bdb (C:\Programme\Python\lib\bdb.pyc)
W: delayed eval hack detected at line 0 - bdb (C:\Programme\Python\lib\bdb.pyc)
W: delayed __import__ hack detected at line 0 - pickle (C:\Programme\Python\lib\pickle.pyc)
W: delayed __import__ hack detected at line 0 - pickle (C:\Programme\Python\lib\pickle.pyc)
W: delayed eval hack detected at line 0 - gettext (C:\Programme\Python\lib\gettext.pyc)
W: delayed __import__ hack detected at line 0 - optik.option_parser (C:\Programme\Python\PyInstaller-1.3\optik\option_parser.pyc)
W: delayed conditional eval hack detected at line 0 - warnings (C:\Programme\Python\lib\warnings.pyc)
W: delayed conditional __import__ hack detected at line 0 - warnings (C:\Programme\Python\lib\warnings.pyc)
W: __all__ is built strangely at line 0 - optik (C:\Programme\Python\PyInstaller-1.3\optik\__init__.pyc)
W: delayed exec statement detected at line 0 - pdb (C:\Programme\Python\lib\pdb.pyc)
W: delayed conditional eval hack detected at line 0 - pdb (C:\Programme\Python\lib\pdb.pyc)
W: delayed eval hack detected at line 0 - pdb (C:\Programme\Python\lib\pdb.pyc)
W: delayed conditional eval hack detected at line 0 - pdb (C:\Programme\Python\lib\pdb.pyc)
W: delayed eval hack detected at line 0 - pdb (C:\Programme\Python\lib\pdb.pyc)
Hat jemand eine Ahnung, was die bedeuten und wie ich es zum Laufen bekomme?!
Nebenbei funzt auch nicht die Funktion dem Exefile ein Icon zuzuweisen als Bild... (per --icon=FILE.ICO)
Und warum kann man eigentlich überhaupt kein Programm schreiben, bei dem es keinen Fehler gibt, und in der warn.txt. einfach mal nichts steht? Selbst bei einem hello-world programm gibt es fehler, was ich nicht verstehe...
Viele Grüße Markus
Alexander am :
Endlich hab ich es geschafft eine Aanleitung zu finden die sogar ich verstehe ^^
@ Markus:
also bei mir funktioniert --icon=icon.ico bestens?! Ich habe "--onefile --icon=icon.ico" rangehängt und dann mit build.py erstellt, er hat es direkt als eine exe Datei ausgegeben und das gewählte Icon mit eingebunden :?
Ich hab mal alles hochgeladen, vielleicht wirst du dadraus schlauer:
http://www.file-upload.net/download-1507086/Script.zip.html
Lukas am :
ich hab leider auch schon Probleme beim ersten Schritt. Anbei die Fehlermeldung:
I: computing EXE_dependencies
Traceback (most recent call last):
File "C:\Lukas\Python\pyinstaller_1.3\Configure.py", line 48, in
toc = bindepend.Dependencies([('', python, '')])
File "C:\Lukas\Python\pyinstaller_1.3\bindepend.py", line 258, in Dependencies
dlls = getImports(pth)
File "C:\Lukas\Python\pyinstaller_1.3\bindepend.py", line 303, in getImports
return getImports2(pth)
File "C:\Lukas\Python\pyinstaller_1.3\bindepend.py", line 213, in getImports2
importva, importsz = datadirs[1]
IndexError: list index out of range
Sascha am :
wie ist das mit Python 3.1.1
weil damit geht keines der Programme. Unteranderem:
Wie ist das mit Windows 7?
Vielen Dank
Jonathan am :
Kann ich mein Hauptprogramm ink. allen dazugehörigen dateien in einer .exe umwandeln? Wenn ja wie?
Alex am :
sehr nützliches Tutorial!
Nur leider habe ich ein Problem, dass ich auch mit Deinem Tutorial nicht lösen kann.
Ich habe ein Programm mit Oberfläche geschrieben (Python 2.4 und Tkinter 8.4) mit dem man div. Dateien einlesen und bearbeiten kann. Soweit klappt auch alles prima und die exe-Datei funktioniert auch.
Nur wenn ich in meine Oberfläche eine Bilddatei einbinde funktioniert die exe nur noch wenn das Bild im selben Verzeichnis liegt. Ich habe schon probiert das .spec-file irgendwie anzupassen, aber bisher leider alles ohne Erfolg. Auch die Doku von Pyinstaller (verwende 1.3) hilft mir hier nicht wirklich weiter.
Vielleich kannst mir ja weiterhelfen, oder hast noch ein paar Anregungen?!
Gruß,
Alex
Franz am :
muss man da beide dateien auf einmal?
Franz am :