Appeler la fonction c à partir de Java
Comment appeler la fonction c à partir de Java. Il semble que c soit basé sur le compilateur.
Je voudrais appeler la fonction C dans Windows à partir de Java, et GCC fonction fron Java aussi.
Toute référence?
10 answers
Regardez Java Native Interface: prise en main.
2.1 Aperçu
[...] écrivez une application Java simple qui appelle une fonction C à imprimer "Bonjour Tout Le Monde!". Le processus comprend les étapes suivantes:
Créer une classe (HelloWorld.java) qui déclare la méthode native. Utiliser javac pour compiler le fichier source HelloWorld, résultant en la classe fichier HelloWorld.classe. Le compilateur javac est fourni avec JDK ou Java 2 SDK publier. Utilisez
javah -jni
pour générer un fichier d'en-tête C (HelloWorld.h
) contenant le prototype de fonction pour la méthode native application. L'outil javah est fourni avec JDK ou Java 2 SDK publier. Ecrire l'implémentation C (HelloWorld.c
) du natif méthode. Compiler l'implémentation C dans une bibliothèque native, en créantHello-World.dll
oulibHello-World.so
. Utilisez le compilateur C et l'éditeur de liens disponible sur l'hôte de l'environnement. Exécutez le programme HelloWorld en utilisant l'interpréteur d'exécution java. Les deux fichiers de classe (HelloWorld.class
) et la bibliothèque native (HelloWorld.dll
oulibHelloWorld.so
) sont chargés au moment de l'exécution. Le reste de ce chapitre explique ces étapes dans détail.2.2 Déclarer la méthode native
Vous commencez par écrire le programme suivant dans la programmation Java langue. Le programme définit une classe nommée HelloWorld qui contient méthode native, imprimer.
class HelloWorld { private native void print(); public static void main(String[] args) { new HelloWorld().print(); } static { System.loadLibrary("HelloWorld"); } }
La définition de la classe HelloWorld commence par la déclaration de la méthode native print. Ceci est suivi d'un principal méthode instancie la classe Hello-World et appelle la méthode print native pour cette instance. La dernière partie de la définition de classe est une statique initialiseur qui charge la bibliothèque native contenant le implémentation de la méthode print native.
, Il existe deux différences entre la déclaration d'une méthode native tels que print et la déclaration des méthodes régulières dans le Java langage de programmation. Une déclaration de méthode native doit contenir natif modificateur. Le modificateur natif indique que cette méthode est implémenté dans une autre langue. En outre, la déclaration de méthode native est terminé par un point-virgule, le symbole de terminaison de l'instruction, parce qu'il n'y a pas d'implémentation pour les méthodes natives dans la classe lui-même. Nous allons implémenter la méthode d'impression dans un fichier C séparé.
Avant que la méthode native print puisse être appelée, la bibliothèque native qui implements print doit être chargé. Dans ce cas, nous chargeons le natif bibliothèque dans l'initialiseur statique de la
HelloWorld
classe. Java la machine virtuelle exécute automatiquement l'initialiseur statique avant invoquant toutes les méthodes de la classeHelloWorld
, garantissant ainsi que le la bibliothèque native est chargée avant l'appel de la méthode print native.Nous définissons une méthode principale pour pouvoir exécuter la classe
HelloWorld
.Hello-World.main
appelle la méthode native print de la même manière que cela appellerait une méthode régulière.
System.loadLibrary
prend un nom de bibliothèque, localise un natif bibliothèque correspond à ce nom, et charge la bibliothèque native dans le application. Nous discuterons du processus de chargement exact plus tard dans la livre. Pour l'instant rappelez vous simplement que pour {[27] } pour réussir, nous devons créer un bibliothèque native appeléeHelloWorld.dll
sur Win32, oulibHelloWorld.so
sur Solaris.2.3 Compiler la classe HelloWorld
Après avoir défini la classe HelloWorld, enregistrez le code source dans un fichier appelé HelloWorld.Java. Puis compilez la source fichier à l'aide de la compilateur javac fourni avec la version du SDK JDK ou Java 2:
javac HelloWorld.java
Cette commande va générer un
HelloWorld.class
fichier dans le répertoire courant.2.4 Créer le fichier d'en-tête de méthode natif
Ensuite, nous utiliserons l'outil
javah
pour générer un fichier d'en-tête de style JNI c'est utile lors de l'implémentation de la méthode native en C. Vous pouvez exécuterjavah
sur la classeHello-World
comme suit:javah -jni HelloWorld
Le nom du fichier d'en-tête est le nom de la classe avec un "
.h
" ajouté à la fin de celui-ci. La commande ci-dessus génère un fichier nomméHelloWorld.h
. Nous ne listerons pas le produit fichier d'en-tête dans son intégralité ici. La partie la plus importante de la le fichier d'en-tête est le prototype de fonction pourJava_HelloWorld_print
, qui est la fonction C qui implémente HelloWorld.méthode d'impression:JNIEXPORT void JNICALL Java_HelloWorld_print (JNIEnv *, jobject);
Ignorez les macros
JNIEXPORT
etJNICALL
pour l'instant. Vous avez peut-être remarqué que l'implémentation C de la méthode native accepte deux arguments quoique la déclaration de la méthode native accepte pas d'arguments. Le premier argument pour chaque méthode native l'implémentation est un pointeur d'interfaceJNIEnv
. Le deuxième argument est un référence à l'objetHelloWorld
lui-même (un peu comme le "this
" pointeur en C++). Nous allons discuter de la façon d'utiliser l'interfaceJNIEnv
pointeur et les argumentsjobject
plus tard dans ce livre, mais ce simple exemple ignore les deux arguments.2.5 Écrire l'implémentation de la méthode native
Le fichier d'en-tête de style JNI généré par
javah
vous aide à écrire C ou Implémentations C++ pour la méthode native. La fonction que vous écrivez doit suivre le prototype spécifié dans le fichier d'en-tête généré. Vous peut implémenter la méthodeHello-World.print
dans un fichier CHelloWorld.c
comme suit:#include <jni.h> #include <stdio.h> #include "HelloWorld.h" JNIEXPORT void JNICALL Java_HelloWorld_print(JNIEnv *env, jobject obj) { printf("Hello World!\n"); return; }
L'implémentation de cette méthode native est simple. Il utilise la fonction printf pour afficher la chaîne " Hello World!"et puis revient. Comme mentionné précédemment, les deux arguments, le pointeur
JNIEnv
et la référence à l'objet sont ignorés.Le programme C comprend trois fichiers d'en-tête:
jni.h
-- Ce fichier d'en-tête fournit des informations dont le code natif a besoin pour appeler les fonctions JNI. Lors de l'écriture de méthodes natives, vous devez toujours incluez ce fichier dans vos fichiers source C ou C++. {[49] } The Le code l'extrait ci-dessus inclut égalementstdio.h
car il utilise leprintf
fonction. {[15] } file Le fichier d'en-tête que vous avez généré en utilisantjavah
. Il il comprend le prototype C / C++ pour leJava_HelloWorld_print
fonction. 2.6 Compiler la source C et créer une bibliothèque nativeRappelez-vous que lorsque vous avez créé la classe
HelloWorld
dans leHelloWorld.java
fichier, vous avez inclus une ligne de code qui a chargé un natif bibliothèque dans le programme:System.loadLibrary("HelloWorld");
Maintenant que tout le code C nécessaire est écrit, vous devez compiler {[57] } et construire ce natif bibliothèque.
Différents systèmes d'exploitation prennent en charge différentes façons de construire natif bibliothèque. Sur Solaris, la commande suivante crée une bibliothèque partagée appelé libHello-World.so:
cc -G -I/java/include -I/java/include/solaris HelloWorld.c -o libHelloWorld.so
L'option-G demande au compilateur C de générer une bibliothèque partagée au lieu d'un Solaris normal fichier exécutable. En raison de la limitation de la largeur de page dans ce livre, nous divisons la ligne de commande en deux lignes. Vous devez taper la commande dans une seule ligne, ou placez la commande dans un fichier de script. Sur
Win32
, le la commande suivante construit une bibliothèque de liens dynamiques (DLL)HelloWorld.dll
utilisation du compilateur Microsoft Visual C++:cl -Ic:\java\include -Ic:\java\include\win32 -MD -LD HelloWorld.c -FeHelloWorld.dll
L'option
-MD
garantit queHelloWorld.dll
est lié à la bibliothèque C multithreadWin32
. L'option-LD
demande au compilateur C de générer une DLL au lieu d'une exécutable Win32 régulier. Bien sûr, sur Solaris et Win32 vous besoin de mettre dans les chemins d'inclusion qui reflètent la configuration sur votre propre machine.2.7 Exécuter le Programme
À ce stade, vous avez les deux composants prêts à fonctionner programme. Le fichier de classe (
HelloWorld.class
) appelle une méthode native, et la bibliothèque native (Hello-World.dll
) implémente la méthode native.Parce que la classe
HelloWorld
contient sa propre méthode principale, vous pouvez exécuter le programme sur Solaris ou Win32 comme suit:java HelloWorld
, Vous devriez voir la sortie suivante:
Hello World!
Il est important de définir votre chemin de bibliothèque natif correctement pour que votre programme s'exécute. Le chemin de la bibliothèque native est une liste des répertoires que le Java virtuel recherches de la machine lors du chargement bibliothèques natives. Si vous n'avez pas de chemin de bibliothèque natif configuré correctement, alors vous voyez une erreur similaire à la suivante:
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)
Assurez-vous que la bibliothèque native réside dans l'un des répertoires de la bibliothèque native chemin. Si vous utilisez un système Solaris, le
LD_LIBRARY_PATH
la variable d'environnement est utilisée pour définir le chemin de la bibliothèque native. Faire assurez-vous qu'il comprend le nom du répertoire qui contient lelibHelloWorld.so
fichier. Si l'libHelloWorld.so
fichier est dans le courant répertoire, vous pouvez émettre les deux commandes suivantes dans la norme shell (sh) ou KornShell (ksh) pour configurer leLD_LIBRARY_PATH
variable d'environnement correctement:LD_LIBRARY_PATH=. export LD_LIBRARY_PATH
La commande équivalente dans le shell C (csh ou tcsh) est le suivant:
setenv LD_LIBRARY_PATH .
Si vous utilisez un Windows 95 ou Windows NT machine, assurez-vous que
HelloWorld.dll
est dans le courant répertoire, ou dans un répertoire répertorié dans l'environnement PATH variable.Dans Java 2 SDK 1.2 release, vous pouvez également spécifier la bibliothèque native chemin sur la ligne de commande java en tant que propriété système comme suit:
java -Djava.library.path=. HelloWorld
L'option de ligne de commande"
-D
" définit une propriété système de plate-forme Java. Réglage dujava.library.path
la propriété ".
" indique à la machine virtuelle Java de rechercher bibliothèques natives dans le répertoire courant.
En termes simples, assurez-vous simplement de charger la bibliothèque pertinente qui contient la définition de la fonction, chargez la bibliothèque qui suit la spécification JNI et enveloppe la fonction cible de la première bibliothèque, exposez les méthodes natives de votre classe Java et vous devriez être prêt à partir.
Je recommanderais contre JNI brut car il contient beaucoup de code standard et vous finiriez par vous maudire si vous commencez à envelopper une bibliothèque big C. Par tous les moyens, n'hésitez pas à barboter en JNI au début, mais utilisez quelque chose comme JNA quand il s'agit de travail réel.
Vos options incluent:
Interface native Java
voir: https://en.wikipedia.org/wiki/Java_Native_Interface
Citation:
JNI permet aux programmeurs d'écrire des méthodes natives pour gérer les situations où une application ne peut pas être écrite entièrement dans le langage de programmation Java, par exemple lorsque la bibliothèque de classes Java standard ne prend pas en charge les fonctionnalités spécifiques à la plate-forme ou la bibliothèque de programmes
Natif Java Accès
Voir: https://en.wikipedia.org/wiki/Java_Native_Access
Citation:
Java Native Access est une bibliothèque développée par la communauté qui fournit aux programmes Java un accès facile aux bibliothèques partagées natives sans utiliser l'interface Java Native.
JNR-FFI
Voir: https://github.com/jnr/jnr-ffi
Citation:
Jnr-ffi est une bibliothèque java pour charger des bibliothèques natives sans écrire du code JNI à la main ou utiliser des outils tels que SWIG.
Dans la catégorie "exotique", voir NestedVM, qui compile le C en Mips, et exécute un Mips VM à l'intérieur de la JVM.
Checkout JNAerator. https://code.google.com/p/jnaerator/
Vous devez fournir le code source et les définitions du préprocesseur, etc.
Si vous utilisez Windows et MinGW gcc, vous aurez peut-être besoin d'un indicateur supplémentaire si vous obtenez UnsatisfiedLinkError pour une méthode spécifique dans lib:
gcc -D_JNI_IMPLEMENTATION_ -Wl,--kill-at -I"%JAVA_HOME%"\include -I"%JAVA_HOME%"\include\win32 BestCode.c -shared -o BestCode.dll
Pour rendre la dll compatible 64 bits Supprimer l'option "- MD " de l'instruction ci-dessous
"cl -Ic:\java\include -Ic:\java\include\win32 -MD-LD HelloWorld.c-FeHelloWorld.dll "
J'ai une solution à ce problème. Ce que vous devez vous assurer, c'est que vous compilez le code à l'aide d'un compilateur c++ 64 bits pour appeler la fonction java s'exécutant sur JRE 64 bits. Parallèlement à cela, nous devons enregistrer le chemin du fichier dll créé dans "Chemin" sous "Variable d'environnement".