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

Interfaçage autre langage Python Discussion :

Appeler une fonction d'une DLL compilée depuis Fortran [Python 3.X]


Sujet :

Interfaçage autre langage Python

  1. #1
    Membre éprouvé

    Homme Profil pro
    Ingénieur
    Inscrit en
    Août 2010
    Messages
    654
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2010
    Messages : 654
    Points : 1 150
    Points
    1 150
    Par défaut Appeler une fonction d'une DLL compilée depuis Fortran
    Bonjour,

    Admettons le code Fortran suivant (add_f.f90) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    function add(x, y)
     
        implicit none
     
        double precision             :: add
        double precision, intent(in) :: x, y
     
        add = x + y
     
    end function add
    Je peux le compiler en une library comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    gfortran -c -fno_underscoring add_f.90
    gfortran -shared -fPIC -o add_f.so add_f.o
    Je peux vérifier le contenu de la library :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    nm -D add_f.so
    00000000000010f9 T add
                     w __cxa_finalize
                     w __gmon_start__
                     w _ITM_deregisterTMCloneTable
                     w _ITM_registerTMCloneTable
    Je souhaite maintenant appeler la fonction add depuis un script Python. Je me suis inspiré pour cela du sujet suivant : https://www.developpez.net/forums/d2.../#post11404304

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    import ctypes
     
    # Définition de la fonction add depuis la library
    libf = ctypes.CDLL('add_f.so')
    func = libf.add
     
    # Définition du type des arguments et de la sortie
    func.argtypes = [ctypes.c_double, ctypes.c_double]
    func.restype = ctypes.c_double
     
    # test
    res = func(1.2, 3)
     
    print(res)
    Qui me renvoie un messagre d'erreur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    /tmp/geany_run_script_SE8FJ0.sh: line 7: 54151 Segmentation fault
    Si je ne spécifie pas le type des arguments j'ai un message d'erreur de type TypeError.

    Qu'est-ce qui est incorrect ici ?

    J

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 283
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 283
    Points : 36 770
    Points
    36 770
    Par défaut
    Salut,

    Quand je me lance dans des opérations inhabituelles, je cherche un peu sur Internet d'abord. Ce que je n'ai pas manqué de faire en lisant votre sujet. Ah ben ouais, on peut le faire sans trop de problèmes pourvu qu'on passe ses arguments par référence et qu'on fasse un peu attention aux variations dans les types.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  3. #3
    Membre éprouvé

    Homme Profil pro
    Ingénieur
    Inscrit en
    Août 2010
    Messages
    654
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2010
    Messages : 654
    Points : 1 150
    Points
    1 150
    Par défaut
    Bonjour Wiztricks,

    Je ne saisi pas en quoi mon exemple diffère des exemples que j'ai pu voir sur la doc de ctypes. Il me manque une pièce au puzzle.

    Je me suis penché sur cette notion de "par référence" et "par valeur". Pour moi les arguments x et y ne doivent pas être passés par référence. Peut être la valeur de retour, add, doit l'être elle.

    Mais si je teste :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    from ctypes import CDLL, POINTER, c_double
     
    libf = CDLL('add_f.so')
    func = libf.add
    func.restype = POINTER(c_double)
     
    # Test
    res = func(c_double(1.2), c_double(3))
     
    print(res)
    J'obtiens un pointer <__main__.LP_c_double object at 0x7fac006a4ae8>. Et dès que j'essaie d'accéder à sa valeur par l'attribut .contents, je me retrouve avec un segfault à nouveau.

    J

  4. #4
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 283
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 283
    Points : 36 770
    Points
    36 770
    Par défaut
    Salut,

    Citation Envoyé par Julien N Voir le message
    Je ne saisi pas en quoi mon exemple diffère des exemples que j'ai pu voir sur la doc de ctypes. Il me manque une pièce au puzzle.
    La documentation de ctypes vous explique juste comment charger une DLL, fabriquer les arguments des fonctions, les appeler,...

    Elle ne vous dira pas que telle fonction de la DLL devra être appelée avec des arguments par référence ou par valeur. Et comme ctypes est plutôt orienté C, çà ne racontera pas grand chose non plus sur Fortran.

    Après, si vous voulez réinventer la roue plutôt que de voir comment çà peut se faire en cherchant un peu sur Internet...

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  5. #5
    Membre éprouvé

    Homme Profil pro
    Ingénieur
    Inscrit en
    Août 2010
    Messages
    654
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2010
    Messages : 654
    Points : 1 150
    Points
    1 150
    Par défaut
    Croyez bien que si je pose une question c'est que je n'ai pas trouvé la réponse par moi-même. Il est plus facile de trouver une réponse lorsqu'on sait ce que l'on recherche. C'est pour cette raison que ma question initiale est :

    Qu'est-ce qui est incorrect ici ?
    Je ne vois pas en quoi je réinvente la roue en essayant de faire marcher un exemple simple destiné à comprendre comment cela fonctionne.

  6. #6
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 283
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 283
    Points : 36 770
    Points
    36 770
    Par défaut
    Citation Envoyé par Julien N Voir le message
    Je ne vois pas en quoi je réinvente la roue en essayant de faire marcher un exemple simple destiné à comprendre comment cela fonctionne.
    Tous les exemples que j'ai trouvé disent (et montrent) qu'avec fortran, les arguments sont appelés par référence...

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  7. #7
    Membre éprouvé

    Homme Profil pro
    Ingénieur
    Inscrit en
    Août 2010
    Messages
    654
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2010
    Messages : 654
    Points : 1 150
    Points
    1 150
    Par défaut
    Navré d'avoir posé une question qui semble aussi évidente.

    Au cas où quelqu'un se poserait la même question plus tard, je vais quand même décrire ci-dessous là je me suis arrêté. Je passe en résolu. Je vais chercher le bout qui me manque ailleurs.

    Code Fortran (f90):
    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
    27
    28
    29
    30
    31
    32
    ! Function to add two values
    function add_f(x, y) result(res)
     
        implicit none
     
        double precision, intent(in) :: x, y
        double precision             :: res
     
        res = x + y
     
        print *, "Function add_f"
        print *, x
        print *, y
        print *, res
     
    end function add_f
     
     
    ! Subroutine to add two values
    subroutine add_s(res, x, y)
     
        double precision, intent(in) :: x, y
        double precision, intent(inout) :: res
     
        res = x + y
     
        print *, "Routine add_s"
        print *, x
        print *, y
        print *, res
     
    end subroutine add_s
    Une sousroutine additionnant deux réels dans une sortie nommée res, et une fonction additionnant deux réels et renvoyant res. res étant à chaque fois également un réel.

    Je compile avec gfortran pour avoir une library nommée add.so:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    gfortran -c -fPIC -fno_underscoring add_f.90
    gfortran -shared -o add_f.so add_f.o
    Je parviens à appeler la sous-routine add_s et récupérer le résultat comme suit :
    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
    import ctypes as ct
     
    # Chargement de la librarie
    libf = ct.CDLL('add.so')
     
    # Definition des valeurs des arguments
    x, y = ct.c_double(1.2), ct.c_double(3)
     
    # Appel de la sous-routine. Nécessité de définir la variable de sortie
    # car une sous-routine modifie une valeur, et non ne renvoie quelque chose.
    # De plus, il est nécessaire de "référencer" la valeur par un pointer, de même
    # pour les arguments d'entrée (soit avec byref soit avec pointer, au choix)
    res = ct.pointer(ct.c_double(0.0))
    _ = libf.add_s(res, ct.byref(x), ct.byref(y))
     
    print(res[0])
     
    >>> Routine add_s
    >>>   1.2000000000000000     
    >>>   3.0000000000000000     
    >>>   4.2000000000000002     
    >>>4.2
    Par contre, bien que je parvienne à appeler la fonction add_f, je n'ai pas trouvé comment récupérer sa sortie :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    import ctypes as ct
     
    libf = ct.CDLL('add.so')
     
    x, y = ct.c_double(1.2), ct.c_double(3)
     
    # Appel de la fonction. Là également il faut référencer les arguments.
    res = libf.add_f(ct.pointer(x), ct.pointer(y))
     
    print(res)
     
    >>> 0
    Je reçois le code de sortie uniquement.

    J

  8. #8
    Membre expert
    Homme Profil pro
    Inscrit en
    Octobre 2011
    Messages
    2 873
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 2 873
    Points : 3 717
    Points
    3 717
    Par défaut
    Salut,

    Pourrais-tu nous donner ce qu'il faut pour qu'on puisse tester (la DLL...) ? Ca pourrait aider à aider lol...

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

Discussions similaires

  1. Appeler une dll C# depuis VBA
    Par doudblast dans le forum Général Dotnet
    Réponses: 4
    Dernier message: 17/08/2009, 15h07
  2. Appeler une DLL depuis Javascript
    Par troubleshooting dans le forum Général JavaScript
    Réponses: 3
    Dernier message: 01/07/2008, 14h45
  3. Appel d'une DLL C depuis VB
    Par oliver_mpt dans le forum Windows
    Réponses: 6
    Dernier message: 13/06/2008, 14h40
  4. appeler une DLL depuis un executable
    Par xxiemeciel dans le forum Framework .NET
    Réponses: 10
    Dernier message: 09/07/2007, 14h42
  5. Appel de fonctions d'une DLL C++ depuis Java
    Par max_rossito dans le forum API standards et tierces
    Réponses: 1
    Dernier message: 11/01/2007, 22h54

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