Domanda

Sono in procinto di scrivere una sorta di sistema di runtime / interprete, e una delle cose che ho bisogno di essere in grado di fare è chiamare C / C ++ funzioni situati in librerie esterne.

su Linux sto usando le funzioni dlfcn.h per aprire una biblioteca e chiamare una funzione si trova all'interno. Il problema è che hanno bisogno, quando si utilizza il puntatore a funzione dlsysm() tornato a essere gettato in un tipo appropriato prima di essere chiamato in modo che gli argomenti della funzione e tipo di ritorno sono sapere, se sto chiamando qualche funzione arbitraria in una biblioteca poi, ovviamente lo farò non so questo prototipo in fase di compilazione.

Quindi quello che sto chiedendo è, c'è un modo per chiamare una funzione caricate dinamicamente e passare gli argomenti, e recuperare il suo valore di ritorno senza saperlo prototipo?

Finora ho giunto alla conclusione, non c'è modo semplice per fare questo, ma alcune soluzioni che ho trovato sono:

  • Assicurarsi che tutte le funzioni che voglio caricare hanno lo stesso prototipo, e fornire un meccanismo di ordinamento per queste funzioni per recuperare i parametri e valori di ritorno. Questo è quello che sto facendo al momento.

  • Usa linea asm per spingere i parametri nello stack, e di leggere il valore di ritorno. Ho molta voglia di evitare di fare questo, se possibile!

Se qualcuno ha qualche idea allora sarebbe molto apprezzato.

Modifica

Ora ho trovato esattamente quello che stavo cercando:

http://sourceware.org/libffi/

"Un portatile Funzione Foreign Interface Library"

(Anche se devo ammettere che avrei potuto essere più chiara nella domanda originale!)

È stato utile?

Soluzione

Credo che la biblioteca FFI rubino realizza quello che chiedete. Si può chiamare funzioni nelle biblioteche esterni collegati dinamicamente senza collegandoli in particolare in.

http://wiki.github.com/ffi/ffi/

Probabilmente non è possibile utilizzare direttamente nel tuo linguaggio di scripting, ma perhapps le idee sono portatili.

- Brad Phelan http://xtargets.heroku.com

Altri suggerimenti

Quello che chiediamo è se C / C ++ supporti di riflessione per le funzioni (vale a dire ottenere informazioni sul loro tipo in fase di esecuzione). Purtroppo la risposta è no.

Si dovrà fare le funzioni conformi a un contratto standard (come hai detto che stavi facendo), o iniziare la meccanica di attuazione per cercare di funzioni di chiamata in fase di esecuzione senza conoscere i loro argomenti.

Dal momento che avere alcuna conoscenza di una funzione rende impossibile chiamarlo, suppongo vostro interprete / "sistema di runtime" almeno ha qualche input dell'utente o simili si può utilizzare per dedurre che si sta cercando di chiamare una funzione che sarà simile qualcosa di prendere tali argomenti e ritorno qualcosa non del tutto inaspettato. Quella ricerca è difficile da attuare in se stessa, anche con la riflessione e un decente sistema di tipo runtime con cui lavorare. Mescolare in convenzioni di chiamata, stili di collegamento, e le piattaforme, e le cose si fanno brutte reale presto.

Stick al vostro piano, far rispettare un contratto ben definito per le funzioni si carica in modo dinamico, e si spera fare causa con quello.

Si può aggiungere una funzione spedizione verso le librerie esterne, per esempio uno che prende il nome di funzione e N parametri di qualche tipo variante (facoltativo) e restituisce una variante? In questo modo la funzione di prototipo di spedizione è noto. La funzione di invio quindi esegue una ricerca (o uno switch) sul nome della funzione e chiama la funzione corrispondente.

Ovviamente diventa un problema di manutenzione, se ci sono un sacco di funzioni.

  

Sono in procinto di scrivere una sorta di sistema di runtime / interprete, e una delle cose che ho bisogno di essere in grado di fare è chiamare C / C ++ funzioni situati in librerie esterne.

Probabilmente si può verificare la presenza di esempi su come Tcl e Python farlo. Se si ha familiarità con il Perl, è anche possibile controllare il Perl XS .

approccio generale è quello di richiedere biblioteca porta in più seduto tra il vostro interprete e la libreria di destinazione C. Dalla mia esperienza con motivi principali Perl XS sono la gestione della memoria / Garbage Collection e la C tipi di dati che sono difficili / impossibili da mappare direttamente al linguaggio dell'interprete.

  

Quindi quello che sto chiedendo è, c'è un modo per chiamare una funzione caricate dinamicamente e passare gli argomenti, e recuperare il suo valore di ritorno senza saperlo del prototipo?

Non sono noti a me.

  

Assicurarsi che tutte le funzioni che voglio caricare hanno lo stesso prototipo, e fornire un meccanismo di ordinamento per queste funzioni per recuperare i parametri e valori di ritorno. Questo è quello che sto facendo al momento.

Questo è ciò che nel mio progetto altra squadra sta facendo troppo. Essi hanno standardizzato API per i plug-in esterni su qualcosa di simile:

typedef std::list< std::string > string_list_t;
string_list_t func1(string_list_t stdin, string_list_t &stderr);

Attività comuni per i plug-in è quello di eseguire la trasformazione o la mappatura o l'ampliamento dell'ingresso, spesso utilizzando RDBMS.

Le versioni precedenti dell'interfaccia è cresciuto nel corso del tempo i problemi che causano impossibile da mantenere per i clienti, gli sviluppatori di prodotti e gli sviluppatori 3rd party plug-in. uso frivolo della std :: string è consentito dal fatto che i plug-in sono chiamati relativamente raramente (e ancora l'overhead è noccioline rispetto al SQL utilizzato in tutto il posto). Il stdin argomento è popolato con ingresso a seconda del tipo plug-in. Plug-in call considerato guasto se il parametro di uscita all'interno stderr qualsiasi stringa inizia con 'E:' ( 'W:' è per avvisi, resto viene ignorata quindi può essere utilizzato per lo sviluppo di plug-in / debug).

Il dlsym viene utilizzato una sola volta sulla funzione con il nome predefinito per andare a prendere dalla matrice libreria condivisa con la tabella di funzione (funzione nome pubblico, il tipo, puntatore, ecc).

La mia soluzione è che si può definire un generic proxy function che convertirà la funzione dinamica di un prototipo divisa, qualcosa di simile a questo:

#include <string>
#include <functional>

using result = std::function<std::string(std::string)>;

template <class F>
result proxy(F func) {
  // some type-traits technologies based on func type
}

Nel file definito dall'utente, è necessario aggiungere definire per fare il convertito:

double foo(double a) { /*...*/ }
auto local_foo = proxy(foo);

Nel vostro sistema di runtime / interprete, è possibile utilizzare dlsym per definire un foo-function. E 'la responsabilità della funzione di foo definita dall'utente per fare calcoli.

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