Open In App

Wrapping C/C++ for Python using SWIG – Set 1

There is no doubt that C is faster than Python then how do Python library like Numpy perform huge number crunching job so fast and efficiently? Actually, libraries like Numpy are not completely written in Python instead, some parts of the library are written in C which provides performance boost. After writing code in C, we wrap them in Python code which acts like an interface for those C codes. We can then call C functions using Python syntax where actual processing is done in C behind the scene and the result is returned back as Python object. In this article, we will see how to create Python wrapper for our C program on Linux systems using a software called SWIG.

What is SWIG



In a nutshell, SWIG is a compiler that takes C/C++ declarations and creates a wrapper needed to access those declarations from other languages like Python, Tcl, Ruby etc.
It normally required no changes in existing code and create an interface within a minute.

Reasons for creating wrapper



In many occasions we need wrappers, following are few of them –

Installing SWIG

For downloading SWIG directly from apt repository type following commands –

sudo apt-get update
sudo apt-get install swig

Writing Wrapper using SWIG

Consider this piece of C code, having two functions and one global variable –




/* 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);
}

Here is our header file gfg.h




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

First, we have to create a SWIG Interface file. This file contains ANSI C function prototypes and variable declaration. Here –




/* 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"
*/

Now we will create wrapper code using the command like $ swig -target_language interface_file.i

$ swig -python gfg.i

After executing this command a wrapper code with name “gfg_wrap.c” is created. This files contains a bloated version of our original C code with various error handling code etc. Another file “gfg.py” is generated which is the module we will import in our python script.

After this, we have to generate position-independent code which will be used in shared library by compiling “gfg_wrap.c” and “gfg.c” using the following command –

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

Replace python2.7 with your Python version. This will generate two object files
“gfg_wrap.o” and “gfg.o”. In above command –

Note: If you get error something like “… ‘Python.h’ file not found” then following might be possible causes –

To get ‘Python.h’ You must install Python-dev using following command –

$ sudo apt-get install python-dev

To find the correct path of ‘Python.h’ execute following command –

$ python-config --cflags

This will output something like this –


Now replace the path in compilation command with this one for python2.7 or change the version as python3.5 for Python 3.5.

Now, at last, we have to link generated objects files together to create a shared object which is analogous to dll files in windows. Use the following command, this will generate a “_gfg.so” shared object file –

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

Now we are ready to test out python wrapper by importing it. Make sure you are in directory having this wrapper file.

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

Here C variables are accessed as module.cvar.var_name.

Compiling and Linking using distutils

Instead of typing in commands and figuring out what compilation options are needed to compile files, we can automate this using distutils. Create a setup.py as below –




# 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])

Now write following commands to compile and install module –

$ python setup.py build_ext --inplace

It should look something like this on terminal –

Possible Alternatives

Obviously, SWIG is not the only way for creating wrappers, one can consider following alternatives based on their requirements –

In next article, we will see how to create wrapper for C++ code (OPP)

References


Article Tags :