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

Cette page explique rapidement comment créer un module d’extension
Windows pour Python en utilisant Microsoft Visual C++, et donne plus
d’informations contextuelles sur son fonctionnement. Le texte
explicatif est utile tant pour le développeur Windows qui apprend à
construire des extensions Python que pour le développeur Unix
souhaitant produire des logiciels pouvant être construits sur Unix et
Windows.

Les auteurs de modules sont invités à utiliser l’approche *distutils*
pour construire des modules d’extension, au lieu de celle décrite dans
cette section. Vous aurez toujours besoin du compilateur C utilisé
pour construire Python ; typiquement Microsoft Visual C++.

Note: Cette page mentionne plusieurs noms de fichiers comprenant un
  numéro de version Python encodé. Ces noms de fichiers sont
  construits sous le format de version "XY" ; en pratique, "'X'"
  représente le numéro de version majeure et "'Y'" représente le
  numéro de version mineure de la version Python avec laquelle vous
  travaillez. Par exemple, si vous utilisez Python 2.2.1, "XY"
  correspond à "22".


4.1. Une approche « recette de cuisine »
========================================

Il y a deux approches lorsque l’on construit des modules d’extension
sur Windows, tout comme sur Unix : utiliser le paquet "distutils" pour
contrôler le processus de construction, ou faire les choses
manuellement. L’approche *distutils* fonctionne bien pour la plupart
des extensions ; la documentation pour utiliser "distutils" pour
construire et empaqueter les modules d’extension est disponible dans
Distribuer des modules Python (Version historique). Si vous considérez
que vous avez réellement besoin de faire les choses manuellement, il
pourrait être enrichissant d’étudier le fichier de projet winsound
pour le module de la bibliothèque standard.


4.2. Différences entre Unix et Windows
======================================

Unix et Windows utilisent des paradigmes complètement différents pour
le chargement du code pendant l’exécution. Avant d’essayer de
construire un module qui puisse être chargé dynamiquement, soyez
conscient du mode de fonctionnement du système.

Sur Unix, un fichier objet partagé (".so") contient du code servant au
programme, ainsi que les noms des fonctions et les données que l’on
s’attend  à trouver dans le programme. Quand le fichier est attaché au
programme, toutes les références à ces fonctions et données dans le
code du fichier sont modifiées pour pointer vers les localisations
actuelles dans le programme où sont désormais placées les fonctions et
données dans la mémoire. C’est tout simplement une opération de
liaison.

Sur Windows, un fichier bibliothèque de liens dynamiques (".dll") n’a
pas de références paresseuses. A la place, un accès aux fonctions ou
données passe par une table de conversion. Cela est fait pour que le
code DLL ne doive pas être réarrangé à l’exécution pour renvoyer à la
mémoire du programme ; à la place, le code utilise déjà la table de
conversion DLL, et cette table est modifiée à l’exécution pour pointer
vers les fonctions et données.

Sur Unix, il n’y a qu’un type de bibliothèque de fichier (".a") qui
contient du code venant de plusieurs fichiers objets (".o"). Durant
l’étape de liaison pour créer un fichier objet partagé (".so"), le
lieur peut informer qu’il ne sait pas où un identificateur est défini.
Le lieur le cherchera dans les fichiers objet dans les bibliothèques ;
s’il le trouve, il inclura tout le code provenant de ce fichier objet.

Sur Windows, il y a deux types de bibliothèques, une bibliothèque
statique et une bibliothèque d’import (toutes deux appelées ".lib").
Une bibliothèque statique est comme un fichier Unix ".a" ; elle
contient du code pouvant être inclus si nécessaire. Une bibliothèque
d’import est uniquement utilisée pour rassurer le lieur qu’un certain
identificateur est légal, et sera présent dans le programme quand la
DLL est chargé. Comme ça le lieur utilise les informations provenant
de la bibliothèque d’import pour construire la table de conversion
pour utiliser les identificateurs qui ne sont pas inclus dans la DLL.
Quand une application ou une DLL est lié, une bibliothèque d’import
peut être générée, qui devra être utilisée pour tous les futures DLL
dépendantes aux symboles provenant de l’application ou de la DLL.

Supposons que vous construisez deux modules de chargement dynamiques,
B et C, qui ne devraient pas partager un autre bloc de code avec A.
Sur Unix, vous ne transmettrez pas "A.a" au lieur pour "B.so" et
"C.so" ; cela le ferait être inclus deux fois, pour que B et C aient
chacun leur propre copie. Sur Windows, construire "A.dll" construira
aussi "A.lib". Vous transmettez "A.lib" au lieur pour B et C. "A.lib"
ne contient pas de code ; il contient uniquement des informations qui
seront utilisées lors de l’exécution pour accéder au code de A.

Sur Windows, utiliser une bibliothèque d’import est comme utiliser
"import spam"; cela vous donne accès aux noms des spams, mais ne crée
par de copie séparée. Sur Unix, se lier à une bibliothèque est plus
comme "from spam import *" ; cela créé une copie séparée.


4.3. Utiliser les DLL en pratique
=================================

Le Python de Windows est construit en Microsoft Visual C++ ; utiliser
d’autres compilateurs pourrait fonctionner, ou pas (cependant Borland
a l’air de fonctionner). Le reste de cette section est spécifique à
MSVC++.

Lorsque vous créez des DLL sur Windows, vous devez transmettre
"pythonXY.lib" au lieur. Pour construire deux DLL, spam et ni (qui
utilisent des fonctions C trouvées dans spam), vous pouvez utiliser
ces commandes :

   cl /LD /I/python/include spam.c ../libs/pythonXY.lib
   cl /LD /I/python/include ni.c spam.lib ../libs/pythonXY.lib

La première commande a créé trois fichiers : "spam.obj", "spam.dll" et
"spam.lib". "Spam.dll" ne contient pas de fonctions Python (telles que
"PyArg_ParseTuple()"), mais il sait comment trouver le code Python
grâce à "pythonXY.lib".

La seconde commande a créé "ni.dll" (et ".obj" et ".lib"), qui sait
comment trouver les fonctions nécessaires dans spam, ainsi qu’à partir
de l’exécutable Python.

Chaque identificateur n’est pas exporté vers la table de conversion.
Si vous voulez que tout autre module (y compris Python) soit capable
de voir vos identificateurs, vous devez préciser
"_declspec(dllexport)", comme dans "void _declspec(dllexport)
initspam(void)" ou "PyObject _declspec(dllexport)
*NiGetSpamData(void)".

Developer Studio apportera beaucoup de bibliothèques d’import dont
vous n’avez pas vraiment besoin, augmentant d’environ 100ko votre
exécutable. Pour s’en débarrasser, allez dans les Paramètres du
Projet, onglet Lien, pour préciser *ignorer les bibliothèques par
défaut*. Et la "msvcrtxx.lib" correcte à la liste des bibliothèques.
