Perl comes with a nifty utility called h2xs that builds a skeleton for a new module. It's useful whether you are going to write a module with extensions in C/C++ or just in plain Perl.
When you run this utility it creates a new directory named after the module, and a skeleton of the Makefile.PL, test.pl, Module.xs, Module.pm, Changes, and MANIFEST files. If you have a C header file, it tries to guess the XS code based on it and write the correct XS file. Depending on how complicated your interface is, it may or may not do the right thing, but it helps anyway since it creates a boilerplate (which saves quite a lot of work).
First we prepare a C source file and its header file (see Examples 13-21 and 13-22).
double factorial_recursive_c(int x); double factorial_iterative_c(int x);
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; }
It's easy to get lost in directories when creating a new module; therefore, we will show the exact directory we are in, using the prompt:
/home/stas/dev/fact>
Assuming that we work in this directory, we will save both files in this working directory. Let's check:
/home/stas/dev/fact> find /home/stas/dev/fact -type f /home/stas/dev/fact/factorial.c /home/stas/dev/fact/factorial.h
Now we are ready to create the skeleton of the new module:
/home/stas/dev/fact> h2xs -n Book::Factorial -A -O -x \ -F '-I ../..' factorial.h Scanning typemaps... Scanning /usr/lib/perl5/5.6.1/ExtUtils/typemap Scanning factorial.h for functions... Scanning factorial.h for typedefs... Writing Book/Factorial/Factorial.pm Writing Book/Factorial/Factorial.xs Writing Book/Factorial/Makefile.PL Writing Book/Factorial/README Writing Book/Factorial/test.pl Writing Book/Factorial/Changes Writing Book/Factorial/MANIFEST
We'll explain the h2xs arguments we used:
-n Book::Factorial specifies the name of the new module. It is also used to create the base directory (in our case, Book/Factorial/).
-A omits all autoload facilities.
-O allows us to overwrite a directory with the new module if one already exists.
-x automatically generates XSUBs based on function declarations in the header file (factorial.h in our case).
-F `-I../..' specifies where the header file is to be found. When h2xs runs, it changes into the newly created directory (Book/Factorial/ in our example), so in order to see the header file, we have to tell h2xs to look two directories back. (You may also need to add -F '-I.' during the make stage.)
The header file (factorial.h in our case) comes last.
Our next step is to copy the C file and header into the newly created directory and cd into it:
/home/stas/dev/fact> cp factorial.c factorial.h Book/Factorial/ /home/stas/dev/fact> cd Book/Factorial/
Since we have a really simple header file with only two function declarations, we just need to adjust Makefile.PL to build the factorial.o object file and Factorial.o, the actual extension library. We adjust Makefile.PL by adding the following line:
'OBJECT' => 'Factorial.o factorial.o',
We fix the INC attribute to point to the current directory so the copied include file will be found.
Now Makefile.PL looks like Example 13-23 (remember that h2xs does most of the work for us).
use ExtUtils::MakeMaker; # See lib/ExtUtils/MakeMaker.pm for details of how to influence # the contents of the Makefile that is written. WriteMakefile( 'NAME' => 'Book::Factorial', 'VERSION_FROM' => 'Factorial.pm', # finds $VERSION 'PREREQ_PM' => { }, # e.g., Module::Name => 1.1 'LIBS' => [''], # e.g., '-lm' 'DEFINE' => '', # e.g., '-DHAVE_SOMETHING' 'INC' => '-I .', # e.g., '-I/usr/include/other' 'OBJECT' => 'Factorial.o factorial.o', );
Now we remove parts of the default module created by h2xs and add the Perl functions to Factorial.pm, since our module mixes pure Perl and C functions. We also write some simple documentation in POD format. After we add the Perl code and documentation and do some patching, Factorial.pm looks like Example 13-24.
package Book::Factorial; require 5.006; use strict; use vars qw($VERSION); $VERSION = '0.01'; use base qw(DynaLoader); bootstrap Book::Factorial $VERSION; 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; } 1; __END__ =head1 NAME Book::Factorial - Perl and C, Recursive and Iterative Factorial Calculation Functions =head1 SYNOPSIS use Book::Factorial; $input = 5; $result = Book::Factorial::factorial_iterative_c( $input); $result = Book::Factorial::factorial_recursive_c( $input); $result = Book::Factorial::factorial_iterative_perl($input); $result = Book::Factorial::factorial_recursive_perl($input); =head1 DESCRIPTION This module provides functions to calculate a factorial using recursive and iterative algorithms, whose internal implementation are coded in Perl and C. =head2 EXPORTS None. =head1 AUTHORS Eric Cholet <email address> and Stas Bekman <email address> =head1 SEE ALSO perl(1). =cut
If you've written pure Perl modules before, you'll see that the only unusual part is the code:
use base qw(DynaLoader); bootstrap Book::Factorial $VERSION;
The base pragma specifies that the package Book::Factorial inherits from DynaLoader. Alternatively, you can write this as:
require DynaLoader; @Book::Factorial::ISA = qw(DynaLoader);
where @ISA is the array that's used when inheritance relations are specified.
bootstrap is the place where the C extension Factorial.o is loaded, making the C functions available as Perl subroutines.
It's very important to document the module, especially when the package's functions don't reside within the module itself. Doing so will let you and your users know what functions are available, how they should be called, and what they return.
We have written very basic documentation. Usually it's a good idea to document each method.
In our example we decided not to export any functions to the callers; therefore, you always need to prefix the functions with the package name if used outside of this module:
use Book::Factorial; $result = Book::Factorial::factorial_iterative_c(5);
We are almost done. Let's build the Makefile:
/home/stas/dev/fact/Book/Factorial> perl Makefile.PL Checking if your kit is complete... Looks good Writing Makefile for Book::Factorial
Next we run make to compile the extension and get the module ready for testing:
/home/stas/dev/fact/Factorial> make
In addition to building the extension, make also renders the POD documentation in nroff format, which will be installed as a manpage when make install is run.
It's now time to test that the C extension was successfully linked and can be bootstrapped. h2xs has already created test.pl, which does this basic testing:
/home/stas/dev/fact/Book/Factorial> make test PERL_DL_NONLAZY=1 /usr/bin/perl -Iblib/arch -Iblib/lib -I/usr/lib/perl5/5.6.1/i386-linux -I/usr/lib/perl5/5.6.1 test.pl 1..1 ok 1
As we can see, the testing phase has passed without any problems. Is that all? Not really. We actually have to test that the functions are working as well, so we extend the test suite with an exhaustive set of tests.
In product-validation terminology this is sometimes known as comparing the results from the good and the bad machine, where the good machine is known to produce a correct result. In our case the good machine is either our head or a simple calculator. We know that:
4! = = 24
So we know that if the function works correctly, for a given input of 4, the output should be 24. Of course, in some cases this test is not enough to tell a good function from a broken one. The function might work correctly for some inputs but misbehave for others. You may need to come up with more elaborate tests.
The testing procedure is based on printing the number of tests to be run in the BEGIN block and, for each test, printing either ok or not ok, followed by the number of the current test. Example 13-25 is a modified test.pl that exercises the bootstrapping (as provided by h2xs), plus two C functions and two Perl functions.
use Test; BEGIN { plan tests => 5; } use Book::Factorial; ok 1; # module loaded OK my $input = 4; my $correct_result = 24; # the good machine: 4! = 24 my $result = 0; my $s = 1; # testing iterative C version $result = Book::Factorial::factorial_iterative_c($input); ok $result = = $correct_result; # testing recursive C version $result = Book::Factorial::factorial_recursive_c($input); ok $result = = $correct_result; # testing iterative Perl version $result = Book::Factorial::factorial_iterative_perl($input); ok $result = = $correct_result; # testing recursive Perl version $result = Book::Factorial::factorial_recursive_perl($input); ok $result = = $correct_result;
Note the magic BEGIN block, which ensures that the test reports failure if it failed to load the module.
Now we run the test again using our new test.pl:
/home/stas/dev/fact/Book/Factorial> make test PERL_DL_NONLAZY=1 /usr/bin/perl -Iblib/arch -Iblib/lib -I/usr/lib/perl5/5.6.1/i386-linux -I/usr/lib/perl5/5.6.1 test.pl 1..5 ok 1 ok 2 ok 3 ok 4 ok 5
Fortunately all the tests have passed correctly. Now all we have to do is to install the module in our filesystem and start using it. You have to be root to install the module into the system-wide area:
/home/stas/dev/fact/Book/Factorial# su /home/stas/dev/fact/Book/Factorial# make install Installing /usr/lib/perl5/site_perl/5.6.1/i386-linux/auto/Book/Factorial/Factorial.so Installing /usr/lib/perl5/site_perl/5.6.1/i386-linux/auto/Book/Factorial/Factorial.bs Installing /usr/lib/perl5/site_perl/5.6.1/i386-linux/Book/Factorial.pm Installing /usr/lib/perl5/man/man3/Book::Factorial.3
That's it. Neither very complicated nor very simple. We mentioned the XS macro language earlier but didn't actually use it—this is because the code was simple, and h2xs wrote the Factorial.xs file (shown in Example 13-26) for us based on the header file we provided (factorial.h).
#include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include <factorial.h> MODULE = Book::Factorial PACKAGE = Book::Factorial double factorial_iterative_c(x) int x double factorial_recursive_c(x) int x
This file actually implements the real gluing specification. During the make phase it was macro-processed by the xsubppsubroutine into the C code version Factorial.c, which was then compiled into the Factorial.o object file and finally converted into the Factorial.so loadable object and installed in the architecture-dependent module library tree (/usr/lib/perl5/site_perl/5.6.1/i386-linux/auto/Book/Factorial on our machine).
When a more complicated C interface is used, the glue code might be much more involved and require knowledge of the XS language. XS is explained in the perlxs manpage. The following manpages might be useful too:
perlembed Perl ways to embed Perl in your C or C++ application perlapio Perl internal I/O abstraction interface perldebguts Perl debugging guts and tips perlxs Perl XS application programming interface perlxstut Perl XS tutorial perlguts Perl internal functions for those doing extensions perlcall Perl calling conventions from C perlapi Perl API listing (autogenerated) perlintern Perl internal functions (autogenerated)
The POD documentation format is explained in the perlpod manpage.
You may also want to read Advanced Perl Programming, by Sriram Srinivasan (O'Reilly), which covers XS and SWIG, and Extending and Embedding Perl, by Tim Jenness and Simon Cozens (Manning Publications).
 
Continue to: