Perl has always been pathetically eclectic, but until now it hasn't been terribly easy to make it work with other languages or with libraries that weren't constructed specifically for it. You had to write interface code in the XS language (or get SWIG to do that for you), build an organized module, and generally keep track of a whole lot of details.
But now things have changed. The Inline module, written and actively (very actively) maintained by Brian Ingerson, provides facilities to bind other languages to Perl. In addition its sub-modules (Inline::C, Inline::Python, Inline::Tcl, Inline::Java, Inline::Foo, etc.) allow you to embed those languages directly in Perl files, where they will be found, built, and dynaloaded into Perl in a completely transparent manner. The user of your script will never know the difference, except that the first invocation of Inline-enabled code takes a little time to complete the compilation of the embedded code.
The world's simplest Inline::C program
Just to show you what I mean, let's look at the simplest possible Inline program; this uses an embedded C function, but you can do substantially the same thing with any other language that has Inline support.
Listing 1. Inline "Hello, world"
use Inline C => <<'END_C';
void greet() {
printf("Hello, world!
");
}
END_C
greet;
|
Naturally, what the code does is obvious. It defines a C-language function to do the expected action, and then it treats it as a Perl function thereafter. In other words, Inline does exactly what an extension module should do. The question that may be uppermost in your mind is, "How does it do that?". The answer is pretty much what you'd expect: it takes your C code, builds an XS file around it in the same way that a human extension module writer would, builds that module, then loads it. Subsequent invocations of the code will simply find the pre-built module already there, and load it directly.
You can even invoke Inline at runtime by using the
Inline->bind function. I don't want to do anything more than
dangle that tantalizing fact before you, because there's nothing special about
it besides the point that you can do it if you want to.
Compare and contrast with XS and SWIG
Contrast this with the same interface without Inline. To call C
code from Perl, you have to create a module using h2xs. Then you
write XS code that xsubpp uses to write C code that understands
all the Perl variable conversions and such. The user has to obtain your
module, run Makefile.PL to create a Makefile, run make
to compile it, test it, and install it, and only then can scripts using the
module be run.
A tool that helps a great deal in this whole process is SWIG, which can be persuaded to generate a lot of the XS code for you. However, SWIG doesn't parse C header files all that well, so there's only so much it can do. For more involved projects you still have to encode at least some of your functions by hand for SWIG to know what to do. Then, of course, if you want any specialized processing done at all (maybe you want a single Perl function to call different C functions depending on the number or type of parameters you pass), you end up modifying its output anyway.
But it's worse, really. XS only generates C code, and SWIG only works on C (or C++) include files in order to generate its output. This means that to interface code in some other language (like Python), you have to first write wrapper code in C to call your Python code, and then wrap it again in XS, which wraps it in Perl. Thus you have to be pretty darned familiar with Perl, C, how they interact with one another, as well as your target language and how it interacts with C.
And it's even worse than that in one respect: your potential user (if you want to distribute your code) has to be comfortable enough with Perl to obtain your module and install it. For installation on UNIX, your user may need root or at least some administrative privileges, because installation is done into Perl's own library directory. In other words, your target user can't be naive. And that's a lot to ask.
But Inline changes the picture completely. The individual language modules
understand how to read their respective languages to discover function
definitions, how to write XS and C wrapper code to call them (or simply how to
invoke an interpreter in the case of interpreted languages like Python), and how
to install the whole thing. Best of all, by far, is that the end user of
your Perl script sees absolutely nothing of any of this. None of the output of
make or compiler is displayed. And since Inline can keep its build files and its
dynamic link objects in any directory (it defaults to an _Inline or .Inline
subdirectory of the location of the script you're running), then your user
doesn't need any special privileges to use an Inline-based module.
The only real requirement, in fact, is that the language in question actually
be installed; for C this means that the compiler used to create the Perl
installation is still available. On UNIX this is rarely a problem; on Windows it
may be, as most Windows Perl users use ActiveState Perl, which is compiled with
Microsoft Visual C++ 6.0 (as of this writing.) One way around this is to use the
Cygwin compatibility layer and a Perl built against that, in which case the
compiler will be gcc. Another way, which I'm using right now, is to
use the Mingw32 toolset (Minimum Win32 GNU), but the support for that is still a
little shaky under some flavors of Windows. (OK, so I use Windows ME sometimes.
I do, however, bathe regularly.) Brian Ingerson is working on getting an
ActiveState Inline installation to use compilers other than Visual C++, so by
the time you read this, this may no longer be an issue at all.
There are two obvious applications of Inline. First is conversion of frequently used code from Perl to C; since C is compiled, its execution time is far faster. And since the rest of the program is still written in Perl, you don't lose the development speed, flexibility, and other nice features of Perl. You can even call Perl functions (regular expressions, anyone?) from your C code. I'm getting quite excited about the possibility of combining Inline, Perl, wxWindows for GUI work, and arbitrary C code for speed.
Which brings me to the other obvious application of Inline, and that is for creating wrappers for external libraries (such as, well, wxWindows). In fact, Inline is probably going to be the default interface method in Perl 6. It's that good. Inline in its latest incarnations (version 0.40 as of this writing) also makes provision for system-level installation of Inline modules. If modules are installed at the system level (as opposed to being on-the-fly compilations) then you can distribute them as precompiled binaries. If the user compiles anyway, Inline can be told not to recompile automatically (as you don't want your core Perl to be recompiled unexpectedly).
A somewhat unexpected boon of Inline, however, at least for me, is that you can use it to test C libraries that you have under development. Since Perl has a pretty decent testing (and test documentation) facility, you can even use a regular Perl test harness for your C libraries. Of course, since the Inline wrapper is so easy to create and to maintain, you're far more likely to follow through on careful testing.
To link to a library, all you have to do is include appropriate flags for the
linker in your invocation of Inline. That's reason enough to present a more
realistically-sized example than the minimal one above, so that you can see not
only how libraries are linked, but the more organized file layout that takes
advantage of the __DATA__ token to separate the C code from the Perl code.
I'd really like to show you a test wrapper I wrote myself, but anything
meaningful would be too big and repetitious to display in an article, so instead
I'll make up an example of a C library for you that's not completely
trivial.
Let's
assume we have a library that works with a session object. When we start
talking to the library about something, we call a function called
newsession that returns a void pointer (not an unusual way to
organize things). On subsequent calls to the library, we pass that session in to
establish a context. Since the session is a malloc'd object, we
also have to free the session when we're done with it. To keep things relatively
simple, let's assume four functions: newsession to allocate a
session, freesession to free it, setattribute to set a
configuration attribute of some sort, and getresult to obtain a
result of some sort. We'll call the whole thing "mylib", and let's assume that
it's stored in a directory "/usr/local/mylib". Note that on Windows you can just
give the directory as 'c:\projects\mylib' and use the filename of the DLL in
question without the .dll extension.
One of Perl's advantages over straight C, of course, is that it does heap management on objects, so that when an object passes out of scope, it will be destroyed. So let's make this module a Perl object-oriented module to get that behavior. As far as I'm concerned, this is the best of all possible worlds -- I like the OO goodness of being able to ignore cleanup, but I don't like the discipline of writing OO code straight through. I much prefer to write low-level routines in C and keep an eye on details there. This configuration lets me do just that, so I predict that I will be much more dangerous from now on.
Listing 2. A non-trivial Inline example
package MyWrapper;
use Inline => Config => LIBS => '-L/usr/local/mylib -lmylib';
use Inline => Config => INC => '-I/usr/local/mylib';
use Inline C;
sub version {
return "MyWrapper 2.0";
}
__DATA__
__C__
#include "mylib.h"
SV* new() {
void * session = newsession();
SV* obj_ref = newSViv(0);
SV* obj = newSVrv(obj_ref, class);
sv_setiv(obj, (IV)session);
SvREADONLY_on(obj);
return obj_ref;
}
void set (SV* obj, char *attribute, char *value) {
setattribute ( ((void*)SvIV(SvRV(obj))), attribute, value);
}
char* get (SV* obj) {
return getresult ( ((void *)SvIV(SvRV(obj))) );
}
void DESTROY(SV* obj) {
return freesession ( ((void *)SvIV(SvRV(obj))) );
}
|
This little example demonstrates basically all you need to make wrappers for
any library; since the wrapper is in Perl and since it gets recompiled whenever you
change it, it's pretty much ideal for testing a library that's still under
development. Let's look at it blow-by-blow. The first thing to notice
is the use Inline statements that demonstrate how to set
configuration parameters for Inline. The only two we're interested in here are
LIBS and INC, which give the link and include
parameters for the compiler. If you're not using gcc as your
compiler, you may need to change these. The Inline C statement, if
you don't specify a string for the code, will look in the __DATA__
area of your script for its code. This gives a way to mix languages, as each
use Inline <lang> will use its own section, so you can stack
them up to your heart's content.
Right under that, I tossed in a little Perl function to return a fairly meaningless string. This is really just to demonstrate how easy it is to build a module that mixes C and Perl. In fact, Perl functions in the module can just as easily call the C functions themselves, and the C functions in your module can even evaluate Perl functions if they need to. (You may have different functions to call depending on argument types, for instance, or require some pre- or post-processing that makes more sense to write in Perl.)
After the version function, we settle down to some nice C
code.
Any Perl object requires the new and DESTROY
methods to be defined. In an Inlined object, those functions can naturally be in
any language, as long as they're named correctly. Since we're working with a
blessed object, the new function has to return a Perl object (the
SV*, which stands for "scalar variable"), and all the other
functions have to accept the same as their first arguments. Every other argument
may be a perfectly normal C type, however, as Inline will figure out the
conversion code for you automatically. For the cases when you really need to
know how to work with Perl variables, though, you'll find the "perlguts"
documentation invaluable. It's included in your Perl distribution, and it's also
accessible from the Perl Web site (see Resources).
The way this is set up, the Perl object contains a read-only integer that
corresponds to the void pointer returned by newsession(). The
new function basically does nothing besides building the object
reference to contain that, and you can see that the other functions have to
unpack the void pointer before getting down to business. Other arguments (the
attribute and name arguments to set
needn't do any kind of Perl gyrations and can treat strings as normal C
strings).
Basically, that's all there is to it! You can practically cut and paste to wrap any library you want; there are further excellent examples in the C cookbook contained in the Inline distribution, but it just isn't that difficult to figure this out. So go download the module and get started -- what are you waiting for?
- Visit Brian Ingerson's Inline home page.
- The central point of reference for all
things Inline is the Inline
distribution on CPAN. You'll find links on this page to the documentation for the module, including the C Cookbook,
which has more examples similar to those in this article.
- Subscribe to the Inline
mailing list. Since the Inline module is so new and it's still changing
rapidly, the mailing list is the best way to get timely information.
- For complete documentation on how to work with Perl values
from C, see the Perl guts
documentation. Not all information in the perlguts documentation is immediately relevant to Inline development, but it's a good read nonetheless.
- Take the XS
tutorial from Perldoc.com to learn what
Inline is actually doing under the hood.
- Visit the Cygwin home page at Red
Hat; the Cygwin porting library is one way to get Inline functionality
under Windows.
- The
Mingw32 distribution is another (and much lighter-weight) way to get GNU
software running under Windows.
- For more information on
SWIG (in case you aren't convinced Inline is easier), visit the SWIG home page.
- Other articles on the developerWorks
Linux zone of interest to Perl developers are:
- Zope for the Perl/CGI programmer (also by Michael Roberts)
- Cultured Perl: A programmer's Linux-oriented setup
- Cultured Perl: Perl 5.6 for C and Java programmers
- Using Perl to create reusable Web apps
Michael Roberts has been coding for his entire adult life (heck, pre-adult, too) but has only written about it for a few months. When not programming, he likes to plan new projects. You can contact him at michael@vivtek.com or visit his Web site at Vivtek.com.





