1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450
|
<!--startcut ==============================================-->
<!-- *** BEGIN HTML header *** -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML><HEAD>
<title>Using SWIG to interface scripting languages with C/C++ LG #49</title>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000FF" VLINK="#0000AF"
ALINK="#FF0000">
<!-- *** END HTML header *** -->
<!-- *** BEGIN navbar *** -->
<A HREF="lg_toc49.html"><IMG ALT="[ Table of Contents ]"
SRC="../gx/indexnew.gif" WIDTH=163 HEIGHT=60 ALIGN=bottom ></A>
<A HREF="../lg_frontpage.html"><IMG ALT="[ Front Page ]"
SRC="../gx/homenew.gif" WIDTH=163 HEIGHT=60 ALIGN=bottom></A>
<A HREF="orr.html"><IMG ALT="[ Prev ]" SRC="../gx/back2.gif" WIDTH=41 HEIGHT=60 ALIGN=bottom></A>
<A HREF="../lg_faq.html"><IMG ALT="[ Linux Gazette FAQ ]"
SRC="./../gx/dennis/faq.gif"WIDTH=163 HEIGHT=60 ALIGN=bottom></A>
<A HREF="silva.html"><IMG ALT="[ Next ]" SRC="../gx/fwd.gif" WIDTH=41 HEIGHT=60 ALIGN=bottom ></A>
<!-- *** END navbar *** -->
<!--endcut ============================================================-->
<H4>
"Linux Gazette...<I>making Linux just a little more fun!</I>"
</H4>
<P> <HR> <P>
<!--===================================================================-->
<center>
<H1><font color="maroon">Using SWIG to interface scripting languages with C/C++</font></H1>
<H4>By <a href="mailto:iclabs@vsnl.com">Pramode C.E and Gopakumar C.E</a></H4>
</center>
<P> <HR> <P>
<!-- END header -->
<H2> Introduction </H2>
<p>
Scripting languages like Perl, Python and Tcl are receiving a lot of attention nowadays - mainly because
these languages facilitate Rapid Application Development and Prototyping. It has been shown
time and again that using a language like Python cuts down development time drastically - with the added
advantage that you get highly robust and flexible code. But there are situations in which a
pure scripting approach does not work, typical examples being scientific applications which require high
speed math and graphics routines or applications which need to control and coordinate hardware devices
on a real time basis. What we need is a mixed-language paradigm in which traditional systems languages
like C/C++ do the 'dirty' low-level work while the Scripting language acts as the overall supervisor. This
article focuses on using an excellent program called the Simplified Wrapper and Interface Generator (SWIG)
to integrate code written in C/C++ with the popular scripting language Python. The code fragments in this article have
been tested on a Red Hat Linux (5.2) machine running Python ver 1.5.1.
<H2> Getting and Installing SWIG </H2>
<p>
SWIG is being developed by Dave Beazley and can be downloaded from <a href="http://www.swig.org">www.swig.org</a>.
Installation is straightforward, just run ./configure and then make. Currently, SWIG supports Perl, Python,
Tcl and FSF Guile.
<H2> A simple example </H2>
<p>
Let us say we have a C function called add(a, b) which returns the sum of two numbers passed to it as
arguments. We will see how the add function can be made Python-callable.
We will create a file called arith.c which contains the following code:
<PRE>
int add(int a, int b)
{
return a+b;
}
</PRE>
Let us now execute the following command:
<PRE>
<b>swig -python -module arith arith.c</b>
</PRE>
We see that SWIG has created two new files, arith_wrap.c and arith_wrap.doc. We should now compile both arith.c and
arith_wrap.c to produce object files, the command being:
<PRE>
<b>gcc -I/usr/include/python1.5 -c arith.c arith_wrap.c</b>
</PRE>
The object files arith.o and arith_wrap.o should now be combined to produced a shared object called arith.so:
<PRE>
<b>ld -shared -o arith.so arith.o arith_wrap.o</b>
</PRE>
If everything goes well, we will have a file called arith.so in our current directory. Here is a sample
interaction using the arith module:
<PRE>
import arith
>>>arith.add(10, 20)
30
>>>arith.add(10, -10)
0
>>>
</PRE>
<H3> Does using C improve speed? </H3>
<p>
We will find out! Let us add one more function to our arith.c file and then rebuild arith.so:
<PRE>
int fact (int n)
{
int f=1;
while (n > 1){
f = f * n;
n = n - 1;
}
return f;
}
</PRE>
Let us make a similar function in Python (store it in a file fact.py):
<PRE>
def fact(n):
f = 1
while n > 1:
f = f * n
n = n - 1
return f
</PRE>
We will now write a crude profiling program, profile.py:
<PRE>
#!/usr/bin/python
import fact, arith, time
pyfact = fact.fact
cfact = arith.fact
# Measuring speed of cfact
start = time.time()
for i in range(1,100000):
cfact(10)
end = time.time()
print 'C factorial function used', end-start, 'seconds'
start = time.time()
for i in range(1,100000):
pyfact(10)
end = time.time()
print 'Python factorial function used', end-start, 'seconds'
</PRE>
Here is the output on our old Pentium box:
<PRE><b>
C factorial function used 1.29531896114 seconds
Python factorial function used 8.22897398472 seconds
</PRE></b>
<H3> The proper way of using SWIG </H3>
<p>
SWIG generates wrappers not by looking at how your C code works internally, but by seeing the interface
specification. Here is how we should have proceeded.
First, create an interface file, arith.i. The file should contain the following
lines:
<PRE>
%module arith
extern int add(int a, int b);
extern int fact(int n);
</PRE>
Now generate the wrappers by running <b>swig -python arith.i</b>, compile into object files and use ld to create
arith.so.
<H2> A low-level interfacing example </H2>
<p>
The PC's parallel port can be used to perform some very amusing hardware interfacing
experiments. On Linux, we have functions like inb(), outb() etc which can be used to access I/O ports.
Here is a C program which writes to the printer port:
<PRE>
#include <asm/io.h>
int main()
{
iopl(3);
outb(1, 0x378);
}
</PRE>
The program should be compiled as <b>cc -O2 io.c</b> and it should be executed with superuser privilege. The iopl
call is required to make the IO ports accessible to user programs. How do we write a Python version of this
program? Simple. Use SWIG to make Python callable versions of outb(), inb() and iopl(). Here is an io.c module
tailored for SWIG:
<PRE>
#include <asm/io.h>
int py_iopl(int level)
{
return iopl(level);
}
void py_outb(unsigned char val, int port)
{
outb(val, port);
}
unsigned char py_inb(int port)
{
return inb(port);
}
</PRE>
Run SWIG and generate the io.so file. Here is a sample interaction (remember, you should run the
Python interpreter as root):
<PRE>
>>>import io
>>>io.py_iopl(3)
>>>io.py_outb(10, 0x378)
>>>io.py_inb(0x378)
10
>>>
</PRE>
<H2> Accessing C variables </H2>
<p>
Global variables declared in your C module can be accessed from Python. We create a module <b>example</b> with
two variables foo and baz:
<PRE>
int foo = 10;
int baz = 20;
</PRE>
The variables foo and baz are accessible in Python through an object called cvar:
<PRE>
>>>import example
>>>example.cvar
Global variables { foo, baz }
>>>example.cvar.foo
10
>>>example.cvar.baz
20
>>>example.cvar.foo = 100
>>>example.cvar.foo
100
>>>
</PRE>
<H2> Accessing C++ Classes </H2>
<p>
Accessing C++ classes is a bit tricky. Let us first create a header file with a simple class
declaration. We call this zoo.h:
<PRE>
class Zoo{
int n;
char animals[10][50];
public:
Zoo();
void shut_up(char *animal);
void display();
};
</PRE>
Now we create an interface file zoo.i:
<PRE>
%module zoo
%{
#include "zoo.h"
%}
class Zoo{
char animals[10][50];
int n;
public:
Zoo();
void shut_up(char *animal);
void display();
};
</PRE>
We generate the Python wrappers by running the command:
<PRE>
<b>swig -python -c++ zoo.i</b>
</PRE>
Here comes our source file zoo.cc:
<PRE>
#include "zoo.h"
#include <stdio.h>
Zoo::Zoo()
{
n = 0;
}
void Zoo::shut_up(char *animal)
{
if (n < 10) {
strcpy(animals[n], animal);
n++;
}
}
void Zoo::display()
{
int i;
for(i = 0; i < n; i++)
printf("%s\n", animals[i]);
}
</PRE>
We create the object files by running:
<PRE>
<b>g++ -I/usr/include/python1.5 -c zoo.cc zoo_wrap.c</b>
</PRE>
And finally, we create the module zoo.so:
<PRE>
<b>ld -shared -o zoo.so zoo.o zoo_wrap.o /usr/lib/libg++.so.2.7.2 /usr/lib/libstdc++.so</b>
</PRE>
Here is an interactive Python session with our zoo module:
<PRE>
Script started on Mon Dec 13 14:31:26 1999
[pce@bhim] ~/src/writings/swig/src/shadow$ python
Python 1.5.1 (#1, Sep 3 1998, 22:51:17) [GCC 2.7.2.3] on linux-i386
Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
>>> import zoo
>>> dir(zoo)
['Zoo_display', 'Zoo_shut_up', '__doc__', '__file__', '__name__', 'new_Zoo']
>>> z=zoo.new_Zoo()
>>> zoo.Zoo_shut_up(z,'Tiger')
>>> zoo.Zoo_shut_up(z,'Lion')
>>> zoo.Zoo_display(z)
Tiger
Lion
>>> z2=zoo.new_Zoo()
>>> zoo.Zoo_shut_up(z2,'Python')
>>> zoo.Zoo_display(z2)
Python
>>>
</PRE>
The constructor in our class Zoo has been mapped to a function called new_Zoo. Similarly, the
member functions shut_up and display have been mapped to Zoo_shut_up and Zoo_display.
<H3> Shadow classes </H3>
<p>
It is possible to create Python classes which act as 'wrappers' around C++ classes. Here is a Python
wrapper class for the C++ Zoo class:
<PRE>
from zoo import *
class Zoo:
def __init__(self):
self.this = new_Zoo()
def shut_up(self, animal):
Zoo_shut_up(self.this, animal)
def display(self):
Zoo_display(self.this)
</PRE>
Now, we can very easily write:
<PRE>
>>> z = Zoo()
>>> z.shut_up('Tiger')
>>> z.shut_up('Lion')
>>> z.display()
Tiger
Lion
>>>
</PRE>
It is even possible to request SWIG to generate Python shadow classes automatically!
<H2>Conclusion</H2>
<p>
SWIG is a useful tool, easy to learn and easy to apply. Though we have only examined SWIG in the
context of Python scripting, usage with other languages like Perl and Tcl is very similar. The
SWIG <a href="http://www.swig.org">Home Page</a> is the definitive source for more information.
<!-- *** BEGIN copyright *** -->
<P> <hr> <P>
<H5 ALIGN=center>
Copyright © 2000, Pramode C.E and Gopakumar C.E<BR>
Published in Issue 49 of <i>Linux Gazette</i>, January 2000</H5>
<!-- *** END copyright *** -->
<!--startcut ==========================================================-->
<P> <HR> <P>
<!-- *** BEGIN navbar *** -->
<A HREF="lg_toc49.html"><IMG ALT="[ Table of Contents ]"
SRC="../gx/indexnew.gif" WIDTH=163 HEIGHT=60 ALIGN=bottom ></A>
<A HREF="../lg_frontpage.html"><IMG ALT="[ Front Page ]"
SRC="../gx/homenew.gif" WIDTH=163 HEIGHT=60 ALIGN=bottom></A>
<A HREF="orr.html"><IMG ALT="[ Prev ]" SRC="../gx/back2.gif" WIDTH=41 HEIGHT=60 ALIGN=bottom></A>
<A HREF="../lg_faq.html"><IMG ALT="[ Linux Gazette FAQ ]"
SRC="./../gx/dennis/faq.gif"WIDTH=163 HEIGHT=60 ALIGN=bottom></A>
<A HREF="silva.html"><IMG ALT="[ Next ]" SRC="../gx/fwd.gif" WIDTH=41 HEIGHT=60 ALIGN=bottom ></A>
<!-- *** END navbar *** -->
</BODY></HTML>
<!--endcut ============================================================-->
|