IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Entrée/Sortie Java Discussion :

[JNI] Appeler une DLL Fortran à partir de Java


Sujet :

Entrée/Sortie Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Février 2006
    Messages
    14
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 14
    Par défaut [JNI] Appeler une DLL Fortran à partir de Java
    Bonjour à tous,
    Ma situation est assez spéciale, je souhaiterais faire appel à des fonctions Fortran sous Windows (compilées dans une DLL) depuis un programme Java. Pour cela j’utilise la librairie Java Native Interface. Avant tout, j'essai de commencer très simple avec le fameux programme HelloWorld. Malheureusement je n’y arrive pas et j’ai besoin de votre aide. J’ai réussi dans un premier temps à linker le Java et le C++ sans problème, mais je bloque à l’étape suivante : lecture la DLL Fortran à partir du C++

    J’essai d’utiliser les compilateurs GNU open source pour réaliser cela, c'est-à-dire gcc (g++) et gfortran.

    Voici les étapes que j’ai réalisée jusque la :
    1- Installation de Java 6.0 et Eclipse 3.4
    2- Installation de gfortran (http://gcc.gnu.org/wiki/GFortran)
    3- Installation de devCpp (http://sourceforge.net/projects/dev-cpp/)
    4- Création du programme HelloWorld fortran (fichier helloworld.f90)

    helloworld.f90

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    program helloworld
        write(*,*) "Hello world!"
    end program helloworld
    5- Compilation du programme avec gfortran (option –c) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    "C:\Program Files\gfortran\bin\gfortran.exe" -c D:\helloworld.f90
    Remarque : J’ai également vu sur certain site l’option –fPIC qui était utilisée mais celle-ci n’a pas l’air d’être utile puisqu’elle génère le message suivant : f951.exe: warning: -fPIC ignored for target (all code is position independent)

    6- Création de la DLL toujours avec gfortran (options -Xlinker -shared –o) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    "C:\Program Files\gfortran\bin\gfortran.exe" -shared -o D:\helloworld.dll D:\helloworld.o
    Remarque : j’ai essayé la commande avec d’autres options que j’ai pu voir :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    "C:\Program Files\gfortran\bin\gfortran.exe" -Xlinker -shared -o D:\helloworld.dll D:\helloworld.o
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    "C:\Program Files\gfortran\bin\gfortran.exe" -shared -mtrd -o D:\helloworld.dll D:\helloworld.o
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    "C:\Program Files\gfortran\bin\gfortran.exe" -Xlinker --add-stdcall-alias -shared -o D:\helloworld.dll D:\helloworld.o
    Mais cela n’a pas l’air de changer quelque chose.
    A la suite de cette étape, j’obtiens la DLL Fortran helloworld.dll

    7- Création du fichier Java FortranExecuter.java et de la méthode native helloworld()

    FortranExecuter.java

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    public class FortranExecuter {
     
    	private static native double helloworld();
     
    	static {
    		System.load("D:\\FortranExecuter.dll");
    	}
     
     
    	public static void main(String[] args) {
    		FortranExecuter.helloworld();
    	}
    }
    8- Compilation du fichier FortranExecuter.java

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    C:\j2sdk6.0.7\jdk\bin\javac.exe D:\FortranExecuter.java
    9- Génération du fichier d’entete .h avec la commande javah.exe

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    C:\j2sdk6.0.7\jdk\bin\javah.exe -classpath D:\ -d D:\ -jni FortranExecuter
    10- Modification du fichier FortranExecuter.h généré en ajoutant la méthode cobol externe

    FortranExecuter.h

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     
    /* DO NOT EDIT THIS FILE - it is machine generated */
    #include <jni.h>
    /* Header for class FortranExecuter */
     
    #ifndef _Included_FortranExecuter
    #define _Included_FortranExecuter
    #ifdef __cplusplus
    extern "C" {
    #endif
    /*
     * Class:     FortranExecuter
     * Method:    helloworld
     * Signature: ()D
     */
    JNIEXPORT jdouble JNICALL Java_FortranExecuter_helloworld(JNIEnv *, jclass);
     
    void helloworld_();
     
    #ifdef __cplusplus
    }
    #endif
    #endif
    Remarque : dans d'autres discussions, j'ai parfois vu l'utilisation des macros __declspec (dllexport) et __stdcall devant la méthode externe, j'ai fait quelques tests mais en vain. je ne sais pas trop à quoi ces directives servent.

    11- Création du fichier FortranExecuter.cpp

    FortranExecuter.cpp

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    // FortranExecuter.cpp
    #include <jni.h>
    #include <stdio.h>
    #include "FortranExecuter.h"
     
    JNIEXPORT jdouble JNICALL Java_FortranExecuter_helloworld(JNIEnv * env, jclass cl) {
        helloworld_();
    }
    12- Compilation du programme avec g++ (option –c) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    C:\Dev-Cpp\bin\g++.exe -I"C:\j2sdk6.0.7\jdk\include" -I"C:\j2sdk6.0.7\jdk\include\win32" -c D:\FortranExecuter.cpp -o D:\FortranExecuter.o
    13- Création de la DLL C toujours avec g++ (options -Xlinker --add-stdcall-alias -shared -o) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    C:\Dev-Cpp\bin\g++.exe -Xlinker --add-stdcall-alias -shared -o D:\FortranExecuter.dll D:\FortranExecuter.o
    Cette commande génère l’érreur de lien suivante me disant qu’il ne trouve pas la fonction helloworld :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    D:\FortranExecuter.o(.text+0x7):FortranExecuter.cpp: undefined reference to `helloworld_'
    collect2: ld returned 1 exit status
    Remarque : j’ai essayé de déplacer la DLL fortran dans les fichiers systèmes mais sans résultat. J’ai également essayé certaines options mais j’ai peur qu’il manque quelquechose dans ma démarche.

    Auriez vous des conseils / idées afin de faire marcher le lien ? Je n'ai trouvé aucun tutoriel viable sur le net et j'ai également consulté certaines autres discussions sur ces pages :

    http://www.developpez.net/forums/d34...fortran-c-cpp/

    http://www.developpez.net/forums/d63...ant-creer-dll/

    http://www.developpez.net/forums/d37...n-fortran-cpp/

  2. #2
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 901
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 901
    Billets dans le blog
    54
    Par défaut
    L'erreur t'indique qu'aucune bibliotheque utilisees lors de la phase de liaison ne contient la fonction helloworld telle qu'elle est appellee par le programme (ce qui ne pose aucun probleme pour la phase de compilation en objet puisque cette fonction est definie dans le .h*). Tu utilises GCC, il t'es possible de specifier le repertoire contenant les lib via la variable systeme LD_LIBRARY_PATH ou via le flag -L<nom du repertoire> lors de la phase de lien.

    *Elle est definie dans le .h et tu l'appelles dans le .cpp mais elle ne semble pas etre implementee nulle part ! Ne te faut-il pas inclure un .h fortran pour lui dire d'aller la chercher dans le DLL ??

    Pour le reste, ceci ne semble pas etre un probleme java (pour le moment).
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Février 2006
    Messages
    14
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 14
    Par défaut Solution!
    Après beaucoup de galères et une longue recherche, j'ai finalement réussi à faire marcher le code Fortran à partir de Java.

    Plusieurs choses n'étaient pas correctes :

    Etape 4 : le programme fortran était un main, donc il s'exécutait directement lors du chargement de la DLL, ce qui arrête brusquement le programme en langage C. Voici les changements apportés :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    subroutine helloworld
        write(*,*) "Hello world!"
    end subroutine
     
    integer function sum(a, b, c)
       implicit none
     
       integer, intent(in) :: a, b, c
     
       sum = a + b + c
    end function sum
    PS : j'ai déclaré une autre fonction sum pour aller plus loin par la suite.

    Etape 6 :
    La bonne commande à exécuter est bien celle ci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    "C:\Program Files\gfortran\bin\gfortran.exe" -shared -o D:\helloworld.dll D:\helloworld.o
    En effet, l'option -XLinker ne marchait pas et elle ajoutait la fonction main dans la DLL, celle ci étant exécutée à son chargement.

    Etape 7 : Petite correction de prototype dans la classe Java

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    public class FortranExecuter {
     
    	private static native void helloworld();
     
    	static {
    		System.load("D:\\FortranExecuter.dll");
    	}
     
     
    	public static void main(String[] args) {
    		FortranExecuter.helloworld();
    	}
    }
    Etape 10 : Il ne faut pas toucher le .h en essayant d'ajouter la fonction de la DLL, ceci ne doit être fait que pour une compilation statique apparament (avec un .lib ou .a par exemple). J'ai donc enlevé la déclaration de la méthode puisque l'on chargera la DLL dynamiquement. Notez également la correction du type de retour de la fonction helloworld qui a été corrigé.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     
    /* DO NOT EDIT THIS FILE - it is machine generated */
    #include <jni.h>
    /* Header for class FortranExecuter */
     
    #ifndef _Included_FortranExecuter
    #define _Included_FortranExecuter
    #ifdef __cplusplus
    extern "C" {
    #endif
    /*
     * Class:     FortranExecuter
     * Method:    helloworld
     * Signature: ()D
     */
    JNIEXPORT void JNICALL Java_FortranExecuter_helloworld(JNIEnv *, jclass);
     
    void helloworld_();
     
    #ifdef __cplusplus
    }
    #endif
    #endif
    Etape 11 : Le fichier .cpp est grandement modifié puisque l'on charge la DLL dynamiquement à l'aide du code suivant ou il faut faire appel à windows.h:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     
    // FortranExecuter.cpp
    #include <jni.h>
    #include <stdio.h>
    #include <windows.h>
    #include "FortranExecuter.h"
     
    typedef void (__stdcall * MYDLLFUNC) (void);
     
    JNIEXPORT void JNICALL Java_FortranExecuter_helloworld(JNIEnv * env, jclass cl) {
        HINSTANCE hModDll;
        if (hModDll = LoadLibrary("D:\\helloworld.dll")) {
           MYDLLFUNC ImpFuncDLL = (MYDLLFUNC) GetProcAddress((HINSTANCE) hModDll, "helloworld_");
           if (ImpFuncDLL) {
              ImpFuncDLL();
           }
           FreeLibrary(hModDll);            
        }
    }
    PS : remarquez bien le caractère _ à la fin de la fonction helloworld. Il est présent dans la définition de la fonction dans la DLL, n'hésitez pas à vérifier son contenu grâce au petit soft depends (http://www.dependencywalker.com/).

    Et voila, avec tout cela, ca marche et le programme Java ne plante plus. J'espère que ce petit tutoriel pourra en aider certain.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Appeler une DLL C à partir de C#
    Par Yan302 dans le forum C#
    Réponses: 1
    Dernier message: 19/07/2010, 16h16
  2. Appeler une Dll (en c++) en Java
    Par MarsOran dans le forum Général Java
    Réponses: 4
    Dernier message: 28/01/2008, 17h30
  3. Réponses: 12
    Dernier message: 23/05/2007, 21h40
  4. Problème appel JNI d'une dll via COM
    Par mfabien dans le forum C
    Réponses: 3
    Dernier message: 13/04/2007, 14h38
  5. Appel d'une DLL Win32 à partir d'une appli DOS 16bit
    Par telghali dans le forum Assembleur
    Réponses: 5
    Dernier message: 23/02/2007, 21h42

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo