Utilizzare il metodo 'System.GetExternSymbol()' per richiamare funzioni esterne di librerie condivise

Da Gambas-it.org - Wikipedia.

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 esterna, il cui file sorgente 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 invece 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

[1] 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