Domanda

Quali sono i modi "normali" per eseguire i plug-in nei linguaggi compilati (C # / C / C ++ / D)? Sono particolarmente interessato agli approcci agnostici della lingua, ma non è inaccettabile una specifica lingua.

Per il momento, gli approcci plug-in "tempo di compilazione" (includi semplicemente il codice o no e tutto funziona) sono validi ma sono preferibili le cose che possono migrare verso un approccio più dinamico.

Per quanto riguarda il tipo di runtime, sono più interessato ai meccanismi di caricamento del plug-in e quant'altro che alla progettazione dell'interfaccia plug-in / app

EDIT: A proposito il plugin sarebbe uno slave, non un master. L'azione di base di un plug-in sarebbe quella in una data situazione, sarebbe chiamato a "fare la sua cosa" e ricevere un oggetto ambiente che dovrebbe usare per ottenere ciò di cui ha bisogno per funzionare.

È stato utile?

Soluzione

Per i linguaggi compilati (dove compilato significa che il programma viene eseguito come eseguibile nativo, senza alcun tipo di macchina virtuale), è praticamente necessario utilizzare una sorta di approccio di libreria condivisa specifico della piattaforma. In Windows, ciò significa utilizzare DLL.

Definisci la tua interfaccia plugin in termini di un insieme di funzioni (con nomi specifici, argomenti e convenzioni di chiamata). Quindi, carichi gli indirizzi delle funzioni all'interno della libreria condivisa e vai in città. In Windows, ciò significa utilizzare GetProcAddress () e quindi trasmettere il valore restituito a un puntatore a funzione del tipo appropriato in C, o qualunque sia l'equivalente nella lingua che stai utilizzando.

Un'altra opzione che potrebbe essere o meno desiderabile sarebbe quella di eseguire una macchina virtuale per un'altra lingua dall'interno della tua applicazione nativa e avere plug-in come codice per quella lingua. Ad esempio, è possibile eseguire una VM Python utilizzando CPython e caricare in modo dinamico i moduli Python.

Altri suggerimenti

Mono.Addins sembra essere una buona soluzione per .NET. Ritengo che includa l'API per consentire all'utente di scaricare plug-in (o componenti aggiuntivi) da un repository e caricarlo dinamicamente in un assembly in esecuzione.

Ho scoperto che le parti difficili dei plugin sono: trovarli, risolvere le loro dipendenze e gestire i problemi di versione. Il modo in cui gestisci questi problemi dovrebbe essere chiaro a te e agli autori dei plug-in. Se sbagli questi problemi, non causerà fine al dolore. Vorrei esaminare i linguaggi di scripting e le applicazioni che utilizzano plugin per idee su ciò che funziona bene.

I costruttori statici sono il più delle volte, "intelligenti" in senso negativo. Dato che dovrai caricare (C / C ++: dlopen e amici sotto Linux) i plugin uno alla volta (nel caso dinamico), puoi anche inizializzarli manifestamente mentre lo fai. Tra le altre cose, ciò potrebbe darti l'opportunità di rifiutare i plugin senza api previsti.

Nota, non è necessario utilizzare librerie di caricamento dinamico per i plug-in. Possono essere utilizzati anche altri meccanismi: memoria condivisa, socket, ecc ....

Dipende davvero da cosa vuoi fare. Il modello Unix comune visto in Emacs e Gimp è quello di scrivere un programma che consiste in un piccolo componente compilato che espone funzionalità essenziali che un componente interpretato usa per fare tutto. I plug-in che forniscono nuove funzionalità che possono essere costruite sulla parte superiore dell'app sono facili, ma è necessario essere molto flessibili nelle primitive fornite affinché ciò sia possibile. All'estremo opposto immagina un editor di foto che può salvare in più formati. Si desidera consentire alle persone di scrivere i propri gestori di formati di file. Ciò richiede che il tuo codice utilizzi un semplice set di primitive, quindi seleziona un'implementazione in fase di esecuzione. In straight (Unix) C usa dlopen, in C ++ usa extern C che limita ciò che puoi fare e dlopen. In Objective-C hai una classe per farlo per te. Nel primo caso stai creando o riutilizzando un interprete in modo da avere il regno libero di farlo come preferisci.

Per un plug-in di tipo slave in cui ogni plug-in incapsula una diversa implementazione di un insieme comune di funzioni, vorrei semplicemente depositare le DLL in una cartella di plug-in nota all'applicazione host (ad esempio " c: \ program files \ myapp \ plug-in), quindi chiama le DLL dall'host tramite Reflection.

Tu potresti eseguire una sorta di elaborato processo di registrazione quando ogni DLL è installata, ma non ho mai avuto problemi con il semplice approccio plug-in in una cartella.

Modifica: per fare ciò in C #, aggiungi semplicemente una classe pubblica alla DLL (denominata " Plugin " o altro), e implementa lì le funzioni necessarie. Dal tuo host, crei quindi un oggetto di tipo Plugin e chiami i suoi metodi (tutti usando Reflection).

Le interfacce con un registro vuoto (EventSource) sembrano funzionare bene - vedi IHttpModule.Init (HttpApplication ) per un esempio.

Ciò consente all'autore dell'app (che controlla EventSource) di aggiungere eventi secondo necessità, senza la necessità di estendere l'interfaccia IPlugin (portando inevitabilmente a IPluginEx, IPlugin2, IPlugin2Ex, ecc.)

Un approccio che ho usato (in .NET) è di fare in modo che l'host effettui una chiamata iniziale al plugin (tramite Reflection), avviando il plugin e passando un riferimento all'host che il plugin salva. Il plug-in chiama quindi i metodi sull'host (anche tramite la riflessione) se necessario.

Penso che con la maggior parte dei plugin, le chiamate verrebbero normalmente fatte nella direzione opposta (cioè l'host chiamerebbe il plugin come necessario). Nel mio caso, i plugin stessi avevano elementi dell'interfaccia utente che dovevano utilizzare la funzionalità host.

a parte problemi di implementazione dei moduli di basso livello (ad es. DLL di Windows e problemi di implementazione), un motore di gioco che uso ha solo una funzione di registrazione globale nelle DLL e tenta di trovarlo e chiamarlo su ogni dll nella directory dei plugin. la funzione di registrazione esegue qualsiasi contabilità necessaria per esporre la funzionalità.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top