2010-10-17 17 views
8

Sto provando a scrivere un plug-in software che incorpori Python. Su Windows il plug-in è tecnicamente una DLL (questo potrebbe essere rilevante). Il Python Windows FAQ dice:Incorporare Python su Windows: perché deve essere una DLL?

1.Do non costruire Python nel file exe direttamente. Su Windows, Python deve essere una DLL per gestire i moduli di importazione che sono essi stessi DLL. (Questo è il primo elemento non documentato.) Invece, collega a pythonNN.dll; in genere è installato in C: \ Windows \ System. NN è la versione di Python, un numero come "23" per Python 2.3.

La mia domanda è perché esattamente Python deve essere una DLL? Se, come nel mio caso, l'applicazione host non è un exe, ma anche una DLL, posso creare Python in esso? O forse questa nota significa che le estensioni C di terze parti si basano su pythonN.N.dll per essere presenti e altre DLL non lo faranno? Supponendo che mi piacerebbe avere una singola DLL, , cosa devo fare?

Vedo che c'è il file dynload_win.c, che sembra essere il modulo per importare estensioni C su Windows e, per quanto posso vedere, analizza il file di estensione per trovare quale pythonX.X.dll importa; ma non ho esperienza con Windows e non capisco tutto il codice lì.

risposta

4

è necessario collegare a pythonXY.dll come DLL, invece di collegare il relativo codice direttamente nel vostro eseguibile, perché altrimenti il ​​runtime di Python non può caricare altri DLL (i moduli di estensione si basa su.) Se fate la tua DLL potresti teoricamente collegare direttamente tutto il codice Python in quella DLL, dal momento che non finisce nell'eseguibile ma è ancora in una DLL. Dovrai fare attenzione a fare il collegamento correttamente, tuttavia, poiché praticamente nessuno degli strumenti standard (come distutils) lo farà per te.

Tuttavia, indipendentemente dal modo in cui si incorpora Python, non è possibile accontentarsi di nella DLL, né si può fare con qualsiasi DLL. L'ABI cambia tra le versioni di Python, quindi se hai compilato il tuo codice con Python 2.6, hai bisogno di python26.dll; non è possibile utilizzare python25.dll o python27.dll. E Python non è solo una DLL; ha anche bisogno della sua libreria standard, che include i moduli di estensione (che sono DLL stessi, sebbene abbiano l'estensione .pyd). Il codice in dynload_win.c in cui è stato eseguito il caricamento è quelle DLL e non sono correlate al caricamento di pythonXY.dll.

In breve, per incorporare Python nel plug-in, è necessario spedire Python con il plug-in o richiedere che sia installata la versione corretta di Python.

+0

Cosa succede se compilo personalmente le estensioni della libreria standard e le collego alla mia DLL (che sarebbe composta da mio 'foo' e' bar' e tutti gli oggetti che normalmente vanno in 'pythonNN.dll' come vedo nel' progetto pythoncore')? Nel mio caso è OK avere versioni speciali di librerie standard o estensioni di terze parti. –

+0

Quindi è ancora necessario tutto il resto della libreria standard (tutti i file .py e .pyc e .pyo in genere.) Sono anche specifici per la versione di Python. Puoi comprimerli, ma non puoi evitare di averli. –

+0

Quindi, in pratica, non è possibile incorporare Python nell'applicazione senza associarla a una DLL di Python? – viraj

0

Python deve essere una DLL (con un nome standard) in modo che l'applicazione e il plug-in possano utilizzare la stessa istanza di python.

I plug-in devono già caricare (e utilizzare python da) un python26.dll (o qualsiasi altra versione) - se il tuo python è incorporato staticamente nel tuo exe, allora due diverse istanze della libreria python sarebbero gestire le stesse strutture di dati.

Se le librerie Python non utilizzano affatto variabili statiche e le impostazioni di compilazione sono esattamente lo stesso non dovrebbe essere un problema. Tuttavia, generalmente è molto più sicuro assicurarsi semplicemente che sia utilizzata una sola istanza dell'interprete python.

1

Su * nix, tutti gli oggetti condivisi in un processo, incluso l'eseguibile, contribuiscono con i loro nomi esportati in un pool comune; qualsiasi oggetto condiviso può quindi estrarre uno qualsiasi dei nomi dal pool e usarli come preferiscono. Ciò consente ad es. cStringIO.so per estrarre le funzioni della libreria Python dall'eseguibile principale quando la libreria Python è collegata in modo statico.

Su Windows, ogni oggetto condiviso ha il proprio gruppo di nomi indipendente che può essere utilizzato. Ciò significa che deve leggere i diversi oggetti condivisi rilevanti di cui ha bisogno di funzioni. Poiché è molto lavoro ottenere tutti i nomi dal file eseguibile principale, le funzioni Python vengono separate nella loro DLL.

1

(Scusa, ho fatto una cosa stupida, prima ho scritto la domanda e poi mi sono registrato, e ora non posso alterarlo o commentare le risposte, perché il motore di StackOverflow non crede che io sia l'autore. anche correttamente ringrazio coloro che hanno risposto :(Quindi questo è in realtà un aggiornamento alla domanda e ai commenti.)

Grazie per tutti i consigli, è molto prezioso. Per quanto ho capito con un po 'di sforzo posso collegare Python staticamente in un DLL personalizzata, a condizione che compili altre estensioni caricate dinamicamente e le colleghi alla stessa DLL (so che ho bisogno di spedire anche la libreria standard, il mio piano era quello di aggiungere un archivio zippato al file DLL. , Potrò persino importare moduli Python puri.)

Ho trovato anche un posto interessante in dynload_win.c. (Comprendo che carica le estensioni dinamiche che usano l'API Python C, ad esempio _ctypes.) Per quanto posso vedere, non cerca solo il simbolo init_ctypes o qualunque sia il nome dell'estensione, ma scansiona anche la tabella di importazione del file .pyd cercando (regex) python\d+\. e quindi confronta il simbolo trovato con la nota stringa pythonNN. per assicurarsi che l'estensione sia stata compilata per questa versione di Python. Se la tabella di importazione non ha un tale simbolo o si riferisce a un'altra versione, genera un errore.

Per me significa che:

  • Se collego un'estensione contro pythonNN.dll e cercare di caricarlo dal mio DLL personalizzata che include un Python collegato staticamente, passerà il controllo, ma - beh, qui Non sono sicuro: fallirà perché non c'è lo pythonNN.dll (cioè prima di arrivare al check) o caricherà felicemente i simboli?
  • E se collego contro la mia DLL personalizzata, troverà i simboli, ma non superare il controllo :)

Credo che avrei potuto riscrivere questo pezzo per soddisfare le mie esigenze ... Ci sono dei altri posti simili, mi chiedo.

Problemi correlati