70 votes

Appeler la fonction c depuis Java

Comment appeler une fonction c à partir de Java. Il semble que c soit basé sur le compilateur.

J'aimerais appeler les fonctions C de Windows depuis Java, et les fonctions GCC depuis Java également. la fonction GCC en Java également.

Une référence ?

1 votes

Vous pouvez consulter la JNI (Java Native Interface).

22 votes

Demandé le 11 mai '11 à 11:11 :-)

85voto

Jonas Points 22309

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

2.1 Aperçu

[...] écrire une simple application Java qui appelle une fonction C pour imprimer "Hello World !". Le processus se compose des étapes suivantes :

Créez une classe (HelloWorld.java) qui déclare la méthode native. Utilisez javac pour compiler le fichier source de HelloWorld, ce qui donne la classe fichier 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 fonction de la méthode native native. L'outil javah est fourni avec les versions JDK ou Java 2 SDK de Java. Écrivez l'implémentation C ( HelloWorld.c ) du natif native. Compilez l'implémentation C dans une bibliothèque native, en créant des fichiers Hello-World.dll o libHello-World.so . Utilisez le compilateur et l'éditeur de liens C disponibles sur l'environnement hôte. Exécutez le programme HelloWorld en utilisant l'interpréteur d'exécution java. Le fichier de classe ( HelloWorld.class ) et la bibliothèque native ( HelloWorld.dll o libHelloWorld.so ) sont chargés au moment de l'exécution. Le reste de ce chapitre explique ces étapes en détail. détaillées.

2.2 Déclarer la méthode native

Vous commencez par écrire le programme suivant dans le langage de programmation Java. de programmation Java. Le programme définit une classe nommée HelloWorld qui contient une méthode native 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. Elle est suivie d'une méthode main qui qui instancie la classe Hello-World et invoque la méthode native print pour cette instance. La dernière partie de la définition de la classe est un initialisateur statique qui charge la bibliothèque native contenant l'implémentation de la méthode contenant l'implémentation de la méthode print native.

Il y a deux différences entre la déclaration d'une méthode native telle que print et la déclaration de méthodes normales dans le langage de programmation Java et la déclaration de méthodes normales dans le langage de programmation Java. La déclaration d'une méthode native doit contenir le modificateur natif. Le modificateur natif indique que cette méthode est mise en œuvre dans un autre langage. En outre, la déclaration de méthode native se termine par un point-virgule, le symbole de fin de déclaration, parce qu'il n'y a pas d'implémentation pour les méthodes natives dans la classe elle-même. Nous implémenterons 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 que implémente print doit être chargée. Dans ce cas, nous chargeons la bibliothèque native dans l'initialisateur statique de la méthode HelloWorld classe. La machine virtuelle exécute automatiquement l'initialisateur statique avant d'invoquer les méthodes de la classe HelloWorld garantissant ainsi que la classe bibliothèque native est chargée avant l'appel de la méthode native d'impression.

Nous définissons une méthode principale pour pouvoir exécuter le programme HelloWorld classe. Hello-World.main appelle la méthode native print de la même manière que qu'il appellerait une méthode normale.

System.loadLibrary prend un nom de bibliothèque, localise une bibliothèque native que qui correspond à ce nom, et charge la bibliothèque native dans l'interface utilisateur. l'application. Nous aborderons le processus de chargement exact plus tard dans le livre. Pour l'instant, retenez simplement que pour que System.loadLibrary("HelloWorld") pour réussir, nous devons créer un bibliothèque native appelée HelloWorld.dll sur Win32, ou libHelloWorld.so sur Solaris.

2.3 Compiler la classe HelloWorld

Après avoir défini la classe HelloWorld, enregistrez le code source dans un fichier fichier appelé HelloWorld.java. Compilez ensuite le fichier source à l'aide du javac qui est fourni avec le JDK ou la version Java 2 SDK :

 javac HelloWorld.java

Cette commande va générer un HelloWorld.class dans le répertoire courant.

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

Ensuite, nous allons utiliser le javah outil pour générer un fichier d'en-tête de style JNI qui est utile lors de l'implémentation de la méthode native en C. Vous pouvez exécuter javah sur le 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 de la commande. La commande présentée ci-dessus génère un fichier nommé HelloWorld.h . Nous n'allons pas énumérer le fichier d'en-tête généré fichier d'en-tête généré dans son intégralité. La partie la plus importante du fichier 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);

Ignorer les JNIEXPORT y JNICALL macros 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. aucun argument. Le premier argument de chaque implémentation de méthode native est un JNIEnv pointeur d'interface. Le second argument est une référence à l'interface HelloWorld lui-même (un peu comme le " this " pointeur en C++). Nous verrons comment utiliser le JNIEnv interface et le pointeur de l jobject arguments plus tard dans ce livre, mais cette simple 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 en C ou en 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 Hello-World.print dans un fichier C HelloWorld.c comme 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. Elle utilise la fonction printf pour afficher la chaîne de caractères "Hello World !" et revient ensuite. Comme mentionné précédemment, les deux arguments, le 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. Lorsque vous écrivez des méthodes natives, vous devez toujours inclure ce fichier dans vos fichiers sources C ou C++. stdio.h -- Le code ci-dessus comprend également stdio.h car il utilise le printf fonction. HelloWorld.h -- Le fichier d'en-tête que vous avez généré en utilisant javah . Il comprend le prototype C/C++ du Java_HelloWorld_print fonction. 2.6 Compiler le source C et créer une bibliothèque native

