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

C++ Discussion :

Appels croisés fortran, c, c++


Sujet :

C++

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    6
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Avril 2009
    Messages : 6
    Points : 5
    Points
    5
    Par défaut Appels croisés fortran, c, c++
    Bonjour à tous.

    Voici mon problème :

    Je dois, à partir d'un programme principal en fortran, appeler une fonction c++, qui elle-même appelle une subroutine fortran du programme principal.

    Je code sous linux et après quelques tours sur des forums sur le sujet j'ai cru comprendre que le plus simple était de passer par du C.

    Mon architecture est donc la suivante :
    le programme fortran appelle une fonction C, qui elle-même appelle une fonction c++, qui elle-même appelle une subroutine fortran.

    Et y'a un soucis à la compilation.

    Voici les squelettes de mes codes :

    Fortran (fonction.f) :
    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
    24
    25
    26
    program fortran
     
    end
     
    recursive &
       subroutine solveur (fcn, x, tolerance, code_sortie)
     
         ! arguments
         interface
           subroutine fcn (n, m,  x, fvec, iflag)
             integer   :: n
             integer   :: m
             real, dimension (1:3) :: x(n)
             real, dimension (1:3) :: fvec(m)
             integer   :: iflag
           end subroutine fcn
         end interface
     
         real, dimension (1:3) :: x(:)
         real, dimension (1:3) :: tolerance
         integer,   intent(out)   :: code_sortie
     
         ! appel
         call interface_n(n, m, x, tolerance, code_sortie)
     
       end subroutine solveur
    Le C (module.c):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    #include <stdlib.h>
    #include <stdio.h>
     
    extern void n_cpp(int, int, float*, int, int);
     
    void interface_n(int n, int m, float *x, int tolerance, int code_sortie)
    {
    	nomad_cpp(n, m, x, tolerance, code_sortie);
    }
    Et le c++ (n_cpp):
    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
    #include <iostream>
    #include <fstream>
     
    using namespace std;
     
    extern "C"
    {
    void n_cpp(int, int, float*, int, int);
    void fcn_(int*, int*,  float*, float*, int*);
    }
     
    void n_cpp(int n, int m, float *x, int tolerance, int code_sortie)
    {
    	float fvec[m];
    	int iflag = -1;
    	fcn_(&n, &m, x, fvec, &iflag);
    }
    Bien sûr ces codes sont bidons, c'est juste pour essayer de faire fonctionner ces "appels croisés".

    Je compile tout ça avec :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    % gfortran -c -ffree-form fonction.f
    % gcc -c module.c
    % g++ -c n_cpp.cpp
    % gfortran -o fonction.o module.o n_cpp.o
    Et voici l'erreur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    n_cpp.o: In function `__static_initialization_and_destruction_0(int, int)':
    n_cpp.cpp:(.text+0x1d): undefined reference to `std::ios_base::Init::Init()'
    n_cpp.cpp:(.text+0x22): undefined reference to `std::ios_base::Init::~Init()'
    n_cpp.o: In function `nomad_cpp':
    n_cpp.cpp:(.text+0x185): undefined reference to `fcn_'
    n_cpp.o:(.eh_frame+0x12): undefined reference to `__gxx_personality_v0'
    /usr/lib/gcc/i586-suse-linux/4.3/libgfortranbegin.a(fmain.o): In function `main':
    (.text+0x35): undefined reference to `MAIN__'
    collect2: ld a retourné 1 code d'état d'exécution
    En tapant ces erreurs dans Google (qui est mon ami) j'ai trouvé comme raison des programmes c++ compilés avec gcc au lieu de g++.
    J'ai donc essayé de compiler mon code c avec g++, modulo une toute petite modif au niveau de la déclaration de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    extern void n_cpp(int, int, float*, int, int);
    qui devient
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    extern "C"
    { void n_cpp(int, int, float*, int, int);}
    mais les erreurs restent les mêmes...

    Et je bloque...

    Est-ce que quelqu'un pourrait m'aider sioupl ?

    Est-ce que les appels croisés que je fais sont tout simplement impossibles ?
    Ou est-ce que je fais une erreur lors de l'éditions des liens ?
    Ou autre chose encore ?

    Merci beaucoup.

  2. #2
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 49
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Points : 4 846
    Points
    4 846
    Par défaut
    En général, importer un module d'un autre langage requiert plusieurs choses :
    • Utiliser une interface commune (convention d'appel, nommage, etc.).
    • Savoir comment charger une fonction externe depuis chaque langage hôte.
    • Utiliser des données pouvant être comprises par les deux langages, que ce soit au niveau des types ou de l'organisation mémoire.


    En général, il est plus simple de compiler une DLL (un SO dans ton cas), et de tenter d'importer les fonctions depuis cette librairie. Ton système d'exploitation fournit des fonctions pour, justement, charger à la demande des fonctions d'une DLL et t'éviter ainsi de devoir absolument faire cohabiter le format d'objets.

    Sous Windows, il existe Dependancy Walker qui permet de savoir quelles sont les fonctions exportées d'une DLL, ainsi que le nom sous lequel elles sont exportées. Tu devrais essayer de trouver l'équivalent sous Linux, je pense.

    EDIT : Il faudrait de toutes façons que tu fasses une librairie en Fortran avec tes fonctions, et non pas un programme...
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

  3. #3
    Membre averti Avatar de uriotcea
    Homme Profil pro
    Ingénieur / physicien
    Inscrit en
    Septembre 2003
    Messages
    1 301
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur / physicien
    Secteur : Service public

    Informations forums :
    Inscription : Septembre 2003
    Messages : 1 301
    Points : 444
    Points
    444
    Par défaut
    Salut,

    Je fais régulierement des appels croisés entre C et fortran en utilisant gcc & gfortran. ca fonctionne bien si je respecte 2 regles simples.
    - finir la fonction en C par '_', ne pas le mettre en fortran
    - Toujours utiliser des pointeurs en C pour les arguments

    Pour ma part, j'ai renoncé à inclure du C++. Alors si tu trouve une méthode je suis preneur

  4. #4
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 49
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Points : 4 846
    Points
    4 846
    Par défaut
    Citation Envoyé par uriotcea Voir le message
    Pour ma part, j'ai renoncé à inclure du C++. Alors si tu trouve une méthode je suis preneur
    En C++, les noms sont modifiés (ce que l'on appelle le name mangling, ou décoration de noms).

    Donc, si tu n'as pas le nom décoré de ta fonction (dépend de ses paramètres, retours et de son adressage absolu en fonction des classes / namespaces), tu ne peux pas l'importer. Si c'est en plus une méthode de classe, c'est encore pire car il faut penser à passer un paramètre this caché, mais ça, encore, on peut le pallier via des singletons et des pointeurs transmis directement depuis le C++.

    Sous Windows, ton ami sera Dependancy Walker, qui te permettra de voir les noms décorés exportés depuis une DLL. Sous Linux, je ne sais pas quel est l'équivalent.
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

  5. #5
    screetch
    Invité(e)
    Par défaut
    il y a plusieurs petites fautes :
    - en fortran, ta fonction fcn n'est pas exportée, probablement car c'est une sous fonction
    ecrit comme ca :
    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
    program fortran
     
    end
     
    recursive &
        subroutine fcn (n, m,  x, fvec, iflag)
             integer   :: n
             integer   :: m
             real, dimension (1:3) :: x(n)
             real, dimension (1:3) :: fvec(m)
             integer   :: iflag
           end subroutine fcn
     
        subroutine solveur (fcn, x, tolerance, code_sortie)
     
         real, dimension (1:3) :: x(:)
         real, dimension (1:3) :: tolerance
         integer,   intent(out)   :: code_sortie
     
         ! appel
         call interface_n(n, m, x, tolerance, code_sortie)
     
       end subroutine solveur
    c'est deja mieux
    utilise objdump -t fonction.o pour voir les symboles

    ensuite en C, tu appelles la fonction inexistante nomade_cpp
    or tu l'as appelée n_cpp avant. Utilise -Wall pour voir ce genre d'erreurs

    ensuite pour pouvoir etre appelée de fortran, ta fonction C doit se terminer par un underscore :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    #include <stdlib.h>
    #include <stdio.h>
     
    extern void n_cpp(int, int, float*, int, int);
     
    void interface_n_(int n, int m, float *x, int tolerance, int code_sortie)
    {
    	n_cpp(n, m, x, tolerance, code_sortie);
    }
    rien a redire sur le C++
    enfin, le probleme plus haut ne venait pas du compilateur mais du linker
    tu dois utiliser le linker g++ lorsque tu compiles du c++, ou le linker gfortran quand tu compiles du fortran, parce qu'ils ajoutent automatiquement les libs C++/Fortran qui vont bien. Si tu dois linker du C++ avec du fortran, je pense que le mieux est de linker avec gfortran et de rajouter les libs C++ sur la ligne de commande :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    gfortran -o pg fonction.o module.o n_cpp.o -l stdc++
    voila, un petit melange de C, C++ et Fortran qui... ne fait rien. j'ai été décu du résultat, j'aurais bien aimé un "Hello world"


    [code]

  6. #6
    Futur Membre du Club
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    6
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Avril 2009
    Messages : 6
    Points : 5
    Points
    5
    Par défaut
    Merci beaucoup screetch, problème résolu !

  7. #7
    Membre éclairé
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    1 298
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 298
    Points : 886
    Points
    886
    Par défaut
    Bonjour,

    j'appelle moi aussi constamment dans mes programmes du code C, C++ et Fortran. Je travaille sous Visual Studio. Je mets tout mon code fortran dans un librairie static, et je compile le C et le C++ ensemble. Je ne me soucis pas de rajouter un underscore à mes noms de fonctions C. Je fais "juste" un extern "C" pour déclarer dans mes sources C++ mes fonctions C et fortran.

    J'ai du code C++ qui appelle du code C qui appelle du code fortran qui réappelle du code C (et / ou C++). Tout se mélange bien...

    Par contre, j'avais entendu dire qu'en fortran les tableaux sont rangés en colonne et en C en ligne. Cela peut-il être source de problèmes ?

    Merci

  8. #8
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 49
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Points : 4 846
    Points
    4 846
    Par défaut
    Citation Envoyé par salseropom Voir le message
    Par contre, j'avais entendu dire qu'en fortran les tableaux sont rangés en colonne et en C en ligne. Cela peut-il être source de problèmes ?
    Bien sûr, vu que ça va normalement transposer ta matrice entre le C et le Fortran (inversion des indices).
    Par contre, sur un tableau simple (vecteur), cela ne devrait pas être visible, seulement sur les matrices.
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

  9. #9
    Membre éclairé
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    1 298
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 298
    Points : 886
    Points
    886
    Par défaut
    Citation Envoyé par Mac LAK Voir le message
    Bien sûr, vu que ça va normalement transposer ta matrice entre le C et le Fortran (inversion des indices).
    Par contre, sur un tableau simple (vecteur), cela ne devrait pas être visible, seulement sur les matrices.
    Effectivement, ça paraît logique ce que tu dis (j'aurais pu réfléchir un peu plus avant de poster...)

  10. #10
    Membre du Club
    Inscrit en
    Mai 2004
    Messages
    76
    Détails du profil
    Informations forums :
    Inscription : Mai 2004
    Messages : 76
    Points : 49
    Points
    49
    Par défaut
    Il est étrange que, pour ces cas là, gcc ne propose pas d'options pour rajouter un tiret bas à la fin du nom de la fonction C, non? on trouve ce genre d'options dans gfortran, etc...

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

Discussions similaires

  1. Appel de fortran à partir du C
    Par lilwah dans le forum C
    Réponses: 2
    Dernier message: 06/10/2014, 17h59
  2. gnuplot appeler par fortran installer sous windows
    Par centkilo dans le forum Fortran
    Réponses: 0
    Dernier message: 14/02/2011, 13h52
  3. Appel de Fortran 90/95 par du 77
    Par sebauvray dans le forum Fortran
    Réponses: 1
    Dernier message: 20/12/2010, 20h17
  4. C# - appeler méthode fortran avec array
    Par azraec dans le forum C#
    Réponses: 0
    Dernier message: 12/04/2010, 16h34
  5. Appel de Fortran
    Par albertgl dans le forum Débuter
    Réponses: 1
    Dernier message: 27/09/2008, 11h12

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