web-dev-qa-db-fra.com

Appeler la fonction c de Java

Comment appeler la fonction c à partir de Java . Semble que c est basé sur un compilateur.

Je voudrais appeler la fonction C dans Windows à partir de Java, et GCC fonction de Java aussi.

Toute référence?

54
Wen

Jetez un coup d'œil à Interface native Java: Mise en route .

2.1 Aperçu

[...] écrivez une simple application Java qui appelle une fonction C pour imprimer "Hello World!". Le processus comprend les étapes suivantes:

Créez une classe (HelloWorld.Java) qui déclare la méthode native. Utilisez javac pour compiler le fichier source HelloWorld, ce qui donne le fichier de classe HelloWorld.class. Le compilateur javac est fourni avec les versions JDK ou Java 2 SDK. Utilisez javah -jni pour générer un fichier d’en-tête C (HelloWorld.h) contenant le prototype de la fonction pour l’implémentation de la méthode native. L'outil javah est fourni avec les versions JDK ou Java 2 SDK. Ecrivez l'implémentation C (HelloWorld.c) de la méthode native. Compilez l'implémentation C dans une bibliothèque native en créant Hello-World.dll ou libHello-World.so. Utilisez le compilateur C et l’éditeur de liens disponibles dans l’environnement hôte. Exécutez le programme HelloWorld à l’aide de l’interpréteur d’exécution Java. Le fichier de classe (HelloWorld.class) et la bibliothèque native (HelloWorld.dll ou libHelloWorld.so) sont chargés à l'exécution. La suite de ce chapitre explique ces étapes en détail.

2.2 Déclarer la méthode native

Vous commencez par écrire le programme suivant dans le langage de programmation Java. Le programme définit une classe nommée HelloWorld contenant une méthode native, print.

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. Cette opération est suivie d'une méthode principale qui instancie la classe Hello-World et appelle la méthode native print pour cette instance. La dernière partie de la définition de classe est un initialiseur statique qui charge la bibliothèque native contenant l'implémentation de la méthode native print.

Il existe deux différences entre la déclaration d'une méthode native telle que print et la déclaration de méthodes régulières dans le langage de programmation Java. Une déclaration de méthode native doit contenir le modificateur native. Le modificateur natif indique que cette méthode est implémentée dans une autre langue. En outre, la déclaration de méthode native se termine par un point-virgule, le symbole de terminaison d'instruction, car il n'existe aucune implémentation des méthodes natives dans la classe elle-même. Nous allons implémenter la méthode print dans un fichier C séparé.

Avant que la méthode native print puisse être appelée, la bibliothèque native qui implémente print doit être chargée. Dans ce cas, nous chargeons la bibliothèque native dans l'initialiseur statique de la classe HelloWorld. La machine virtuelle Java exécute automatiquement l'initialiseur statique avant d'appeler des méthodes de la classe HelloWorld, garantissant ainsi que la bibliothèque native est chargée avant l'appel de la méthode native print.

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 qu'elle appellerait une méthode standard.

System.loadLibrary prend un nom de bibliothèque, localise une bibliothèque native correspondant à ce nom et charge la bibliothèque native dans l'application. Nous discuterons du processus de chargement exact plus tard dans le livre. Pour l'instant, rappelez-vous simplement que pour que System.loadLibrary("HelloWorld") réussisse, nous devons créer une bibliothèque native appelée HelloWorld.dll sous Win32 ou libHelloWorld.so sous 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 le fichier source à l’aide du compilateur javac fourni avec le kit JDK ou Java 2 SDK:

 javac HelloWorld.Java

Cette commande générera un fichier HelloWorld.class dans le répertoire actuel.

2.4 Créer le fichier d'en-tête de méthode native

Nous utiliserons ensuite l'outil javah pour générer un fichier d'en-tête de style JNI, utile lors de l'implémentation de la méthode native en C. Vous pouvez exécuter javah sur la classe Hello-World comme suit:

  javah -jni HelloWorld

