Ich versuche, ein Software-Plug-in zu schreiben, das Python einbettet. Unter Windows ist das Plug-in technisch eine DLL (dies kann relevant sein). Die Python Windows-FAQ lautet:
1.Do nicht bauen Sie Python direkt in Ihre EXE-Datei ein. Unter Windows muss Python eine DLL sein, um Module zu importieren, die selbst DLLs sind. (Dies ist der erste nicht dokumentierte Schlüssel.) Stattdessen verknüpfen Sie mit pythonNN.dll; Es wird normalerweise in C: \ Windows \ System installiert. NN ist die Python-Version, eine Nummer wie "23" für Python 2.3.
Meine Frage ist warum genau Python eine DLL sein muss? Wenn, wie in meinem Fall, die Host-Anwendung keine .exe, sondern auch eine DLL ist, könnte ich Python darin einbauen? Oder vielleicht, dieser Hinweis bedeutet, dass C-Erweiterungen von Drittanbietern auf pythonN.N.dll
vorhanden sein und andere DLL nicht tun? Angenommen, ich würde wirklich eine einzelne DLL haben wollen, was soll ich tun?
Ich sehe, dass es die Datei dynload_win.c
gibt, die das Modul zum Importieren von C-Erweiterungen unter Windows zu sein scheint, und, soweit ich das sehen kann, scannt sie die Erweiterungsdatei, um herauszufinden, welche pythonX.X.dll
sie importiert; aber ich habe keine Erfahrung mit Windows und ich verstehe nicht den ganzen Code dort.
Sie müssen eine Verknüpfung zu pythonXY.dll
als DLL herstellen, anstatt den relevanten Code direkt mit Ihrer ausführbaren Datei zu verknüpfen, da die Python-Laufzeitumgebung sonst keine anderen DLLs laden kann on.) Wenn Sie Ihre eigene DLL erstellen, könnten Sie theoretisch den gesamten Python-Code in dieser DLL direkt verknüpfen, da er nicht in der ausführbaren Datei, sondern immer noch in einer DLL endet. Sie müssen jedoch darauf achten, die Verknüpfung richtig zu machen, da so ziemlich kein Standardwerkzeug (wie disttitils) dies für Sie tun wird.
Unabhängig davon, wie Sie Python einbetten, können Sie jedoch weder mit nur der DLL auskommen, noch mit einer DLL. Der ABI wechselt zwischen den Python-Versionen. Wenn Sie also Ihren Code gegen Python 2.6 kompiliert haben, benötigen Sie python26.dll
; Sie können python25.dll
oder python27.dll
nicht verwenden. Und Python ist nicht nur eine DLL; Es benötigt auch seine Standardbibliothek, die Erweiterungsmodule enthält (die DLLs selbst sind, obwohl sie die Erweiterung .pyd
haben). Der Code in dynload_win.c
, in den Sie hineingeraten sind, lädt diese DLLs und beziehen sich nicht auf das Laden von pythonXY.dll
.
Kurz gesagt, um Python in Ihr Plugin einzubetten, müssen Sie entweder Python mit dem Plugin ausliefern oder verlangen, dass die richtige Python-Version bereits installiert ist.
On * nix, alle gemeinsam genutzten Objekte in einem Prozess, einschließlich der ausführbaren Datei, tragen ihre exportierten Namen in einen gemeinsamen Pool ein; Jedes der gemeinsam genutzten Objekte kann dann einen der Namen aus dem Pool abrufen und sie so verwenden, wie sie möchten. Dies ermöglicht z.B. cStringIO.so
, um die relevanten Python-Bibliotheksfunktionen aus der Hauptdatei abzurufen, wenn die Python-Bibliothek statisch verknüpft ist.
Unter Windows verfügt jedes gemeinsam genutzte Objekt über einen eigenen unabhängigen Pool von Namen, den es verwenden kann. Dies bedeutet, dass es die relevanten verschiedenen gemeinsamen Objekte lesen muss, von denen es Funktionen benötigt. Da es sehr aufwendig ist, alle Namen von der Hauptdatei abzurufen, werden die Python-Funktionen in eine eigene DLL getrennt.
(Sorry, ich habe eine blöde Sache gemacht, zuerst habe ich die Frage geschrieben und dann registriert, und jetzt kann ich sie nicht ändern oder die Antworten kommentieren, weil die Engine von StackOverflow nicht denkt, dass ich der Autor bin richtig danke denen, die geantwortet haben :( Also das ist eigentlich ein Update zu der Frage und den Kommentaren.)
Danke für all die Ratschläge, es ist sehr wertvoll. Soweit ich mit einiger Mühe verstehe, kann ich Python statisch in eine benutzerdefinierte DLL einbinden, vorausgesetzt, ich kompiliere andere dynamisch geladene Erweiterungen selbst und verknüpfe sie mit derselben DLL. (Ich weiß, dass ich auch die Standardbibliothek liefern muss. Mein Plan war es, ein gezipptes Archiv an die DLL-Datei anzuhängen. Soweit ich es verstehe, werde ich sogar in der Lage sein, reine Python-Module daraus zu importieren.)
Ich habe auch einen interessanten Platz in dynload_win.c
gefunden. (Ich verstehe, dass es dynamische Erweiterungen lädt, die Python C API benutzen, zB _ctypes
.) Soweit ich sehen kann, sucht es nicht nur nach init_ctypes
Symbol oder was auch immer der Erweiterungsname ist, sondern durchsucht auch den Import der .pyd
Datei Die Tabelle sucht nach (regex) python\d+\.
und vergleicht dann das gefundene Symbol mit dem bekannten pythonNN.
-Zeichen, um sicherzustellen, dass die Erweiterung für diese Version von Python kompiliert wurde. Wenn die Importtabelle kein solches Symbol enthält oder auf eine andere Version verweist, wird ein Fehler ausgegeben.
Für mich bedeutet das:
pythonNN.dll
verbinde und versuche, sie von meiner benutzerdefinierten DLL zu laden, die ein statisch verknüpftes Python enthält, wird sie die Prüfung bestehen, aber - nun, ich bin mir nicht sicher: Wird es scheitern, weil es da ist nein pythonNN.dll
(also noch bevor du zum check gehst) oder es wird fröhlich die symbole laden? Ich denke, ich könnte dieses Stück so umschreiben, dass es meinen Bedürfnissen entspricht ... Gibt es noch andere solche Orte, frage ich mich.
Python muss eine DLL (mit einem Standardnamen) sein, so dass Ihre Anwendung und das Plugin dieselbe Instanz von Python verwenden können.
Plugin-DLLs werden bereits erwarten, dass sie eine python26.dll (oder eine andere Version) laden (und python verwenden) - wenn Ihr Python statisch in Ihrer exe eingebettet ist, würden zwei verschiedene Instanzen der Python-Bibliothek verwaltet werden die gleichen Datenstrukturen.
Wenn die Python-Bibliotheken überhaupt keine statischen Variablen verwenden und die Kompilierungseinstellungen genau gleich sind, sollte dies kein Problem darstellen. Im Allgemeinen ist es jedoch weitaus sicherer, sicherzustellen, dass nur eine Instanz des Python-Interpreters verwendet wird.