Deslizar para envolver el código C

Requisito previo: Usar códigos C en Python , Envolver C/C++ para Python usando SWIG

Supongamos que hemos proporcionado un código C y es necesario acceder a él como un módulo de extensión C. Entonces, para la tarea dada, se usa Swig Wrapper Generator.

Swig funciona analizando los archivos de encabezado C y creando automáticamente el código de extensión. Primero se necesita el archivo de encabezado C para usar Swig. Proporcione un ejemplo de archivo de encabezado C en el código a continuación.

Código #1:work.h

// work.h
  
# include <math.h>
  
extern int gcd(int, int);
extern int divide(int a, int b, int * remainder);
extern double avg(double * a, int n);
  
typedef struct Point
{
    double x, y;
} Point;
  
extern double distance(Point * p1, Point * p2);

 
Después de tener el archivo de encabezado, el siguiente paso es escribir un archivo de «interfaz» de Swig. Por convención, estos archivos tienen un sufijo .i y pueden tener un aspecto similar al siguiente.

Código #2: work.i

// work.i - Swig interface % module work %
{
# include "work.h"
    %
}
// Customizations % extend Point
{
    // Constructor for Point objects 
    Point(double x, double y)
    {
        Point * p = (Point *) malloc(sizeof(Point));
        p->x = x;
        p->y = y;
        return p;
    };
};

 
Código #3: Mapeo

// Map int * remainder as an output argument
%include typemaps.i 
%apply int * OUTPUT { int * remainder };
   
// Map the argument pattern (double * a, int n) to arrays 
%typemap(in) (double * a, int n)(Py_buffer view)
{
    view.obj = NULL;
    if (PyObject_GetBuffer($input, &view, 
                           PyBUF_ANY_CONTIGUOUS | PyBUF_FORMAT) == -1)
    {
        SWIG_fail;
    }
    if (strcmp(view.format, "d") != 0)
    {
        PyErr_SetString(PyExc_TypeError, 
                        "Expected an array of doubles");
        SWIG_fail;
    }
    $1 = (double *) view.buf;
    $2 = view.len / sizeof(double);
}
   
% typemap(freearg) (double * a, int n)
{
    if (view$argnum.obj)
    {
        PyBuffer_Release(&view$argnum);
    }
}

 
Una vez que el archivo de interfaz está listo, Swig se invoca como una herramienta de línea de comandos

Código #4:

bash % swig -python -py3 work.i
bash %

 
La salida de swig son dos archivos, work_wrap.cy work.py. El archivo work.py es lo que importan los usuarios y el archivo work_wrap.c es un código C que debe compilarse en un módulo de soporte llamado _work. Se realiza utilizando las mismas técnicas que para los módulos de extensión normales. Por ejemplo, crear un setup.pyarchivo como se muestra en el siguiente código:

Código #5:

# setup.py
from distutils.core import setup, Extension
setup(name='sample', 
      py_modules=['sample.py'],
      ext_modules=[ Extension(
              '_sample', ['sample_wrap.c'], 
              include_dirs = [], 
              define_macros = [],
              undef_macros = [],
              library_dirs = [],
              libraries = ['sample']
              ) ] )

 
Código # 6: Compile y pruebe, ejecute python3 en setup.py

bash % python3 setup.py build_ext --inplace
running build_ext
building '_sample' extension
  
gcc -fno-strict-aliasing -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes
-I/usr/local/include/python3.3m -c work_wrap.c
-o build/temp.macosx-10.6-x86_64-3.3/work_wrap.o
  
work_wrap.c: In function ‘SWIG_InitializeModule’:
  
work_wrap.c:3589: warning: statement with no effect
  
gcc -bundle -undefined dynamic_lookup build/temp.macosx-10.6-x86_64-3.3/work.o
  
build/temp.macosx-10.6-x86_64-3.3/work_wrap.o -o _work.so -lwork
bash %

 
Después de realizar todas las tareas, podemos usar el módulo de extensión C de una manera muy fácil.

Código #7:

import work
print ("GCD : ", work.gcd(12,8))
  
print ("\nDivision : ", work.divide(42,8))
  
pt1 = work.Point(2,3)
pt2 = work.Point(4,5)
  
print ("\nDistance between pt1 and pt2 : ", 
       work.distance(pt1,pt2))
  
  
print ("\nx co-ordinate of pt1 : ", pt1.x)
print ("\ny co-ordinate of pt1 : ", pt1.x)
  
  
import array
ar = array.array('d',[2, 4, 6])
print ("\nAverage : ", work.avg(arr))

Producción :

GCD : 4

Divide : [5, 2]

Distance between pt1 and pt2 : 2.8284271247461903

Distance between pt1 and pt2 : 2.0

Distance between pt1 and pt2 : 3.0

Average : 4.0

Publicación traducida automáticamente

Artículo escrito por manikachandna97 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *