Chiama la funzione c da Java

Come chiamare la funzione c da Java. Sembra che c sia basato sul compilatore.

Vorrei chiamare la funzione C in Windows da Java e la funzione GCC anche da Java.

Qualche riferimento?

Dai un’occhiata a Java Native Interface: come iniziare .

2.1 Panoramica

[…] scrivi una semplice applicazione Java che chiama una funzione C per stampare “Hello World!”. Il processo consiste dei seguenti passaggi:

Crea una class (HelloWorld.java) che dichiari il metodo nativo. Usa javac per compilare il file sorgente HelloWorld, dando come risultato il file di class HelloWorld.class. Il compilatore javac viene fornito con versioni di JDK o Java 2 SDK. Utilizzare javah -jni per generare un file di intestazione C ( HelloWorld.h ) contenente il prototipo di funzione per l’implementazione del metodo nativo. Lo strumento javah viene fornito con versioni di JDK o Java 2 SDK. Scrivi l’implementazione C ( HelloWorld.c ) del metodo nativo. Compilare l’implementazione C in una libreria nativa, creando Hello-World.dll o libHello-World.so . Utilizzare il compilatore C e il linker disponibili nell’ambiente host. Esegui il programma HelloWorld utilizzando l’interprete runtime Java. Sia il file di class ( HelloWorld.class ) che la libreria nativa ( HelloWorld.dll o libHelloWorld.so ) vengono caricati in fase di runtime. Il resto di questo capitolo spiega dettagliatamente questi passaggi.

2.2 Dichiarare il metodo nativo

Inizi a scrivere il seguente programma nel linguaggio di programmazione Java. Il programma definisce una class denominata HelloWorld che contiene un metodo nativo, stampa.

 class HelloWorld { private native void print(); public static void main(String[] args) { new HelloWorld().print(); } static { System.loadLibrary("HelloWorld"); } } 

La definizione della class HelloWorld inizia con la dichiarazione del metodo nativo di stampa. Questo è seguito da un metodo principale che istanzia la class Hello-World e invoca il metodo di stampa nativo per questa istanza. L’ultima parte della definizione della class è un inizializzatore statico che carica la libreria nativa contenente l’implementazione del metodo nativo di stampa.

Esistono due differenze tra la dichiarazione di un metodo nativo come la stampa e la dichiarazione di metodi regolari nel linguaggio di programmazione Java. Una dichiarazione del metodo nativo deve contenere il modificatore nativo. Il modificatore nativo indica che questo metodo è implementato in un’altra lingua. Inoltre, la dichiarazione del metodo nativo termina con un punto e virgola, il simbolo del terminatore dell’istruzione, perché non esiste un’implementazione per i metodi nativi nella class stessa. Implementeremo il metodo di stampa in un file C separato.

Prima di poter chiamare la stampa del metodo nativo, è necessario caricare la libreria nativa che implementa la stampa. In questo caso, carichiamo la libreria nativa nell’inizializzatore statico della class HelloWorld . La Java virtual machine esegue automaticamente l’inizializzatore statico prima di richiamare qualsiasi metodo nella class HelloWorld , garantendo in tal modo che la libreria nativa venga caricata prima che venga chiamato il metodo di stampa nativo.

Definiamo un metodo principale per essere in grado di eseguire la class HelloWorld . Hello-World.main chiama il metodo nativo print nello stesso modo in cui chiamerebbe un metodo normale.

System.loadLibrary accetta un nome di libreria, individua una libreria nativa corrispondente a tale nome e carica la libreria nativa nell’applicazione. Discuteremo il processo di caricamento esatto più avanti nel libro. Per ora basta ricordare che, per fare in modo che System.loadLibrary("HelloWorld") successo, dobbiamo creare una libreria nativa chiamata HelloWorld.dll su Win32 o libHelloWorld.so su Solaris.

2.3 Compilare la class HelloWorld

Dopo aver definito la class HelloWorld, salva il codice sorgente in un file chiamato HelloWorld.java. Quindi compila il file sorgente usando il compilatore javac fornito con la release JDK o Java 2 SDK:

  javac HelloWorld.java 

Questo comando genererà un file HelloWorld.class nella directory corrente.

2.4 Creare il file di intestazione del metodo nativo

Successivamente utilizzeremo lo strumento javah per generare un file di intestazione in stile JNI che è utile quando si implementa il metodo nativo in C. È ansible eseguire javah sulla class Hello-World come segue:

  javah -jni HelloWorld 

