2011-10-02 24 views
15

Sto costruendo un'applicazione Java che utilizza una libreria condivisa scritta in C++ e compilata per diversi sistemi operativi. Il problema è che questa stessa libreria condivisa dipende da una libreria aggiuntiva che normalmente trova nella variabile d'ambiente appropriata (PATH, LIBRARY_PATH o LD_LIBRARY_PATH).Carica libreria condivisa per percorso al runtime

Posso - ma non voglio - impostare queste variabili di ambiente. Preferisco caricare le necessarie librerie condivise da un determinato percorso in fase di esecuzione, proprio come un plugin. E no - non voglio nessuna applicazione di avviamento che avvia un nuovo processo con un nuovo ambiente. Qualcuno sa come ottenere questo?

So che questo deve essere possibile, in quanto una delle librerie che uso è in grado di caricare i suoi plugin da un determinato percorso. Ovviamente preferirei codice indipendente dalla piattaforma, ma se ciò non fosse possibile, anche le soluzioni separate per Windows, Linux e MacOS lo farebbero.

EDIT Avrei detto che la libreria condivisa che avrei voluto usare è orientato agli oggetti, il che significa che un legame di singole funzioni non lo farà.

+0

Come si carica la libreria da Java? –

+0

Java Native Access (JNA) – aRestless

risposta

8

Su Windows, è possibile utilizzare LoadLibrary e su Linux, dlopen. Le API sono estremamente simili e possono caricare una so/dll direttamente fornendo il percorso completo. Funziona se si tratta di una dipendenza in fase di esecuzione (dopo il caricamento, si "collega" chiamando GetProcAddress/dlsym.)

15

Un sistema UNIX/Linux è possibile utilizzare dlopen. Il problema poi è che devi prendere tutti i simboli necessari tramite dlsym

semplice esempio:

typedef int (*some_func)(char *param); 

void *myso = dlopen("/path/to/my.so", RTLD_NOW); 
some_func *func = dlsym(myso, "function_name_to_fetch"); 
func("foo"); 
dlclose(myso); 

caricherà il .so ed eseguire function_name_to_fetch() da lì. Vedere la pagina man dlopen (1) per ulteriori informazioni.

+0

Penso che avrei dovuto aggiungere che la libreria condivisa stessa è orientata agli oggetti. Se solo le funzioni possono essere "collegate", questo non funzionerà, giusto? – aRestless

+0

Se si conosce il nome generato dal linker, è possibile accedere a qualsiasi simbolo. Una buona pratica è avere una funzione che utilizza le convenzioni di chiamata C che restituisce un puntatore a una struttura che contiene oggetti o qualcosa. – johannes

+0

Bene, lo faccio già - per accedere alla libreria tramite Java. La libreria C++ che sto scrivendo non è altro che uno stub che usa la libreria di terze parti (che non sono in grado di modificare). – aRestless

1

Non penso che tu possa farlo per questo.

La maggior parte delle DLL ha una sorta di funzione init() che deve essere chiamata dopo che è stata caricata, e talvolta la funzione init() ha bisogno di alcuni parametri e restituisce qualche handle da utilizzare per chiamare le funzioni della dll. Conosci la definizione della libreria aggiuntiva?

Quindi, la prima libreria non può semplicemente cercare se la DLL X si trova nella RAM solo utilizzando il suo nome. Quello di cui ha bisogno può trovarsi in una directory diversa o in una versione/versione diversa. Il sistema operativo riconoscerà la libreria se il percorso completo è uguale a quello già caricato e lo condividerà invece di caricarlo una seconda volta.

L'altra libreria può caricare i suoi plug-in da un altro percorso perché è scritta per non dipendere da PATH e sono i suoi plugin.

Hai provato ad aggiornare le variabili di ambiente del processo dal codice prima di caricare la DLL? Ciò non dipende da un processo iniziale.

3

Concordo con gli altri poster sull'utilizzo di dlopen e LoadLibrary. Lo libltdl offre un'interfaccia indipendente dalla piattaforma per queste funzioni.

Problemi correlati