Swig to wrap C Code
Last Updated :
27 Mar, 2019
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
# 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
{
# include "work.h"
%
}
{
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 :
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
Share your thoughts in the comments
Please Login to comment...