Using XS and SWIG may seem like a lot of time and work, especially for something as simple as our factorial benchmark. Fortunately, there is a new module called Inline.pm that makes using Perl with C almost as easy as writing Perl by itself.

Inline.pm allows you to put the source code of other programming languages directly inside your Perl script or module. It currently supports C, C++, Python, Tcl, and Java. The idea is that you can write functions, subroutines, or methods in these languages, and Inline.pm will automatically do whatever it takes to make them callable by Perl. It will analyze your code, compile it if necessary, bind the appropriate routines, and load all the required components. This means that you can simply run your code as if it were any other Perl program.

For example, the entire factorial benchmark program can be written as shown in Example 13-28.

Example 13-28. factorial_benchmark_inline.pl

use strict;
use Benchmark;
use Inline 'C';

my $top = 150;

timethese(500000,
      {
       recursive_perl => sub {factorial_recursive_perl($top)},
       iterative_perl => sub {factorial_iterative_perl($top)},
       recursive_c    => sub {factorial_recursive_c(   $top)},
       iterative_c    => sub {factorial_iterative_c(   $top)},
      });

sub factorial_recursive_perl {
    return 1 if $_[0] < 2;
    return $_[0] * factorial_recursive_perl($_[0] - 1);
}

sub factorial_iterative_perl {
    my $return = 1;
    $return *= $_ for 2..$_[0];
    return $return;
}

__END__

_ _C_ _

double factorial_recursive_c(int x) {
    if (x < 2)  return 1;
    return x * factorial_recursive_c(x - 1);
}

double factorial_iterative_c(int x) {
    int i;
    double result = 1;
    for (i = 2; i <= x; i++) result *= i;
    return result;
}

That's all there is to it. Just run this Perl program like any other, and it will work exactly as you expect. The first time you run it, Inline.pm takes time to compile the C code and build an executable object. On subsequent runs, Inline.pm will simply load the precompiled version. If you ever modify the C code, Inline.pm will detect that and recompile automatically for you.

The results of this benchmark should be similar to the benchmark of the XS version of Book::Factorial, developed in the previous section.

Example 13-29 is an example of a simple mod_perl handler using Inline.pm with C.

Example 13-29. Apache/Factorial.pm

package Apache::Factorial;
use strict;

use Apache::Constants qw(:common);

use Inline 'Untaint';
use Inline Config => DIRECTORY => '/tmp/Inline';
use Inline 'C';
Inline->init;

sub handler {
    my $r = shift;
    $r->send_http_header('text/plain');
    printf "%3d! = %10d\n", $_, factorial($_) for 1..10;
    return OK;
}
1;

__DATA__

_ _C_ _

double factorial(int x) {
    int i;
    double result = 1;
    for (i = 2; i <= x; i++) result *= i;
    return result;
}

This handler will list out all of the factorial numbers between 1 and 10. The extra Inline.pm commands are needed because of mod_perl's unique environment requirements. It's somewhat tricky to make Inline.pm work with mod_perl because of the file permissions. The best approach is to force Inline.pm to compile the module before starting the server. In our case, we can do:

panic% mkdir /tmp/Inline
panic% perl -I/home/httpd/perl -MApache::Factorial \
-e 'Apache::Factorial::handler'

Now all we need is for the /tmp/Inline directory to be readable by the server. That's where Inline.pm has built the loadable object and where it's going to read from.

Inline.pm is an extremely versatile tool and can be used instead of XS in almost any application. It also has features that go well beyond the capabilities of XS. Best of all, you can get an Inline.pm program up and running in minutes.

The Inline.pm distribution comes with copious documentation, including a cookbook of common C-based recipes that you can adapt to your taste. It is also actively supported by the inline@perl.org mailing list.

Just like with XS, you can prepare a package with Makefile.PL and a test suite for a distribution on CPAN. See the Inline.pm manpage for more details.