Il nome del file di intestazione è il nome della class con un ” .h ” aggiunto alla fine di esso. Il comando mostrato sopra genera un file denominato HelloWorld.h . Qui non verrà elencato il file di intestazione generato nella sua interezza. La parte più importante del file di intestazione è la funzione prototype per Java_HelloWorld_print , che è la funzione C che implementa il metodo HelloWorld.print:

  JNIEXPORT void JNICALL Java_HelloWorld_print (JNIEnv *, jobject); 

Ignora i macro JNIEXPORT e JNICALL per ora. Potresti aver notato che l’implementazione C del metodo nativo accetta due argomenti anche se la corrispondente dichiarazione del metodo nativo non accetta argomenti. Il primo argomento per ogni implementazione del metodo nativo è un puntatore all’interfaccia JNIEnv . Il secondo argomento è un riferimento all’object HelloWorld stesso (simile al puntatore ” this ” in C ++). Discuteremo su come utilizzare il puntatore dell’interfaccia JNIEnv e gli argomenti del jobject più avanti in questo libro, ma questo semplice esempio ignora entrambi gli argomenti.

2.5 Scrivere l’implementazione del metodo nativo

Il file di intestazione in stile JNI generato da javah consente di scrivere implementazioni C o C ++ per il metodo nativo. La funzione che scrivi deve seguire il -prototype specificato nel file di intestazione generato. È ansible implementare il metodo Hello-World.print in un file C HelloWorld.c come segue:

 #include  #include  #include "HelloWorld.h" JNIEXPORT void JNICALL Java_HelloWorld_print(JNIEnv *env, jobject obj) { printf("Hello World!\n"); return; } 

L’implementazione di questo metodo nativo è semplice. Usa la funzione printf per visualizzare la stringa “Hello World!” e poi ritorna. Come accennato in precedenza, entrambi gli argomenti, il puntatore JNIEnv e il riferimento all’object, vengono ignorati.

Il programma C include tre file di intestazione:

jni.h : questo file di intestazione fornisce informazioni necessarie al codice nativo per chiamare le funzioni JNI. Quando si scrivono metodi nativi, è sempre necessario includere questo file nei file di origine C o C ++. stdio.h : lo snippet di codice sopra include anche stdio.h perché utilizza la funzione printf . HelloWorld.h : il file di intestazione che hai generato utilizzando javah . Include il prototipo C / C ++ per la funzione Java_HelloWorld_print . 2.6 Compilare la sorgente C e creare una libreria nativa

Ricorda che quando hai creato la class HelloWorld nel file HelloWorld.java , hai inserito una riga di codice che caricava una libreria nativa nel programma:

  System.loadLibrary("HelloWorld"); 

Ora che è stato scritto tutto il codice C necessario, è necessario compilare Hello-World.c e creare questa libreria nativa.

Diversi sistemi operativi supportano diversi modi per creare librerie native. Su Solaris, il seguente comando costruisce una libreria condivisa chiamata libHello-World.so:

  cc -G -I/java/include -I/java/include/solaris HelloWorld.c -o libHelloWorld.so 

L’opzione -G indica al compilatore C di generare una libreria condivisa invece di un normale file eseguibile di Solaris. A causa della limitazione della larghezza della pagina in questo libro, suddividiamo la riga di comando in due righe. È necessario digitare il comando in una singola riga o posizionare il comando in un file di script. Su Win32 , il seguente comando crea una libreria di collegamento dinamico (DLL) HelloWorld.dll utilizzando il compilatore Microsoft Visual C ++:

  cl -Ic:\java\include -Ic:\java\include\win32 -MD -LD HelloWorld.c -FeHelloWorld.dll 

L’opzione -MD assicura che HelloWorld.dll sia collegato con la libreria C multithread Win32 . L’opzione -LD indica al compilatore C di generare una DLL invece di un eseguibile Win32 regolare. Naturalmente, sia su Solaris che su Win32 è necessario inserire i percorsi di inclusione che riflettono l’installazione sulla propria macchina.

2.7 Esegui il programma

A questo punto, hai i due componenti pronti per eseguire il programma. Il file di class ( HelloWorld.class ) chiama un metodo nativo e la libreria nativa ( Hello-World.dll ) implementa il metodo nativo.

Poiché la class HelloWorld contiene il proprio metodo principale, è ansible eseguire il programma su Solaris o Win32 come segue:

  java HelloWorld 

Dovresti vedere il seguente output:

  Hello World! 

È importante impostare correttamente il percorso della libreria nativa per l’esecuzione del programma. Il percorso della libreria nativa è un elenco di directory che la macchina virtuale Java cerca quando carica le librerie native. Se non si dispone di un percorso di libreria nativo impostato correttamente, viene visualizzato un errore simile al seguente:

  java.lang.UnsatisfiedLinkError: no HelloWorld in library path at java.lang.Runtime.loadLibrary(Runtime.java) at java.lang.System.loadLibrary(System.java) at HelloWorld.main(HelloWorld.java) 

