I like
Inline and I especially like
Inline::C. There is great
power for good and evil with
Inline so below is my quick guide to using
and hopefully not abusing it.
What is Inline
Inline allows you to simply
embed other languages inside of
perl. Right now there are about ten languages you can
Inline -
Assembly, Awk, Basic, C++, Guile, Java, Octave, Python, Ruby, Tcl
and of course C. There are other things you can do with
Inline (like
reverse it and embed perl in C) but I'm going to stick with the more common
form.
Why
Why would you want to use
Inline? That's a good question and
I can think of three answers:
- You wish to expose an existing non-perl library to perl
- You wish to increase run-time speed
- Its just plain fun
Why Not
Of course there are reasons you shouldn't be using
Inline:
- There are all ready existing, viable CPAN modules that do the task
- You're a purist and wish all solutions to be perl alone
- You should concentrate on optimizations last not first
That purist issue really is a good one. You have to remember that
in order to use
Inline, not only do you need the CPAN modules but you
also need the necessary tools and libraries for the other language
as well.
Competition
Inline is the new kid on the block. There are other mechanism
for embedding other languages into your code. There is the venerable
perlxs as well as
swig. I
cannot comment too much on swig but I can say that
Inline is much
easier to start with than XS.
Where to start
You should do a lot of reading before you decide to
Inline. Here's a
good list:
Tools Needed for Inline::C
To continue with the rest of this tutorial, you should ensure you have a
c compiler and the
Inline module
(which includes the
Inline::C module).
Examples
The cannonical
The following code is just a simple straight forward snippet of
Inline
that prints everyones favorite line:
hello.pl
#!/usr/bin/perl -w
use Inline C;
use strict;
hello_inline();
__END__
__C__
#include <stdio.h>
void hello_inline( ) {
printf( "Hello World. Best Regards from Inline\n" );
}
Exposing a Library
There is a nice little
library that exposes the services file and lets you view, add, delete
of modify entries in it.
In order to use the rest of the examples, download and install the services
library. Make sure you install it in a directory where your compiler/loader can
find the header and library. You can still use Inline if the files are in an odd
location but you would need to configure your Inline properly.
This next snippet of Inline just exposes that part
of the services library that reads the file. (This is also a sub-benefit of
Inline, you can pare-down or wrapper only those parts of a library which
you deem important).
services_print.pl
#!/usr/bin/perl
use Inline C => DATA =>
LIBS => '-lservices';
# Here's how we would configure Inline if our headers and
# libraries are in a non-standard location
#use Inline C => DATA =>
# INC => '-I/usr/local/include' =>
# LIBS => '-L/usr/local/lib -lservices';
my_services();
__END__
__C__
#include <libservices.h>
int my_services( ) {
struct serv *serv_list = serv_load(NULL);
struct serv *serv = serv_list;
for (; serv; serv = serv->next) {
printf("%s %s %s \n", serv->name, serv->port, serv->proto );
}
serv_destroy(serv_list);
return 1;
}
If you run this code, you will see a listing of all the services contained
in your services file. But this isn't really useful. Let's slightly modify this
example to add the services to the stack, thus returning an array of
of services that we can work on in perl world:
services_stack.pl
#!/usr/bin/perl -w
use Inline C => DATA =>
LIBS => '-lservices';
my( @srvs ) = my_services();
foreach( @srvs ) {
foreach( @$_ ) {
print $_, " ";
}
print "\n";
}
__END__
__C__
#include <libservices.h>
void my_services( ) {
struct serv *serv_list = serv_load(NULL);
struct serv *serv = serv_list;
SV *record[3];
AV *entry;
Inline_Stack_Vars;
Inline_Stack_Reset;
for (; serv; serv = serv->next) {
record[0] = newSVpv(serv->name, 0 );
record[1] = newSVpv(serv->port, 0 );
record[2] = newSVpv(serv->proto, 0 );
Inline_Stack_Push(newRV_noinc((SV*)av_make(3,record)));
}
serv_destroy(serv_list);
Inline_Stack_Done;
}
Now that's pretty powerful.
Speed
Now we could parse the /etc/services ourselves and just have
a pure perl approach. The next snippet of
Inline shows that and
bench marks the two approaches:
services_bm.pl
#!/usr/bin/perl -w
use Benchmark;
use Inline C => DATA =>
LIBS => '-lservices';
use strict;
timethese( 500, {
'inline' => sub{ &inline(); },
'pure' => sub{ &pure(); },
}
);
sub pure {
my( $serv, $pp, $rst, $port, $proto, $array, @all );
open( SERVICES, "</etc/services" ) or die "Cannot open: $!\n";
while( <SERVICES> ) {
next if /^#/;
next if /^\s+$/;
( $serv, $pp, $rst ) = split( /\s+/, $_ );
( $port, $proto ) = split( /\//, $pp );
#print $serv, " ", $port, " ", $proto, " ", "\n";
push( @all, [$serv,$port,$proto] );
}
close( SERVICES );
@all;
}
sub inline {
my( @srvs ) = my_services();
}
__END__
__C__
#include <libservices.h>
void my_services( ) {
struct serv *serv_list = serv_load(NULL);
struct serv *serv = serv_list;
SV *record[3];
AV *entry;
Inline_Stack_Vars;
Inline_Stack_Reset;
for (; serv; serv = serv->next) {
record[0] = newSVpv(serv->name, 0 );
record[1] = newSVpv(serv->port, 0 );
record[2] = newSVpv(serv->proto, 0 );
Inline_Stack_Push(newRV_noinc((SV*)av_make(3,record)));
}
serv_destroy(serv_list);
Inline_Stack_Done;
}
And the results of benchmarking are:
Benchmark: timing 500 iterations of inline, pure...
inline: 3 wallclock secs ( 2.67 usr + 0.38 sys = 3.05 CPU) @ 16
+3.93/s (n=500)
pure: 8 wallclock secs ( 8.65 usr + 0.16 sys = 8.81 CPU) @ 56
+.75/s (n=500)
Benchmark: timing 500 iterations of inline, pure...
inline: 3 wallclock secs ( 2.58 usr + 0.46 sys = 3.04 CPU) @ 16
+4.47/s (n=500)
pure: 9 wallclock secs ( 8.64 usr + 0.11 sys = 8.75 CPU) @ 57
+.14/s (n=500)
Benchmark: timing 500 iterations of inline, pure...
inline: 3 wallclock secs ( 2.63 usr + 0.41 sys = 3.04 CPU) @ 16
+4.47/s (n=500)
pure: 8 wallclock secs ( 8.62 usr + 0.15 sys = 8.77 CPU) @ 57
+.01/s (n=500)
So we can see the
Inline version is much faster than the perl version
(but I'm sure there are other pure perl implementations which would be
faster than what I've done here).
Thanks and Credits
Inline would not have been possible without the hardwork
and dedication of
Brian Ingerson.
Also, check out the official
Inline site.
-derby
updated: return type for hello_inline function was incorrect (thanks ariels). Also just recently read tye remarks about posting snippets to pm should
cannocalize the shebang to /usr/bin/perl (I just wish I
could find that node again - no luck with search or supersearch).
-
Are you posting in the right place? Check out Where do I post X? to know for sure.
-
Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
<code> <a> <b> <big>
<blockquote> <br /> <dd>
<dl> <dt> <em> <font>
<h1> <h2> <h3> <h4>
<h5> <h6> <hr /> <i>
<li> <nbsp> <ol> <p>
<small> <strike> <strong>
<sub> <sup> <table>
<td> <th> <tr> <tt>
<u> <ul>
-
Snippets of code should be wrapped in
<code> tags not
<pre> tags. In fact, <pre>
tags should generally be avoided. If they must
be used, extreme care should be
taken to ensure that their contents do not
have long lines (<70 chars), in order to prevent
horizontal scrolling (and possible janitor
intervention).
-
Want more info? How to link
or How to display code and escape characters
are good places to start.