I. Introduction▲
Ce tutoriel est la suite d'un premier sujet intitulé « Introduction au Cython » disponible ici. L'objectif est de montrer quelques utilisations de l'appel de code Python au sein d'un code écrit en C. Ce tutoriel présente de façon plus détaillée certaines fonctionnalités avancées.
Nous allons écrire un exemple simple incorporant du code Python dans du code C et créant une application exécutable pouvant être lancée en incluant l'interpréteur Python, de sorte qu'il ne soit pas nécessaire d'appeler Python.
L'installation de Python 3 et d'un compilateur C seront nécessaires pour compiler le code C en exécutable, comme indiqué précédemment. Sans compilateur C, vous ne pourrez pas essayer les exemples présentés dans ce document.
Notez que l'article original a été écrit sur un environnement Mac, de sorte que les exemples peuvent ne pas fonctionner comme prévu.
NDLR L'auteur précise qu'il est possible de le contacter en cas de problèmes sur un environnement Windows.
II. Incorporer et compiler du code Python▲
Nous allons en premier lieu examiner le fonctionnement de l’API d’initialisation Python et du modèle de lien de chargement lors de l’incorporation de code Python dans du C ou C++.
Pour incorporer du code Python, nous allons simplement utiliser ce squelette :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
#include <Python.h>
// Inclure l'en-tête de votre module ici
int
main (
int
argc, char
**
argv) {
// Initialisation
Py_SetProgramName (
argv [0
]);
Py_Initialize (
);
//PyInit_yourfilename(); // Initialisation pour Python 3
// Insérer la logique du code ici
Py_Finalize
(
);
return
0
;
}
Il faut s'assurer que l'inclusion de Python.h soit la première dans vos fichiers C/C++, car Python utilise lui-même de nombreux fichiers d'en-tête qui activent ou désactivent des paramètres.
Il y a ensuite une fonction principale très simple qui contient toute la logique que vous souhaitez ajouter. Il n'est, bien entendu, pas nécessaire d'écrire tout le code dans cette fonction. Vous pouvez découper le code en plusieurs fonctions et ainsi respecter de meilleures pratiques de codage,
Et comme vous pouvez le voir, il y a trois lignes d'initialisation. Les deux premières parlent d'elles-mêmes et sont identiques à chaque fois, mais la troisième doit être changée pour chaque module que vous souhaitez utiliser. Dans l'exemple ci-dessus, il est commenté et porte un nom « amusant », mais un exemple plus concret sera montré plus tard et vous permettra de mieux comprendre comment cette ligne devrait fonctionner.
Il y a deux manières d'ajouter des fonctionnalités Python au code C. La première, appelée approche « pythonique », consiste à partager des objets Python. Cette approche est fortement conseillée lorsque votre base de code est principalement du code Python. Dans ce cas, vous aurez un module natif qui appelle le code natif. L'autre solution consiste à intégrer pleinement Python et le code Python dans votre application native. Cela signifie que dans ce cas, nous avons déjà l'environnement d'exécution de Python. Dans l'autre solution, nous devions exécuter l'interpréteur Python qui appelait notre code Cython (c'est ce qui a été fait dans l'article précédent).
Maintenant que nous savons comment lier le code Python à exécuter, examinons de plus près les exemples de code suivants :
2.
3.
4.
5.
cdef void
cython_function
(
):
print
(
'
Je suis dans une fonction Cython
'
)
cdef public void
cython_function
(
):
print
(
'
Je suis dans une fonction Cython
'
)
L'unique différence est le mot clé « public ». Mais cela fait une différence très significative. Si nous compilons les deux avec cythonize nous obtenons le résultat suivant :
Comme vous pouvez le constater, le code contenant le mot clé public a également l'extension « .h » à côté de son fichier « .c ». Ce fichier d’en-tête contient une ligne qui déclare une fonction initcythonfile_public (void) si la version de Python est inférieure à 2. Pour Python 3, il n’y a rien de plus à faire. Pour Python 2, vous devez appeler cette méthode d’initialisation dans le code standard comme indiqué au début du chapitre avant de faire d'autres appels.
Créons maintenant notre fichier C qui appellera la fonction définie précédemment :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
#include <Python.h>
#include "cythonfile_public.h"
int
main (
int
argc, char
**
argv) {
Py_SetProgramName (
argv [0
]);
Py_Initialize (
);
PyInit_cythonfile_public
(
);
// Insérer la logique du code ici
cython_function (
);
Py_Finalize
(
);
return
0
;
}
La compilation de l'exemple se fait avec les étapes suivantes :
2.
3.
4.
cython -3 cythonfile_public.pyx
gcc -g -fpic -c cythonfile_public.c -o cythonfile_public.o `python3.6-config --includes`
gcc -g -fpic -c cythontest.c -o cythontest.o `python3.6-config --includes`
gcc -g -o cythontest cythonfile_public.o cythontest.o `python3.6-config --libs` -L /Library/Frameworks/Python.framework/Versions/3.6/lib
La première commande compile le fichier Cython cythonfile_public.pyx en un fichier « .h » et un fichier « .c ». L'indicateur -3 indique au compilateur Cython que le code Python a été écrit avec la syntaxe Python 3 et qu'un fichier C basé sur Python 3 sera créé.
La deuxième commande compile ce fichier C, la troisième commande compile le fichier cythontest.c et la quatrième commande lie les deux fichiers « .o » compilés à un exécutable appelé « cythontest ».
Les paramètres appliqués, tels que python3.6-config --includes, indiquent l’emplacement des bibliothèques de l’installation Python à inclure dans le processus de compilation. Le nom python3.6-config inclut le numéro de version de l'installation Python dans le cas où vous en avez plusieurs, et que la valeur par défaut n'est pas celle-ci. Vous pouvez vérifier si python-config est suffisant pour votre ordinateur en exécutant cette commande :
2.
ComputerName$ python3.6-config --includes
-I/Library/Frameworks/Python.framework/Versions/3.6/include/python3.6m -I/Library/Frameworks/Python.framework/Versions/3.6/include/python3.6m
Vous pouvez voir le numéro de version dans la sortie. S'il est supérieur à 3, vous pouvez continuer. Si c'est quelque chose comme ça :
GHajba$
python-config --includes
-I/System/Library/Frameworks/Python.framework/Versions/2
.7
/include/python2.7
-I/System/Library/Frameworks/Python.framework/Versions/2
.7
/include/python2.7
vous devez ajuster alors votre configuration pour qu'elle pointe vers une installation Python 3.
Le bloc de commandes de compilation présenté précédemment peut également être inclus dans un Makefile si vous ne voulez pas tout écrire à chaque fois.
Nous pouvons exécuter l’exemple d’application en exécutant le fichier exécutable créé précédemment. Cela ressemblera à ceci :
2.
ComputerName$ ./cythontest
Je suis dans une fonction Cython
Comme vous pouvez le constater, les liens entre le code Cython et le code C fonctionnent correctement.
III. Conclusion▲
Dans cet article, nous avons utilisé du code Python à partir de code C avec le module Cython. Nous avons vu comment nous pouvons compiler différentes parties ensemble pour avoir un exécutable natif basé sur un code C qui appelle une fonction dans un module Cython.