Assicurarsi che la libreria nativa risieda in una delle directory nel percorso della libreria nativa. Se si sta eseguendo su un sistema Solaris, la variabile di ambiente LD_LIBRARY_PATH viene utilizzata per definire il percorso della libreria nativa. Assicurati che includa il nome della directory che contiene il file libHelloWorld.so . Se il file libHelloWorld.so trova nella directory corrente, è ansible eseguire i seguenti due comandi nella shell standard (sh) o KornShell (ksh) per impostare correttamente la variabile di ambiente LD_LIBRARY_PATH :

  LD_LIBRARY_PATH=. export LD_LIBRARY_PATH 

Il comando equivalente nella shell C (csh o tcsh) è il seguente:

  setenv LD_LIBRARY_PATH . 

Se si esegue su un computer Windows 95 o Windows NT, assicurarsi che HelloWorld.dll sia nella directory corrente o in una directory elencata nella variabile di ambiente PATH.

Nella release Java 2 SDK 1.2, è anche ansible specificare il percorso della libreria nativa sulla riga di comando java come proprietà di sistema come segue:

  java -Djava.library.path=. HelloWorld 

L’opzione della riga di comando ” -D ” imposta una proprietà di sistema della piattaforma Java. L’impostazione della proprietà java.library.path su ” .java.library.path alla macchina virtuale Java di cercare librerie native nella directory corrente.

In parole semplici, assicurati di caricare la libreria pertinente che contiene la definizione della funzione, carica la libreria che segue le specifiche JNI e avvolge la funzione di destinazione dalla prima libreria, espone i metodi nativi dalla tua class Java e dovresti essere bravo a farlo .

Mi raccomando contro JNI non elaborato poiché contiene un sacco di codice boilerplate e finiresti per maledirti da solo se avvii il wrapping di una grande libreria C. Con ogni mezzo, sentitevi liberi di dilettarvi in ​​JNI all’inizio, ma usate qualcosa come JNA quando si tratta di un vero lavoro.

Le opzioni includono:

Java Native Interface
vedere: https://en.wikipedia.org/wiki/Java_Native_Interface

citazione:

JNI consente ai programmatori di scrivere metodi nativi per gestire situazioni in cui un’applicazione non può essere scritta interamente nel linguaggio di programmazione Java, ad esempio quando la libreria di classi Java standard non supporta le funzionalità specifiche della piattaforma o la libreria di programmi

Accesso nativo Java

vedi: https://en.wikipedia.org/wiki/Java_Native_Access

citazione:

Java Native Access è una libreria sviluppata dalla comunità che fornisce ai programmi Java un facile accesso alle librerie native native senza utilizzare l’interfaccia nativa Java.

JNR-FFI

vedi: https://github.com/jnr/jnr-ffi

citazione:

jnr-ffi è una libreria java per caricare librerie native senza scrivere codice JNI a mano, o usando strumenti come SWIG.

Nella categoria “esotica”, vedi NestedVM, che compila il C in Mips, ed esegue una VM Mips all’interno di JVM.

http://nestedvm.ibex.org/

Se si utilizza Windows e MinGW gcc, potrebbe essere necessario un ulteriore flag se si ottiene UnsatisfiedLinkError per un metodo specifico in lib:

 gcc -D_JNI_IMPLEMENTATION_ -Wl,--kill-at -I"%JAVA_HOME%"\include -I"%JAVA_HOME%"\include\win32 BestCode.c -shared -o BestCode.dll 

JNI – Java Native Interface

Per chiamare la funzione C da Java è necessario utilizzare JNI

Acquista JNAerator. https://code.google.com/p/jnaerator/

È necessario fornire il codice sorgente e le definizioni del preprocessore, ecc.

Per creare una DLL compatibile a 64 bit Rimuovere l’opzione “-MD” dall’istruzione sottostante

“cl -Ic: \ java \ include -Ic: \ java \ include \ win32 -MD -LD HelloWorld.c -FeHelloWorld.dll”

Ho una soluzione per questo problema. Ciò che è necessario assicurarsi è che si stia compilando il codice utilizzando il compilatore c ++ a 64 bit per chiamare la funzione java in esecuzione su JRE a 64 bit. Insieme a questo abbiamo bisogno di salvare il percorso del file dll creato in “Percorso” in “Variabile d’ambiente”.

Prima assicurati di caricare la libreria nativa o il file .dll nel percorso della class impostando il percorso nella proprietà java.library.path

Quindi utilizzare System.loadLibrary()

 Do not use .dll extension at the end.