Le nom du fichier d'en-tête est le nom de la classe avec un ".h" "à la fin. La commande ci-dessus génère un fichier nommé HelloWorld.h. Nous ne listerons pas l'intégralité du fichier d'en-tête généré ici. La partie la plus importante du fichier d'en-tête est le prototype de fonction pour Java_HelloWorld_print, qui est la fonction C qui implémente la méthode HelloWorld.print:

 JNIEXPORT void JNICALL   Java_HelloWorld_print (JNIEnv *, jobject);

Ignorez les macros JNIEXPORT et JNICALL pour le moment. Vous avez peut-être remarqué que l'implémentation C de la méthode native accepte deux arguments, même si la déclaration correspondante de la méthode native n'accepte aucun argument. Le premier argument de chaque implémentation de méthode native est un pointeur d'interface JNIEnv. Le deuxième argument est une référence à l'objet HelloWorld lui-même (un peu comme le pointeur "this" en C++). Nous verrons plus tard comment utiliser le pointeur d'interface JNIEnv et les arguments jobject, mais cet exemple simple 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 des implémentations C ou 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 pouvez implémenter la méthode Hello-World.print dans un fichier C HelloWorld.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;
}

La mise en œuvre de cette méthode native est simple. Il utilise la fonction printf pour afficher la chaîne "Hello World!" et revient ensuite. 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 les informations nécessaires au code natif pour appeler les fonctions JNI. Lors de l'écriture de méthodes natives, vous devez toujours inclure ce fichier dans vos fichiers source C ou C++. stdio.h - L'extrait de code ci-dessus inclut également stdio.h parce qu'il utilise la fonction printf. HelloWorld.h - Le fichier d'en-tête que vous avez généré avec javah. Il inclut le prototype C/C++ pour la fonction Java_HelloWorld_print. 2.6 Compiler la source C et créer une bibliothèque native

Rappelez-vous que lorsque vous avez créé la classe HelloWorld dans le fichier HelloWorld.Java, vous avez inclus une ligne de code qui a chargé une bibliothèque native dans le programme:

 System.loadLibrary("HelloWorld");   

Maintenant que tout le code C nécessaire est écrit, vous devez compiler Hello-World.c et construire cette bibliothèque native.

Différents systèmes d'exploitation prennent en charge différentes manières de créer des bibliothèques natives. Sous Solaris, la commande suivante crée une bibliothèque partagée appelée libHello-World.so:

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

L'option -G indique au compilateur C de générer une bibliothèque partagée au lieu d'un fichier exécutable Solaris standard. En raison de la limitation de la largeur de page dans ce livre, nous séparons la ligne de commande en deux lignes. Vous devez taper la commande sur une seule ligne ou la placer dans un fichier de script. Sur Win32, la commande suivante crée une bibliothèque de liens dynamiques (DLL) HelloWorld.dll à l'aide du compilateur Microsoft Visual C++:

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

L'option -MD garantit que HelloWorld.dll est lié à la bibliothèque Win32 multithread. L'option -LD indique au compilateur C de générer un DLL au lieu d'un exécutable Win32 standard. Bien entendu, sous Solaris et Win32, vous devez indiquer les chemins d’inclusion qui reflètent la configuration sur votre propre ordinateur.

2.7 Lancer le programme

À ce stade, vous avez les deux composants prêts à exécuter le 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.

Étant donné que la classe HelloWorld contient sa propre méthode principale, vous pouvez exécuter le programme sous Solaris ou Win32 comme suit:

 Java HelloWorld

Vous devriez voir la sortie suivante:

   Hello World! 

Il est important de définir correctement le chemin de votre bibliothèque native pour que votre programme puisse s'exécuter. Le chemin de la bibliothèque native est une liste de répertoires que la machine virtuelle Java recherche dans le chargement de bibliothèques natives. Si vous ne disposez pas d'un chemin de bibliothèque natif configuré correctement, une erreur similaire à celle-ci s'affiche:

 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 du chemin de la bibliothèque native. Si vous utilisez un système Solaris, la variable d’environnement LD_LIBRARY_PATH sert à définir le chemin de la bibliothèque native. Assurez-vous qu'il inclut le nom du répertoire contenant le fichier libHelloWorld.so. Si le fichier libHelloWorld.so se trouve dans le répertoire en cours, vous pouvez émettre les deux commandes suivantes dans le shell standard (sh) ou KornShell (ksh) pour configurer correctement la variable d'environnement LD_LIBRARY_PATH:

 LD_LIBRARY_PATH=.
 export LD_LIBRARY_PATH

