Envolviendo C/C++ para Python usando SWIG – Conjunto 1

No hay duda de que C es más rápido que Python, entonces, ¿cómo la biblioteca de Python como Numpy realiza un gran trabajo de procesamiento de números de manera tan rápida y eficiente? En realidad, las bibliotecas como Numpy no están completamente escritas en Python, sino que algunas partes de la biblioteca están escritas en C, lo que proporciona un aumento del rendimiento. Después de escribir el código en C, lo envolvemos en código Python que actúa como una interfaz para esos códigos C. Luego podemos llamar a las funciones de C usando la sintaxis de Python donde el procesamiento real se realiza en C detrás de escena y el resultado se devuelve como un objeto de Python. En este artículo, veremos cómo crear un envoltorio de Python para nuestro programa C en sistemas Linux usando un software llamado SWIG .

¿Qué es SWIG?

En pocas palabras, SWIG es un compilador que toma declaraciones de C/C++ y crea un contenedor necesario para acceder a esas declaraciones de otros lenguajes como Python, Tcl, Ruby, etc.
Normalmente no requiere cambios en el código existente y crea una interfaz en un minuto.

Razones para crear un contenedor

En muchas ocasiones necesitamos envoltorios, los siguientes son algunos de ellos:

  • Creación de una interfaz interpretada para programas C existentes.
  • Creación de módulos C de alto rendimiento para lenguajes de secuencias de comandos
  • Es una gran molestia probar programas enormes en C, por lo que escribimos contenedores en algunos lenguajes de secuencias de comandos como Python, donde es muy fácil escribir pruebas. etc.

Instalación de SWIG

Para descargar SWIG directamente desde el repositorio apt, escriba los siguientes comandos:

sudo apt-get update
sudo apt-get install swig

Envoltura de escritura usando SWIG

Considere esta pieza de código C, que tiene dos funciones y una variable global:

/* file : gfg.c */
  
#include <stdio.h>
#include <math.h>
  
//our header file
#include "gfg.h"
#define ll long long
  
double myvar = 3.4;
  
// calculate factorial
ll int fact(ll int n)
{
    if(n <= 1)
        return 1;
    else
        return (n * fact(n-1));
}
  
//find mod
int my_mod(int n, int m)
{
  return(n % m);
}

Aquí está nuestro archivo de encabezado gfg.h

long long int fact(long long int n);
int my_mod(int n, int m);

Primero, tenemos que crear un archivo de interfaz SWIG . Este archivo contiene prototipos de funciones ANSI C y declaración de variables. Aquí –

  • La directiva %module especifica el nombre del módulo que usaremos en Python.
  • El bloque %{ .. % } proporciona una ubicación para insertar código adicional, como archivos de encabezado C o declaración C adicional en el código contenedor generado.
  • La directiva %include nos permite incluir archivos adicionales como archivos de encabezado.
/* file : gfg.i */
  
/* name of module to use*/
%module gfg
%{
    /* Every thing in this file is being copied in 
     wrapper file. We include the C header file necessary
     to compile the interface */
    #include "gfg.h"
  
    /* variable declaration*/
    double myvar;
%}
  
/* explicitly list functions and variables to be interfaced */
double myvar;
long long int fact(long long int n1);
int my_mod(int m, int n);
  
/* or if we want to interface all functions then we can simply
   include header file like this - 
   %include "gfg.h"
*/

Ahora crearemos un código contenedor usando el comando como $swig -target_language interface_file.i

$ swig -python gfg.i

Después de ejecutar este comando, se crea un código contenedor con el nombre «gfg_wrap.c» . Estos archivos contienen una versión ampliada de nuestro código C original con varios códigos de manejo de errores, etc. Se genera otro archivo «gfg.py» , que es el módulo que importaremos en nuestro script de python.

Después de esto, tenemos que generar un código independiente de la posición que se usará en la biblioteca compartida al compilar «gfg_wrap.c» y «gfg.c» usando el siguiente comando:

$ gcc -c -fpic gfg_wrap.c gfg.c -I/use/include/python2.7

Reemplace python2.7 con su versión de Python. Esto generará dos archivos de objeto
«gfg_wrap.o» y «gfg.o» . En el comando anterior –

  • -fpic genera código independiente de la posición (PIC) adecuado para usar en una biblioteca compartida, si es compatible con la máquina de destino. Dicho código accede a todas las direcciones constantes a través de una tabla de compensación global (GOT)

Nota: Si recibe un error similar a «… No se encontró el archivo ‘Python.h'» , las siguientes pueden ser las posibles causas:

  • Es posible que no tenga el archivo ‘Python.h’ o
  • Está proporcionando una ubicación incorrecta del archivo ‘Python.h’ al compilador

Para obtener ‘Python.h’, debe instalar Python-dev usando el siguiente comando:

$ sudo apt-get install python-dev

Para encontrar la ruta correcta de ‘Python.h’, ejecute el siguiente comando:

$ python-config --cflags

Esto generará algo como esto:

ahora reemplace la ruta en el comando de compilación con esta para python2.7 o cambie la versión como python3.5 para Python 3.5.

Ahora, por fin, tenemos que vincular los archivos de objetos generados para crear un objeto compartido que sea análogo a los archivos dll en Windows. Use el siguiente comando, esto generará un archivo de objeto compartido «_gfg.so» :

$ gcc -shared gfg.o gfg_wrap.o -o _gfg.so

Ahora estamos listos para probar el envoltorio de python importándolo. Asegúrese de estar en el directorio que tiene este archivo contenedor.

>>> import gfg
>>> res = fact(5)
>>> res
120
>>> res = my_mod(5,2)
>>> res
1
>>> gfg.cvar.myvar
3.4

Aquí se accede a las variables C como module.cvar.var_name .

Compilación y enlace usando distutils

En lugar de escribir comandos y averiguar qué opciones de compilación se necesitan para compilar archivos, podemos automatizar esto usando distutils. Cree un setup.py como se muestra a continuación:

# File : setup.py
  
from distutils.core import setup, Extension
#name of module
name  = "gfg"
  
#version of module
version = "1.0"
  
# specify the name of the extension and source files
# required to compile this
ext_modules = Extension(name='_gfg',sources=["gfg.i","gfg.c"])
  
setup(name=name,
      version=version,
      ext_modules=[ext_modules])

Ahora escriba los siguientes comandos para compilar e instalar el módulo:

$ python setup.py build_ext --inplace

Debería verse algo como esto en la terminal:
salida setyp.py

Alternativas posibles

Obviamente, SWIG no es la única forma de crear envoltorios, se pueden considerar las siguientes alternativas según sus requisitos:

En el próximo artículo, veremos cómo crear un contenedor para código C++ (OPP)

Referencias

Este artículo es una contribución de Atul Kumar . Si le gusta GeeksforGeeks y le gustaría contribuir, también puede escribir un artículo usando contribuya.geeksforgeeks.org o envíe su artículo por correo a contribuya@geeksforgeeks.org. Vea su artículo que aparece en la página principal de GeeksforGeeks y ayude a otros Geeks.

Escriba comentarios si encuentra algo incorrecto o si desea compartir más información sobre el tema tratado anteriormente.

Publicación traducida automáticamente

Artículo escrito por GeeksforGeeks-1 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 *