Rappelez-vous que lorsque vous avez créé le HelloWorld dans la classe HelloWorld.java vous avez inclus une ligne de code qui charge un fichier natif dans le programme :

 System.loadLibrary("HelloWorld");   

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

Les différents systèmes d'exploitation prennent en charge différentes manières de construire des applications natives. natives. Sous Solaris, la commande suivante construit 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'une bibliothèque Solaris ordinaire. ordinaire. En raison de la limitation de la largeur des pages dans ce livre, nous divisons la ligne de commande en deux lignes. Vous devez taper la commande sur une seule ligne, ou placer la commande dans un fichier script. Sur Win32 le suivante construit une bibliothèque de liens dynamiques (DLL) HelloWorld.dll en utilisant le compilateur Microsoft Visual C++ :

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

El -MD garantit que l'option HelloWorld.dll est liée à la Win32 bibliothèque C multithread. Le site -LD indique au compilateur C de générer une DLL au lieu d'un fichier exécutable Win32 normal. Bien sûr, sur Solaris comme sur Win32, vous devez devez mettre les chemins d'inclusion qui reflètent la configuration de votre propre machine. machine.

2.7 Exécuter le programme

A 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 l'option bibliothèque native ( Hello-World.dll ) implémente la méthode native.

Parce que le HelloWorld contient sa propre méthode principale, vous pouvez exécuter le programme sur Solaris ou Win32 comme suit :

 java HelloWorld

Vous devriez voir le résultat suivant :

   Hello World! 

Il est important de définir le chemin de votre bibliothèque native correctement pour que votre programme puisse s'exécuter. Le chemin de la bibliothèque native est une liste liste de répertoires que la machine virtuelle Java recherche lors du chargement des bibliothèques natives. Si vous n'avez pas configuré de chemin d'accès à la bibliothèque native correctement, vous obtenez une erreur semblable à celle qui suit :

 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 travaillez sur un système Solaris, l'option LD_LIBRARY_PATH est utilisée pour définir le chemin de la bibliothèque native. Assurez-vous que assurez-vous qu'elle inclut le nom du répertoire qui contient les libHelloWorld.so fichier. Si le libHelloWorld.so se trouve dans le répertoire courant vous pouvez lancer les deux commandes suivantes dans l'interpréteur de commandes standard shell (sh) ou KornShell (ksh) pour configurer le fichier LD_LIBRARY_PATH correctement :

 LD_LIBRARY_PATH=.
 export LD_LIBRARY_PATH

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

 setenv LD_LIBRARY_PATH .

Si vous travaillez sur un ordinateur Windows 95 ou Windows NT, assurez-vous que HelloWorld.dll est dans le courant ou dans un répertoire répertorié dans la variable d'environnement PATH. d'environnement.

Dans la version 1.2 du SDK de Java 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

Le " -D Option de ligne de commande " ". définit une propriété système de la plate-forme Java. La définition de l'option java.library.path en " . " indique à la machine virtuelle Java de rechercher les bibliothèques natives dans le répertoire actuel.

0 votes

Les utilisateurs de Mac peuvent ignorer les commandes de Solaris. Ce blog m'a permis de terminer ce que cette réponse avait permis de commencer : nerdposts.blogspot.com/2010/10/jni-mac-os-x-simple-sample.html

0 votes

Les gens qui lisent ces lignes et qui se demandent pourquoi javah ne fonctionne pas et qui vous disent : " Je ne sais pas ce qui se passe. Error: Could not find class file for 'YourFileName.class'. stackoverflow.com/questions/19137201/

1 votes

Pour Java >= 9, javah est obsolète, il faut donc utiliser javac -h . HelloWorld.java . La réponse à cette question se trouve un peu partout, mais je l'ajouterai ici pour faire court.

12voto

Sanjay T. Sharma Points 12620

En termes simples, assurez-vous 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.

Je vous déconseille d'utiliser la JNI brute, car elle contient beaucoup de code passe-partout et vous finirez par vous maudire si vous commencez à envelopper un fichier de type grand Bibliothèque C. N'hésitez pas à utiliser JNI pour vos débuts, mais utilisez quelque chose comme JNA quand il s'agit du vrai travail.

0 votes

Est-ce que JNA est aussi rapide que JNI ?

5voto

Dawnkeeper Points 1070

Vous avez le choix entre plusieurs options :

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 en langage de programmation Java, par exemple lorsque la bibliothèque de classes Java standard ne prend pas en charge les fonctionnalités ou la bibliothèque de programmes spécifiques à la plate-forme.

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 permet aux programmes Java d'accéder facilement 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 permettant de charger des bibliothèques natives sans avoir à écrire du code JNI à la main, ou à utiliser des outils tels que SWIG.

0 votes

La JNR diffère donc de la JNA ?

3voto

ddyer Points 1546

Dans la catégorie "exotique", voir NestedVM, qui compile le C en Mips, et exécute une Mips à l'intérieur de la JVM.

http://nestedvm.ibex.org/

1voto

Aykut Kllic Points 113

Vérifiez JNAerator. https://code.google.com/p/jnaerator/

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X