La commande équivalente dans le shell C (csh ou tcsh) est la suivante:

 setenv LD_LIBRARY_PATH .

Si vous utilisez une machine Windows 95 ou Windows NT, assurez-vous que HelloWorld.dll se trouve dans le répertoire en cours ou dans un répertoire répertorié dans la variable d'environnement PATH.

Dans la version Java 2 SDK 1.2, vous pouvez également spécifier le chemin d'accès à la bibliothèque native 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 la plate-forme Java. Définir la propriété Java.library.path sur "." demande à la machine virtuelle Java de rechercher des bibliothèques natives dans le répertoire en cours.

72
Jonas

En termes simples, veillez simplement à charger la bibliothèque appropriée contenant la définition de la fonction, la bibliothèque qui suit la spécification JNI et enveloppe la fonction cible de la première bibliothèque, expose les méthodes natives de votre classe Java et vous devriez être prêt à partir .

Je recommande contre raw JNI car il contient beaucoup de code passe-partout et vous finirez par vous maudire si vous commencez à emballer une bibliothèque big C. Bien sûr, n'hésitez pas à vous lancer dans JNI lorsque vous débutez, mais utilisez quelque chose comme JNA lorsqu'il s'agit de travail réel.

11
Sanjay T. Sharma

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 dans lesquelles une application ne peut pas être entièrement écrite 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

Accès natif Java

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

citation:

Java Native Access est une bibliothèque développée par la communauté qui offre aux programmes Java un accès facile aux bibliothèques partagées natives sans utiliser l'interface native Java.

JNR-FFI

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

citation:

jnr-ffi est une bibliothèque Java permettant de charger des bibliothèques natives sans écrire manuellement le code JNI ni utiliser des outils tels que SWIG.

5
Dawnkeeper

Dans la catégorie "exotique", voir NestedVM, qui compile le C en Mips et exécute un Mips VM au sein de la JVM.

http://nestedvm.ibex.org/

2
ddyer

Si vous utilisez Windows et MinGW gcc, vous devrez peut-être 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
1
Justas

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

Vous devez fournir le code source et les définitions du préprocesseur, etc.

1
Aykut Kllic

J'ai une solution à ce problème. Vous devez vous assurer que vous compilez le code à l'aide du compilateur c ++ 64 bits pour appeler une fonction Java exécutée sur un environnement d'exécution Java 64 bits. Parallèlement, nous devons enregistrer le chemin du fichier dll créé dans "Chemin" sous "Variable d'environnement".

0
Dila Gurung

Assurez-vous d'abord de charger votre bibliothèque native ou votre fichier .dll dans le chemin d'accès aux classes en définissant le chemin dans la propriété Java.library.path

Ensuite, utilisez System.loadLibrary()

Do not use .dll extension at the end.
0
user3906011

@Jonas a donné une réponse très élaborée, mais je pense que cela vaut également la peine de consulter ce site Web et vous obtiendrez toutes vos réponses essentielles ici: 

http://www.ntu.edu.sg/home/ehchua/programming/Java/javanativeinterface.html

Il explique comment appeler un programme utilisant JNI: 

  • Pour les langages C et C++ ou un mélange des deux
  • JNI sans aucun paramètre, primitive, chaîne ou tableau de primitives
  • Accéder aux variables d'objet, aux méthodes d'instances de rappel et bien plus encore.
0
aks

Pour rendre les dll compatibles 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" 

0
Dila Gurung

JNI - Interface native Java

Pour appeler la fonction C depuis Java, vous devez utiliser JNI

0
Steven Bialecki