Open In App

Swig to wrap C Code

Last Updated : 27 Mar, 2019
Improve
Improve
Like Article
Like
Save
Share
Report

Prerequisite: Using C codes in Python, Wrapping C/C++ for Python using SWIG

Suppose we have given a C code and it needs to be accessed as a C extension module. So, for the given task – Swig Wrapper Generator is used.

Swig operates by parsing C header files and automatically creating extension code. C-header file is needed first, to use Swig. Give an example of C-header file in the code below.

Code #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);


 
After having the header file, the next step is to write a Swig “interface” file. By convention, these files have a .i suffix and might look similar to the following.

Code #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;
    };
};


 
Code #3 : Mapping




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


 
Once the interface file is ready, Swig is invoked as a command-line tool

Code #4 :




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


 
The output of swig is two files – work_wrap.c and work.py. work.py file is what users import and the work_wrap.c file is C code that needs to be compiled into a supporting module called _work. It is performed using the same techniques as for normal extension modules. For example, creating a setup.py file as shown in the code below –

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


 
Code #6 : Compile and test, run python3 on the 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 %


 
After performing all the tasks, we can use the C extension module in a very easy way.

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


Output :

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


Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads