Utilizzare il metodo 'System.GetExternSymbol()' per richiamare funzioni esterne di librerie condivise
E' possibile richiamare funzioni esterne di librerie condivise .so anche senza l'uso di Extern, ma mediante il metodo ".GetExternSymbol()" della Classe System .
In tal caso la procedura è più complessa. Infatti, poiché si farà uso di un puntatore alla funzione esterna da invocare ed utilizzare, sarà necessario creare una nostra apposita libreria ad hoc, nella quale si chiamerà effettivamente la funzione esterna.
Mostriamo di seguito un esempio, nel quale supponiamo di dover invocare una funzione che svolge una semplice moltiplicazione utilizzando il valore ricevuto dal nostro progetto Gambas. Tale funzione esterna, che chiameremo FunzioneEsterna(), è contenuta in una libreria dinamica esterna, che chiameremo LibreriaEsterna.c, il cui semplice codice sorgente in C è il seguente: [Nota 1]
int FunzioneEsterna(int i) { i = i * 10; return i; }
Il codice del progetto Gambas sarà il seguente:
Private Extern Invoca_Funzione(fun_est As Pointer, valore As Integer) As Integer In "/tmp/Libadhoc" Public Sub Main() Dim libreriaso As String = "/tmp/LibreriaEsterna.so" Dim NomeFunzione As String = "FunzioneEsterna" Dim p As Pointer Dim ris As Integer ' Carica la funzione esportata da 'mialibreria.so': p = System.GetExternSymbol(Replace(libreriaso, ".so", Null), NomeFunzione) If p == 0 Then Error.Raise("Impossibile caricare la funzione della libreria esterna !") ' Crea un'apposita libreria condivisa esterna ".so", il cui file del codice sorgente sarà chiamato "Libadhoc.c": CreaLibSoAdHoc() ' Invoca la 'FunzioneEsterna' e le passa un Intero: ris = Invoca_Funzione(FunzioneEsterna, 44) Print "Risultato: "; ris End Private Procedure CreaLibSoAdHoc() ' Imposta il codice C della libreria ad hoc da creare: File.Save("/tmp/Libadhoc.c", "int Invoca_Funzione(int (*FunzioneEsterna)(int), int r) {\n" & " return FunzioneEsterna(r); \n}") Shell "gcc -o /tmp/Libadhoc.so /tmp/Libadhoc.c -shared" Wait End
Come si è potuto notare, la parola chiave Extern è stata comunque utilizzata, anche se però non direttamente per dichiarare la vera funzione esterna da chiamare e da utilizzare (ossia quella contenuta in LibreriaEsterna.c), ma solo per dichiarare la funzione esterna della libreria ad hoc da noi creata che provvede ad invocare ed utilizzare la predetta funzione esterna di LibreriaEsterna.c.
Esempio con una funzione esterna della libreria standard di C
In quest'altro esempio utilizzeremo in modo semplice la funzione esterna printf( ), dichiarata nel file header "/usr/include/stdio.h".
Private Extern Invoca_Funzione(FunzioneEsternaPuntata As Pointer) As Integer In "/tmp/libso" Public Sub Main() Dim p As Pointer ' Invoca la procedura per scrivere il sorgente e per creare la libreria dinamica condivisa: CreaSo() ' Richiama mediante System.GetExternSymbol() la funzione "printf()" della libreria standard di C: p = System.GetExternSymbol("libc:6", "printf") ' Invoca la funzione esterna da noi creata e le passiamo il Puntatore alla funzione esterna "printf()": Invoca_Funzione(p) End Private Procedure CreaSo() ' Scrive e salva il sorgente della nostra libreria esterna ad hoc dinamica condivisa per la chiamata della funzione puntata "printf()": File.Save("/tmp/libso.c", "void Invoca_Funzione(int (*FunzioneEsternaPuntata)(const char *__restrict __format)) {\n\n" & " FunzioneEsternaPuntata(\"abcdefg\");\n\n}") ' Crea la nostra libreria esterna dinamica condivisa ad hoc: Shell "gcc -o /tmp/libso.so /tmp/libso.c -shared -fPIC" Wait End
Di seguito vediamo un esempio simile al precedente, ma ora passando dei valori agli argomenti della funzione esterna "printf()".
Private Extern Invoca_Funzione(FunzioneEsternaPuntata As Pointer, st As String) As Integer In "/tmp/libso" Public Sub Main() Dim p As Pointer ' Invoca la procedura per scrivere il sorgente e per creare la libreria dinamica condivisa: CreaSo() ' Richiama mediante System.GetExternSymbol() la funzione "printf()" della libreria standard di C: p = System.GetExternSymbol("libc:6", "printf") ' Invoca la funzione esterna da noi creata e le passiamo il Puntatore alla funzione esterna "printf()": Invoca_Funzione(p, "abcdefg") End Private Procedure CreaSo() ' Nella funzione puntata vanno descritti i parametri previsti dalla funzione esterna "printf()": File.Save("/tmp/libso.c", "void Invoca_Funzione(int (*FunzioneEsternaPuntata)(const char *__restrict __format, char * stringa), char * st) {\n\n" & " FunzioneEsternaPuntata(\"%s\\n\", st); \n\n}") ' Crea la nostra libreria esterna dinamica condivisa ad hoc: Shell "gcc -o /tmp/libso.so /tmp/libso.c -shared -fPIC" Wait End
Note
Se si intende provare l'esempio pratico esposto in questa pagina, il codice sorgente della libreria esterna LibreriaEsterna.c va compilato nel terminale con la seguente riga di comando:
~ $ gcc -o /tmp/LibreriaEsterna.so /tmp/LibreriaEsterna.c -shared