Swig to wrap C Code

Suppose we gave C code and we want to access it as a C plugin. So, for this task we use the Swig Wrapper Generator.

Swig works by parsing C header files and automatically generating the extension code. The C-header file is required primarily to use Swig. Give an example of a C header file in the code below.

Code # 1: work.h

// work.h

 
# include & lt; math.h & gt; 

 

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 getting the header file, the next step is — write a Swig interface file. By convention, these files are suffixed .i and may look something like this:

Code # 2: work.i

// work.i - Swig interface% module work%
{
# include" work.h "

  %

}
//% extension settings Point
{

// Constructor for point objects

Point ( double x, double y)

  {

  Point * p = (Point *) malloc ( sizeof (Point)); 

p- & gt; x = x; 

p- & gt; 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 , & amp; 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 (& amp; view $ argnum); 

}

}

Once the interface file is ready, Swig is called as command line tool

Code # 4:

bash % swig -python -py3 work.i

bash %

Output swig — these are two files — work_wrap.c and work.py File work.py — this is what users import, and the file work_wrap.c — this is C code that needs to be compiled into a helper module named _work . This is done using the same techniques as for regular plugins. 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 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 completing all the tasks, we can m use the C plugin in a very simple way.

Code # 7:

import work

print ( "GCD:" , work.gcd ( 12 , 8 ))

 

print ( "Division:" , work.divide ( 42 , 8 ))

  

pt1 = work.Point ( 2 , 3 )

pt2 = work.Point ( 4 , 5 )

 

print ( "Distance between pt1 and pt2:"

  work.distance (pt1, pt2))

  

 

print ( "x co-ordinate of pt1:" , pt1.x)

print ( "y co-ordinate o f pt1: " , pt1.x)

  

 

import array

ar = array.array ( `d` , [ 2 , 4 , 6 ] )

print ( "Average:" , 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