Using h2xs to Make a Module with C Code (Perl Cookbook, 2nd Edition)

## 12.18. Using h2xs to Make a Module with C Code

### 12.18.1. Problem

You'd like to access your system's unique C functions from Perl.

### 12.18.2. Solution

Use the h2xs tool to generate the necessary template files, fill the files in appropriately, and then type:

>     % perl Makefile.PL
>     % make

### 12.18.3. Discussion

A Perl module need not be written solely in Perl. As with any other module, first pick a module name and use h2xs on it. We'll make a `FineTime::time` function with the same semantics as in the previous recipe, but this time around, we'll implement it using real C.

First, we run the following command:

>     % h2xs -cn FineTime

If we had a .h file with function prototype declarations, we could include that, but because we're writing this one from scratch, we'll use the -c switch to omit building code to translate any `#define` symbols. The -n switch says to create a module directory named FineTime/, which will have the following files:

Manifest | List of files in the distribution
--- | ---
Changes | Change log
Makefile.PL | A meta-makefile
FineTime.pm | The Perl parts
FineTime.xs | The soon-to-be C parts
test.pl | A test driver

Before we can type `make`, we'll have to generate a Makefile based on our system's configuration using the Makefile.PL template. Here's how to do that:

>     % perl Makefile.PL

If the XS code calls library code that isn't in the normal set of libraries Perl links from, add one more line to Makefile.PL first. For example, if we wanted to link against the librpm.a library, which lives in the /usr/redhat/lib directory, we'd change the line of Makefile.PL that reads:

>     "LIBS"      => [""],   # e.g., "-lm"

so that it says:

>     "LIBS"      => ["-L/usr/redhat/lib -lrpm"],

If the module is to be installed somewhere other than the local site_lib directory, specify that on the command line:

>     % perl Makefile.PL LIB=~/perllib

Finally, edit the FineTime.pm and FineTime.xs files. In the first case, most of the work has been done for us. We just set up the export list with the function to be exported. This time we put it in `@EXPORT_OK` so that if the user wants the function, they must ask for it by name. Here's FineTime.pm:

>     package FineTime;
>     use strict;
>     use vars qw($VERSION @ISA @EXPORT_OK);
>     require Exporter;
>     require DynaLoader;
>     @ISA = qw(Exporter DynaLoader);
>     @EXPORT_OK = qw(time);
>     $VERSION = "0.01";
>     bootstrap FineTime $VERSION;
>     1;

The make process automatically translates FineTime.xs into a FineTime.c file and eventually into a shared library, probably called FineTime.so on most platforms. The utility that does this translation is xsubpp, which is described in its own manpage and perlxstut(1). The build will call xsubpp automatically.

Besides a strong C background, you also need to understand the C-to-Perl interface, called XS (external subroutine). The details and nuances of XS are beyond the scope of this book. The automatically generated FineTime.xs had the Perl-specific include files in it, as well as the MODULE declaration. We've added some extra includes and written the code for the new `time` function. Although this doesn't look entirely like C, it will, once xsubpp is done with it.

Here's the FineTime.xs we used:

>     #include <unistd.h>
>     #include <sys/time.h>
>     #include "EXTERN.h"
>     #include "perl.h"
>     #include "XSUB.h"

>     MODULE = FineTime           PACKAGE = FineTime

>     double
>     time( )
>         CODE:
>             struct timeval tv;
>             gettimeofday(&tv,0);
>             RETVAL = tv.tv_sec + ((double) tv.tv_usec) / 1000000;
>         OUTPUT:
>             RETVAL

Defining a function by the same name as one from the standard C library won't cause a problem when it's compiled, because that's not its real name. That's just what Perl calls it. The C linker will see it as `XS_FineTime_time`, so no conflict exists.

Here's what happened with make install (with some edits):

>     % make install
>     mkdir ./blib/lib/auto/FineTime
>     cp FineTime.pm ./blib/lib/FineTime.pm
>     /usr/local/bin/perl -I/usr/lib/perl5/i686-linux/5.00403  -I/usr/lib/perl5
>     /usr/lib/perl5/ExtUtils/xsubpp -typemap
>             /usr/lib/perl5/ExtUtils/typemap FineTime.xs
>     FineTime.tc && mv FineTime.tc FineTime.c && cc -c -Dbool=char -DHAS_BOOL
>         -O2-DVERSION=\"0.01\" -DXS_VERSION=\"0.01\" -fpic
>         -I/usr/lib/perl5/i686-linux/5.00403/CORE  FineTime.c
>     Running Mkbootstrap for FineTime ( )
>     chmod 644 FineTime.bs
>     LD_RUN_PATH="" cc -o blib/arch/auto/FineTime/FineTime.so
>         -shared -L/usr/local/lib FineTime.o
>     chmod 755 blib/arch/auto/FineTime/FineTime.so
>     cp FineTime.bs ./blib/arch/auto/FineTime/FineTime.bs
>     chmod 644 blib/arch/auto/FineTime/FineTime.bs
>     Installing /home/tchrist/perllib/i686-linux/./auto/FineTime/FineTime.so
>     Installing /home/tchrist/perllib/i686-linux/./auto/FineTime/FineTime.bs
>     Installing /home/tchrist/perllib/./FineTime.pm
>     Writing /home/tchrist/perllib/i686-linux/auto/FineTime/.packlist
>     Appending installation info to /home/tchrist/perllib/i686-linux/perllocal.pod

Once this is all done, we'll be able to type something like this into the shell:

>     % perl -I ~/perllib -MFineTime=time -le "1 while print time( )" | head
>     888177070.090978
>     888177070.09132
>     888177070.091389
>     888177070.091453
>     888177070.091515
>     888177070.091577
>     888177070.091639
>     888177070.0917
>     888177070.091763
>     888177070.091864

### 12.18.4. See Also

Chapters 18 through 20 in Advanced Perl Programming; perlxstut(1) and perlxs(1) to learn how to call C from Perl; perlcall(1) and perlguts(1) to understand the internal Perl API, also the "Extending Perl" section of Chapter 21 of Programming Perl; perlembed(1) to learn how to call Perl from C, also the "Embedding Perl" section of Chapter 21 of Programming Perl; the documentation for the standard ExtUtils::MakeMaker module, h2ph(1) and xsubpp(1); http://www.cpan.org/authors/Dean_Roehrich/, which contains Dean's comprehensive XS cookbook that includes directions on interfacing with C++

Copyright © 2003 O'Reilly & Associates. All rights reserved.