Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Getting Started with Inline::C

by derby (Abbot)
on Mar 12, 2002 at 13:52 UTC ( [id://151114]=perltutorial: print w/replies, xml ) Need Help??

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:
  1. You wish to expose an existing non-perl library to perl
  2. You wish to increase run-time speed
  3. Its just plain fun

Why Not

Of course there are reasons you shouldn't be using Inline:
  1. There are all ready existing, viable CPAN modules that do the task
  2. You're a purist and wish all solutions to be perl alone
  3. 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).

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perltutorial [id://151114]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others about the Monastery: (6)
As of 2024-03-19 09:09 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found