Skip to content

Python Scripte mit PyInstaller als .exe verteilen

Python

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)
Sowie diverse andere, abhängig von Betriebssystem und Verwendeter Python-Version (z.B. Microsoft Visual Studio für IronPython, die .NET Version von Python).

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.

  1. C:\> cd C:\Python24\PyInstaller_1.2\
  2. C:\Python24\PyInstaller_1.2> Configure.py
  3. I: computing EXE_dependencies
  4. I: Finding TCL/TK...
  5. I: found TCL/TK version 8.4
  6. I: testing for Zlib...
  7. I: ... Zlib available
  8. I: Testing for ability to set icons, version resources...
  9. I: ... resource update available
  10. I: Testing for Unicode support...
  11. I: ... Unicode available
  12. I: testing for UPX...
  13. I: ...UPX unavailable
  14. I: computing PYZ dependencies...
  15.  
  16. 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\:

  1. #!/usr/bin/env python
  2. print "hello world!"


Für dieses einfache Programm wird nun die .spec-Datei erstellt:

  1. C:\Test> C:\Python24\PyInstaller_1.2\Makespec.py helloworld.py
  2. wrote C:\test\helloworld.spec
  3. 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:

  1. a = Analysis([os.path.join(HOMEPATH,'support\\_mountzlib.py'), os.path.join(HOMEPATH,'support\\useUnicode.py'), 'helloworld.py'],
  2.              pathex=['C:\\test'])
  3. pyz = PYZ(a.pure)
  4. exe = EXE(pyz,
  5.           a.scripts,
  6.           exclude_binaries=1,
  7.           name='buildhelloworld/helloworld.exe',
  8.           debug=False,
  9.           strip=False,
  10.           upx=False,
  11.           console=True )
  12. coll = COLLECT( exe,
  13.                a.binaries,
  14.                strip=False,
  15.                upx=False,
  16.                name='disthelloworld')
  17.  


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:

  1. -F, --onefile
  2.         Erstellt eine einzelne Datei, die alles beinhaltet.
  3.  
  4. -D, --onedir
  5.         Erstellt ein Verzeichnis mit allen benötigten Dateien (default).
  6.  
  7. -w, --windowed, --noconsole    
  8.         Das zu erstellende Programm wird als Windows Programm gestartet
  9.         ohne eine Konsole dafür zu öffnen.
  10.  
  11. -o DIR, --out=DIR
  12.         Erstellt die .spec-Datei im angegebenen Verzeichnis. Wenn nicht
  13.         angegeben und das aktuelle Verzeichnis ist das PyInstaller-
  14.         Verzeichnis, wird ein Unterverzeichnis angelegt und dort die
  15.         .spec Datei hineingeschrieben. Steht man in einem anderen
  16.         Verzeichnis, so wird die .spec-Datei in das aktuelle Verzeichnis
  17.         geschrieben.
  18.  
  19. --icon=<file.ico>    
  20.         Fügt dem zu erstellenden Programm das Icon FILE.ICO hinzu.
  21.  
  22. --icon=<file.exe,n>
  23.         Fügt dem zu erstellenden Programm das N-te Icon aus FILE.EXE
  24.         hinzu.
  25.  
  26. -n NAME, --name=NAME
  27.         Gibt dem Programm einen Namen. Wenn dieser Name nicht angegeben
  28.         wird bekommt das zu erstellende Programm den Namen des ersten
  29.         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:

  1. C:\test> c:\Python24\pyinstaller_1.2\Build.py helloworld.spec
  2. checking Analysis
  3. building Analysis because out0.toc non existent
  4. running Analysis out0.toc
  5. Analyzing: c:\Python24\pyinstaller_1.2\support\_mountzlib.py
  6. Analyzing: c:\Python24\pyinstaller_1.2\support\useUnicode.py
  7. Analyzing: helloworld.py
  8. Warnings written to C:\test\warnhelloworld.txt
  9. checking PYZ
  10. rebuilding out1.toc because out1.pyz is missing
  11. building PYZ out1.toc
  12. checking PKG
  13. rebuilding out3.toc because out3.pkg is missing
  14. building PKG out3.pkg
  15. checking ELFEXE
  16. rebuilding out2.toc because helloworld.exe missing
  17. building ELFEXE out2.toc
  18. checking COLLECT
  19. building out4.toc because out4.toc missing
  20. 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.

