<?xml version="1.0" encoding="utf-8"?>
<document>
   <titre>Python et SWIG</titre>
   <contenu>
      
      <h2>SWIG pour interfacer une bibliothèque C avec Python</h2>
      
      <p class="abstract">
     SWIG (<i>Simplified Wrapper and Interface Generator</i>) permet de connecter des langages interprétés comme Python, Perl ou Ruby avec C/C++.
     SWIG utilise les fichiers <i>header</i> de ces langages pour générer un emballage (<i>wrapper</i>) qui permet
     d’accéder aux méthodes, structures et objets des langages C/C++.
      </p>

<p>L’interêt de SWIG est de profiter de l’efficacité des langages compilés C/C++
 et de la diversité des différentes bibliothèques construites dans ces langages.</p>

<p>
Ce document montre par un exemple comment récupérer des stuctures de données
du langage C.
</p>

<h3>Exemple</h3>

<p>Prenons le cas d’une bibliotèque très simple qui manipule des vecteurs.</p>

<p><a href="SWIG-Python.zip">Télécharger les fichiers d’exemples</a>.</p>

<h4>Fichier <i>header</i> "biblio.h"</h4> 

<p>
Le fichier <i>header</i> décris les structures de données et le 
prototype des fonctions de la bibliothèque
</p>

<pre>
struct Vector
{
        double x,y,z;
        <span>// ce tableau nous sera utile pour 
        // détécter des fuites de mémoire</span>
        double faketab[100000];
};

struct Vector * getUnitVector();
void deleteVector(struct Vector *v);
</pre>

<h4>Fichier de la bibliothèque "biblio.c"</h4> 

<p>En suivant une syntaxe particulière, il est possible de définir
un constructeur et un destructeur pour notre structure. Si
on ne le fait pas SWIG les génère automatiquement à partir 
du fichier <code>header</code>.</p>

<pre>
<span>#include "biblio.h"
#include &lt;stdlib.h&gt;</span>

<span>// constructeur de la structure pour SWIG</span>
struct Vector * new_Vector()
{
        struct Vector *v;
        v = (struct Vector *)malloc(sizeof(struct Vector));
        v-&gt;x = v-&gt;y = v-&gt;z = 0;
        return v;
}

<span>// destructeur de la structure pour SWIG</span>
void delete_Vector(struct Vector *v)
{
        free(v);
}

<span>// créé un vecteur unitaire</span>
struct Vector * getUnitVector()
{
        struct Vector *v = new_Vector();
        v-&gt;x=1;
        return v;
}

<span>// supprime un vecteur donné</span>
void deleteVector(struct Vector *v)
{
        free(v);
}


</pre>

<h4>Fichier d’interface "biblio.i"</h4>

<p>Ce fichier d’interface indique à SWIG quel sera le nom
du <i>wrapper</i> ainsi que les fichiers sources qu’il doit analyser.</p> 

<pre>
%module biblio
<span>// le code suivant est simplement copié 
// au début de celui du "wrapper" généré</span>
%{
#include "biblio.h"
%}
<span>// le fichier à analyser</span>
%include "biblio.h"

<span>// permet d’enregistrer le constructeur 
// et le destructeur auprès de SWIG</span>
%extend Vector 
{
     Vector();
     ~Vector();
};

</pre>

<h4>Le <i>Makefile</i></h4>

<p>Ce fichier de commande suivant génère les fichiers <i>wrapper</i> en C et en Python puis compile la bibliotèque.</p>

<pre>
SHELL = /bin/sh
WRAPPER = biblio

make:
   swig -python ${WRAPPER}.i 
   gcc -c ${WRAPPER}.c ${WRAPPER}_wrap.c \
      -I /usr/include/python2.4/
   rm ${WRAPPER}_wrap.c
   ld -shared ${WRAPPER}.o \
      ${WRAPPER}_wrap.o -o _${WRAPPER}.so
   rm ${WRAPPER}.o ${WRAPPER}_wrap.o
</pre>

<h3>Utilisation du <i>wrapper</i> avec Python</h3>

<p>Ce script Python permet de montrer comment 
utiliser cette bibliotèque C afin d'éviter des fuites de mémoire.</p>

<p>Ce code crée 1000 vecteurs, une fois en utilisant la fonction <code>getUnitVector</code>, une fois en
utilisant le constructeur.</p>

<p>Si on utilise le constructeur de l’objet Python fourni par le <i>wrapper</i> le destructeur de l’objet Python appelera le destructeur de la bibliothèque <code>Vector</code> automatiquement. Par contre si on utilise la fonction <code>getUnitVector</code> il faut supprimer 
explicitement la structure afin d'éviter une fuite de mémoire.</p>

<pre>
<span>#!/usr/bin/python
# -*- coding: utf8 -*-</span>

import sys
import biblio
import time

def main(args):
        i=0
        print 'boucle de test pour le ramasse-miettes'
        print 'controlez l\'etat de la memoire'
        while(i<1000):
                <span># sans utiliser le constructeur</span>
                if i%2==0:v = biblio.getUnitVector()
                <span># en utilisant le constructeur</span>
                else:v = biblio.Vector()
                time.sleep(0.01)
                <span># on supprime explicitement le vecteur
                # si il a n’a pas été créé avec le 
                # constructeur, la propriété "thisown" 
                # donne cette information</span>
                if v.thisown==0:biblio.deleteVector(v)
                i=i+1
        print 'boucle terminee'

if __name__=="__main__":
        main(sys.argv)
</pre>

<h3>Remarques</h3>

<p>En utilisant ce script on constate que l'état de la mémoire est stable. Si la ligne <code>biblio.deleteVector</code> de suppression explicite est supprimée, on constate une augmentation rapide de l’utilisation mémoire qui ne sera pas rendue. Il y a donc une fuite mémoire.</p>

<p>Quand Python n’a plus de référence sur un objet le <i>Garbage Collector</i> supprime l’objet Python. Le destructeur de cet objet Python commande à la bibliothèque C/C++ la libération de la mémoire via le destructeur programmé en C.</p>

<p>On peut donc profiter pleinement du <i>Garbage Collector</i> de Python tant qu’on respecte la règle de ne
 pas commander la création d’une structure dans une fonction C/C++.</p>

</contenu>


   <zone>
       <h3>Liens connexes</h3>
      <ul>
         <li><a href="SWIG-Python.zip">Télécharger les fichiers d’exemples</a>.</li>
         <li><a href="http://www.python.org/">Le langage Python</a></li>
         <li><a href="http://www.swig.org/">SWIG</a></li>
      </ul>

       <dl>
       <dt>Auteur</dt>
       <dd>Batiste Bieler</dd>
       <dt>Licence</dt>
      <dd>Les exemples de code sont sous <a href="http://fr.wikipedia.org/wiki/LGPL">LGPL</a></dd>
      <dd>Vous pouvez distribuer librement l’ensemble de ces documents en respectant le droit d’auteur.</dd>
       </dl>
   </zone>
</document>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    		