4. Construire des extensions C et C++
*************************************

Une extension C pour CPython est une bibliothèque partagée (Un ".so"
sur Linux, un ".pyd" sur Windows), qui expose une *fonction
d'initialisation*.

Pour pouvoir être importée, la bibliothèque partagée doit pourvoir
être trouvée dans "PYTHONPATH", et doit porter le nom du module, avec
l'extension appropriée. En utilisant *distutils*, le nom est généré
automatiquement.

La fonction d'initialisation doit avoir le prototype :

PyObject *PyInit_modulename(void)

It returns either a fully initialized module, or a "PyModuleDef"
instance. See Initializing C modules for details.

Pour les modules dont les noms sont entièrement en ASCII, la fonction
doit être nommée "PyInit_<modulename>", dont "<modulename>" est
remplacé par le nom du module. En utilisant Multi-phase
initialization, il est possible d'utiliser des noms de modules
comptant des caractères non ASCII. Dans ce cas, le nom de la fonction
d'initialisation est "PyInitU_<modulename>", où "modulename" est
encodé avec l'encodage *punyencode* de Python, dont les tirets sont
remplacés par des tirets-bas. En Python ça donne :

   def initfunc_name(name):
       try:
           suffix = b'_' + name.encode('ascii')
       except UnicodeEncodeError:
           suffix = b'U_' + name.encode('punycode').replace(b'-', b'_')
       return b'PyInit' + suffix

Il est possible d'exporter plusieurs modules depuis une seule
bibliothèque partagée en définissant plusieurs fonctions
d'initialisation. Cependant pour les importer, un lien symbolique doit
être créé pour chacun, ou un *importer* personnalisé, puisque par
défaut seule la fonction correspondant au nom du fichier est cherchée.
Voir le chapitre *"Multiple modules in one library"* dans la **PEP
489** pour plus d'informations.


4.1. Construire les extensions C et C++ avec *distutils*
========================================================

Des modules d'extension peuvent être construits avec *distutils*, qui
est inclus dans Python. Puisque *distutils* gère aussi la création de
paquets binaires, les utilisateurs n'auront pas nécessairement besoin
ni d'un compilateur ni de *distutils* pour installer l'extension.

Un paquet *distutils* contient un script "setup.py". C'est un simple
fichier Python, ressemblant dans la plupart des cas à :

   from distutils.core import setup, Extension

   module1 = Extension('demo',
                       sources = ['demo.c'])

   setup (name = 'PackageName',
          version = '1.0',
          description = 'This is a demo package',
          ext_modules = [module1])

Avec ce "setup.py" et un fichier "demo.c", lancer

   python setup.py build

compilera "demo.c", et produira un module d'extension nommé "demo"
dans le dossier "build". En fonction du système, le fichier du module
peut se retrouver dans "build/lib.system", et son nom peut être
"demo.py" ou "demo.pyd".

Dans le fichier "setup.py", tout est exécuté en appelant la fonction
"setup". Elle prend un nombre variable d'arguments nommés, dont
l'exemple précédent n'utilise qu'une partie. L'exemple précise des
méta-informations pour construire les paquets, et définir le contenu
du paquet. Normalement un paquet contient des modules additionnels,
comme des modules sources, documentation, sous paquets, etc. Référez-
vous à la documentation de *distutils* dans Distribuer des modules
Python (Version historique) pour en apprendre plus sur les
fonctionnalités de *distutils*. Cette section n'explique que la
construction de modules d'extension.

Il est classique de pré-calculer les arguments à la fonction
"setup()", pour plus de lisibilité. Dans l'exemple ci-dessus,
l'argument "ext_modules" à "setup()" est une liste de modules
d'extension, chacun est une instance de la classe "Extension". Dans
l'exemple, l'instance définit une extension nommée "demo" construite
par la compilation d'un seul fichier source "demo.c".

Dans la plupart des cas, construire une extension est plus complexe à
cause des bibliothèques et définitions de préprocesseurs dont la
compilation pourrait dépendre. C'est ce qu'on remarque dans l'exemple
plus bas.

   from distutils.core import setup, Extension

   module1 = Extension('demo',
                       define_macros = [('MAJOR_VERSION', '1'),
                                        ('MINOR_VERSION', '0')],
                       include_dirs = ['/usr/local/include'],
                       libraries = ['tcl83'],
                       library_dirs = ['/usr/local/lib'],
                       sources = ['demo.c'])

   setup (name = 'PackageName',
          version = '1.0',
          description = 'This is a demo package',
          author = 'Martin v. Loewis',
          author_email = 'martin@v.loewis.de',
          url = 'https://docs.python.org/extending/building',
          long_description = '''
   This is really just a demo package.
   ''',
          ext_modules = [module1])

Dans cet exemple, la fonction "setup()" est appelée avec quelques
autres méta-informations, ce qui est recommandé pour distribuer des
paquets. En ce qui concerne l'extension, sont définis quelques macros
préprocesseur, dossiers pour les en-têtes et bibliothèques. En
fonction du compilateur, *distutils* peut donner ces informations de
manière différente. Par exemple, sur Unix, ça peut ressembler aux
commandes

   gcc -DNDEBUG -g -O3 -Wall -Wstrict-prototypes -fPIC -DMAJOR_VERSION=1 -DMINOR_VERSION=0 -I/usr/local/include -I/usr/local/include/python2.2 -c demo.c -o build/temp.linux-i686-2.2/demo.o

   gcc -shared build/temp.linux-i686-2.2/demo.o -L/usr/local/lib -ltcl83 -o build/lib.linux-i686-2.2/demo.so

Ces lignes ne sont qu'à titre d'exemple, les utilisateurs de
*distutils* doivent avoir confiance en *distutils* qui fera les appels
correctement.


4.2. Distribuer vos modules d'extension
=======================================

Lorsqu'une extension a été construite avec succès, il existe trois
moyens de l'utiliser.

Typiquement, les utilisateurs vont vouloir installer le module, ils le
font en exécutant

   python setup.py install

Les mainteneurs de modules voudront produire des paquets source, pour
ce faire ils exécuteront

   python setup.py sdist

Dans certains cas, des fichiers supplémentaires doivent être inclus
dans une distribution source : c'est possible via un fichier
"MANIFEST.in", c.f. Spécifier les fichiers à distribuer.

Si la distribution source a été construite avec succès, les
mainteneurs peuvent aussi créer une distribution binaire. En fonction
de la plateforme, une des commandes suivantes peut être utilisée.

   python setup.py bdist_rpm
   python setup.py bdist_dumb