Trackbacks

Keine Trackbacks

Kommentare

Ansicht der Kommentare: Linear | Verschachtelt

Marco am :

Hi Namensvetter,

ist diese Exe-Fassung bei allen Python Skripten möglich? Also z.B. auch bei jenen, die eine GUI verwenden?

Ciao,
M

Marco am :

hi namensvetter,

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 :

Kannst Du mir eventuell auch verraten, um wieviel die .exe circa (!) größer wird? (Evtl. gibt es ja einen "festen Bestandteil", den man immer zur Skriptgröße addieren kann.) Vielleicht hast Du ja einen Pi-mal-Daumen-Erfahrungswert.

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 :

um wieviel sie größer wird ist schwer zu beantworten, weil das vom verwendeten GUI toolkit abhängt. bei wxpython sind es ein paar mb (ca. 2-6 je nach verwendeter kompression), weil die verwendete dll eben diese paar mb mitbringt. bei tkinter ist es weniger, sagt mir aber von der optik nicht zu. bei "venster" ist es kaum der rede wert, aber da musst du dich mit den windows-api funktionen rumschlagen.

- 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 :

Dass es keinen Performance-Unterschied gibt ist falsch. Zum einen müssen die benötigten Dateien vor der Ausführung des Skripts in einen temp-Ordner gepackt warden, das dauert ein paar Sekunden. Und zum anderen habe ich gerade mal einen Performance-Test mit einem Plotting-Skript laufen lassen. Das Skript als .exe läuft ca. 3-4 mal länger als die reine Skriptversion...

Thomas am :

Hallo Marco,
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 :

hi thomas. auf anhieb kann ich zwar nicht helfen, aber vielleicht schaust du dir mal die .spec datei mit einem editor an. vielleicht kannst du ohne die option leben, in dem du die datei selbst änderst um das icon einzubinden.

Chris am :

Hallo Marco, schönes Tutorial.
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 :

Na, das kam gerade zu rechten Zeit. Ich bin gerade dabei, dass deployment für ein wxpython-Programm zu erarbeiten.

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 :

Hallo,
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 :

Hast du denn die Win32 extensions installiert? Die werden benötigt, um die entsprechenden dlls zu laden/finden.

Markus am :

Hallo,
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 :

Nein^^
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! :-D

Gruß Markus

Marco am :

steht sogar in der fehlermeldung mit drin :-)

http://starship.python.net/skippy/win32/Downloads.html

Markus am :

Ja, danke, habe das mit dem Link auch schon gesehen^^
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? :-D

Liebe Grüße Markus

Markus am :

Hallo nochmal,
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 :

Erstmal vielen dank für dieses tutorial :-D
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 :

Hallo Marco,

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 :

mal ne Frage:
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 :

Vielen Dank für das super Tutorial!! Ich hab nun eine Frage zu einem etwas umfangreicheren Programm. Undzwar besteht mein Programm auch aus unterordnern wo diverse Module sind.
Kann ich mein Hauptprogramm ink. allen dazugehörigen dateien in einer .exe umwandeln? Wenn ja wie?

Alex am :

Hallo Marco,

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 :

Wie geht es mit einer gui?
muss man da beide dateien auf einmal?

Franz am :

wo muss man das -F, --onefile eingeben da kommt immer f ist unbekannt??????

Kommentar schreiben

Standard-Text Smilies wie :-) und ;-) werden zu Bildern konvertiert.
Die angegebene E-Mail-Adresse wird nicht dargestellt, sondern nur für eventuelle Benachrichtigungen verwendet.
Um einen Kommentar hinterlassen zu können, erhalten Sie nach dem Kommentieren eine E-Mail mit Aktivierungslink an ihre angegebene Adresse.
BBCode-Formatierung erlaubt
Sie können [geshi lang=LANG][/lang] Tags verwenden um Quellcode abhängig von der gewählten Programmiersprache einzubinden
Formular-Optionen
tweetbackcheck cronjob