Interfaçage avec les bibliothèques C/C++

C Foreign Function Interface

CFFI fournit un mécanisme simple à utiliser pour l’interfaçage avec C à la fois depuis CPython et PyPy. Il prend en charge deux modes: un mode de compatibilité ABI inline (exemple ci-dessous), ce qui vous permet de charger et exécuter dynamiquement des fonctions depuis des modules exécutables (exposant essentiellement les mêmes fonctionnalités que LoadLibrary ou dlopen), et un mode API, qui vous permet de construire des modules d’extension C.

Interaction avec ABI (Application Binary Interface)

1
2
3
4
5
6
7
from cffi import FFI
ffi = FFI()
ffi.cdef("size_t strlen(const char*);")
clib = ffi.dlopen(None)
length = clib.strlen("String to be evaluated.")
# prints: 23
print("{}".format(length))

ctypes

ctypes est la bibliothèque de fait pour l’interfaçage avec C/C ++ depuis CPython, et il fournit non seulement un accès complet à l’interface C native de la plupart des principaux systèmes d’exploitation (par exemple, kernel32 sur Windows, ou libc sur *nix), mais fournit également le support pour le chargement et l’interfaçage avec des bibliothèques dynamiques, telles que les DLL ou les objets partagés (Shared Objects ou SO) lors de l’exécution. Il embarque avec lui toute une série de types pour interagir avec les APIs système, et vous permet de définir assez facilement vos propres types complexes, tels que les structs et les unions, et vous permet de modifier des choses telles que le padding et l’alignement, si nécessaire. Il peut être un peu retors à utiliser, mais conjointement avec le module struct, vous recevez essentiellement un contrôle complet sur la façon dont vos types de données sont traduits en quelque chose d’utilisable par une méthode C(++) pure.

Équivalents de struct

MyStruct.h

1
2
3
4
struct my_struct {
    int a;
    int b;
};

MyStruct.py

1
2
3
4
import ctypes
class my_struct(ctypes.Structure):
    _fields_ = [("a", c_int),
                ("b", c_int)]

SWIG

SWIG, bien que pas strictement orienté Python (il prend en charge un grand nombre de langages de scripting), est un outil pour générer des bindings pour les langages interprétés à partir des fichiers d’en-tête C/C++. Il est extrêmement simple de l’utiliser: le consommateur doit simplement définir un fichier d’interface (détaillée dans le tutoriel et la documentation), inclure les en-têtes C/C ++ nécessaires, et exécuter l’outil de build sur eux. Alors qu’il a quelques limites, (il semble actuellement avoir des problèmes avec un petit sous-ensemble de nouvelles fonctionnalités C++, et avoir du code avec des templates partout pour travailler peut être un peu verbeux), il est très puissant et expose beaucoup de fonctionnalités pour Python avec peu d’effort. En outre, vous pouvez facilement étendre les bindings SWIG créés (dans le fichier d’interface) pour surcharger les opérateurs et les méthodes intégrées, recaster les exceptions C++ pour être capturables par Python, etc.

Exemple: Overloading __repr__

MyClass.h

1
2
3
4
5
6
7
#include <string>
class MyClass {
private:
    std::string name;
public:
    std::string getName();
};

myclass.i

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
%include "string.i"

%module myclass
%{
#include <string>
#include "MyClass.h"
%}

%extend MyClass {
    std::string __repr__()
    {
        return $self->getName();
    }
}

%include "MyClass.h"

Boost.Python

Boost.Python nécessite un peu plus de travail manuel pour exposer la fonctionnalité d’un objet C++, mais il est capable de fournir tous les fonctionnalités que SWIG fournit, et quelques unes pour inclure des wrappers pour accéder à des objets Python en C ++, en extrayant des objets wrappés SWIG-, et même permettant d’incorporer des morceaux de Python dans votre code C++.