The Module Creation Process

Perl provides the module creator a set of tools to make his life easier. The main one is called h2xs. This is a program that translates C header files (h files) into Perl external subroutine specifications (xs files).

In C, you use a header file to define an interface to the module. A Perl module is no different; it starts with a C header file.

This example defines a function that manipulates a magnetic tape drive. In other words, it allows the user to rewind the tape, forward space files, and so on.

The header appears in Listing 17.1.

Listing 17.1. mt_op.h
/* Magnetic Tape operations [Not all operations supported by all drivers]: */ 
#define MTRESET   0    /* +reset drive in case of problems */ 
#define MTFSF     1    /* forward space over FileMark, 
                        * position at first record of next file 
                        */ 
#define MTBSF     2    /* backward space FileMark (position before FM) */ 
#define MTFSR     3    /* forward space record */ 
#define MTBSR     4    /* backward space record */ 
#define MTWEOF    5    /* write an end–of–file record (mark) */ 
#define MTREW     6    /* rewind */ 
#define MTOFFL    7    /* rewind and put the drive offline (eject?) */ 
#define MTRETEN   9    /* retension tape */ 
#define MTBSFM    10   /* +backward space FileMark, position at FM */ 
#define MTFSFM    11   /* +forward space FileMark, position at FM */ 
#define MTEOM     12   /* goto end of recorded media (for appending files). 
                        * MTEOM positions after the last FM, ready for 
                        * appending another file. 
                        */ 
#define MTERASE 13      /* erase tape –– be careful! */ 

/* 
 * Perform an operation on the file who's descriptor 
 * is fd.  The operation is one of the constants listed 
 * above (i.e. MTFSF) and the count is the number of items 
 * to space.  (Count is not used on all operations) 
 */ 
int mt_op(const int fd, const int op, const int count);

With this file, you can start to create the module. The first step is to create the prototype files using the command

$ h2xs –An mt_op 
Writing mt_op/mt_op.pm 
Writing mt_op/mt_op.xs 
Writing mt_op/Makefile.PL 
Writing mt_op/README 
Writing mt_op/test.pl 
Writing mt_op/Changes 
Writing mt_op/MANIFEST

(Be careful with the order of the flags. –An works; –nA does not.)

The program h2xs is the Perl utility used to create modules from header files. The –n flag tells the program that this program is called mt_op. The –A flag tells Perl to omit the autoloader flag. (This makes things simpler, and simple is good for now.)

The program creates a directory called mt_op (the name of the module) and a number of files in it. These are

  • mt_op.pm The Perl interface to the module. This file contains the code that actually loads the C functions.

  • mt_op.xs The external subroutine specification. This code is a special sort of half Perl, half C language used to create the interface between the Perl and C code.

  • Makefile.PL The Perl version of the Makefile. Actually, the Perl script that generates the Makefile.

  • README A prototype README file. (For you to edit and fill in.)

  • test.pl A test script. (You are encouraged to add your own tests to this script.)

  • Changes A change history.

  • MANIFEST A list of files included in this module.

If you’re interested, you can examine these files now, but the real fun is about to begin. You need to copy the header file into the mt_op directory and run h2xs again. But before you start, first install the module C::Scan if you have not already done so. Then you can copy the header file and run h2xs again (from the same directory as the previous h2xs command). For example:

$ cp mt_op.h mt_op 
$ h2xs –OAxn mt_op mt_op.h 
Overwriting existing mt_op!!! 
Scanning typemaps... 
Scanning mt_op.h for functions... 
Scanning mt_op.h for typedefs... 
Writing mt_op/mt_op.pm 
Writing mt_op/mt_op.xs 
Writing mt_op/typemap 
Writing mt_op/Makefile.PL 
Writing mt_op/README 
Writing mt_op/test.pl 
Writing mt_op/Changes 
Writing mt_op/MANIFEST

The preceding code uses a few new flags. The –O flag tells h2xs to overwrite existing files. The –x indicator tells the program to scan the header files listed on the command line (mt_op.h) for function prototype and constants and to generate code based on what it finds there.

You may wonder why you couldn’t run the program like this in the first place. Why run it twice?

The reason is that h2xs scans the header files only if they are in the module’s directory. The first run creates the directory; the second does the work. (I don’t know why things are this way, but they are.)

Filling Out the Files

The key file that’s been generated is called mt_op.xs. It will be translated by the xsubpp program into a C module. The current version is somewhat incomplete, but you can see it in Listing 17.2.

Listing 17.2. mt_op.xs (Unmodified)
#include "EXTERN.h" 
#include "perl.h" 
#include "XSUB.h" 

#include <mt_op.h> 


MODULE = mt_op        PACKAGE = mt_op 


int 
mt_op(fd, op, count) 
    int    fd 
    int    op 
    int    count

The file starts with a number of include directives. These are actually C statements. In fact, everything up to the MODULE line is C code and will be copied verbatim into the C file. Edit this section and remove the line

#include <mt_op.h>

You can’t use this header file because it contains symbols that conflict with the official system header file.

You also need to add this line:

#include <sys/mtio.h>

This brings in the official system file.

The MODULE and PACKAGE definitions identify the name of the module. In this case, it’s mt_op. (Normally, the module and package names are the same.)

Tell Perl that you want to generate prototypes for this module. To do that, you need to add the following line after the MODULE directive:

PROTOTYPES: ENABLE

This is followed by the definitions of the functions in the module. In this case, the mt_op function definition.

Spacing and line breaks are important in this file. The return type must begin in column 1 and be on a line by itself. The rest of the prototype follows.

Now you need to fill in the rest of the function. The C version of the function looks like this:

int mt_op(int fd, int op, int count) 
{
    struct mt_op cmd; 
    cmd.mt_op = op; 
    cmd.mt_count = count; 
    return (ioctl(fd, MTIOCTOP, &cmd)); 
}

The Perl XS version looks like the following:

int 
mt_op(fd, op, count) 
    int    fd 
    int    op 
    int    count 

    PREINIT: 
        struct mtop arg; 

    CODE: 
    cmd.mt_op = op; 
    cmd.mt_count = count; 
    RETVAL = ioctl(fd, MTIOCTOP, &cmd)); 
    OUTPUT: 
        RETVAL

Variables are declared in the PREINIT section. (They have to be put in their own section because of what goes on during the translation process.)

The code goes in a CODE section. (That’s simple enough.) The only funny thing about this is the special variable RETVAL. This is used to indicate the value returned from the function.

At the end is the OUTPUT section, which tells Perl what’s actually output from the function. Listing 17.3 shows the modified mod_mt.xs file.

Listing 17.3. mod_mt.xs (Modified)
#include "EXTERN.h" 
#include "perl.h" 
#include "XSUB.h" 

#include <sys/mtio.h> 
MODULE = mt_op        PACKAGE = mt_op 

PROTOTYPES: ENABLE 


int 
mt_op(fd, op, count) 
    int    fd 
    int    op 
    int    count 

    PREINIT: 
        struct mtop arg; 

    CODE: 
    arg.mt_op = op; 
    arg.mt_count = count; 
        RETVAL = ioctl(fd, op, count); 
    OUTPUT: 
        RETVAL

You also need to modify the POD section of the mt_op.pm file. Perl’s h2xs program puts in a template for the documentation, but you’ll need to make it real. You’ll also need to modify the README file as well.

The Makefile.PL file needs to be edited to include any special compilation flags or libraries needed to build the module. In this case, you are including any of them, so there’s no need to edit the file.

Finally, the typemap file is used by Perl to do automatic type conversions. This feature is not used in this example program, so delete the entries in the typemap file.

Now that everything is ready, you can install and test the file.

Building the Module

In Chapter 1, “Exploring Perl,” you learned how to build, test, and install modules. This module is no different. It starts with the command

$ perl Makefile.PL 
Checking if your kit is complete... 
Looks good 
Writing Makefile for mt_op

Note that if you are installing private modules on UNIX/Linux, make sure that you include the "PREFIX=" option. (See Chapter 1 for more details.)

This is followed by the make command, which generates the code. (If you are using Microsoft’s Visual C++, the command is nmake.) For example:

$ make 
cp mt_op.pm blib/lib/mt_op.pm 
/usr/bin/perl –I/usr/lib/perl5/5.6.1/i586–linux –I/usr/lib/perl5/5.6.1 
/usr/lib/perl5/5.6.1/ExtUtils/xsubpp  –typemap 
/usr/lib/perl5/5.6.1/ExtUtils/typemap –typemap typemap mt_op.xs > 
mt_op.xsc && mv mt_op.xsc mt_op.c 
cc –c –I. –DDEBUGGING –fno–strict–aliasing –I/usr/local/include 
–D_LARGEFILE_SOURCE –D_FILE_OFFSET_BITS=64 –g   –DVERSION="0.01" 
–DXS_VERSION="0.01" –fpic –I/usr/lib/perl5/5.6.1/i586–linux/CORE 
mt_op.c 
Running Mkbootstrap for mt_op () 
chmod 644 mt_op.bs 
rm –f blib/arch/auto/mt_op/mt_op.so 
LD_RUN_PATH="" cc  –shared –L/usr/local/lib mt_op.o  –o 
blib/arch/auto/mt_op/mt_op.so 
chmod 755 blib/arch/auto/mt_op/mt_op.so 
cp mt_op.bs blib/arch/auto/mt_op/mt_op.bs 
chmod 644 blib/arch/auto/mt_op/mt_op.bs 
Manifying blib/man3/mt_op.3

Now that the module is created, you should test it. The test.pl script contains the test for this module. By default, the h2xs program generates a single test that checks to see whether the module compiles and the library loads. You can add additional tests to this, but for now go with the default.

The command to run the tests is make test:

$ make test 
PERL_DL_NONLAZY=1 /usr/bin/perl –Iblib/arch –Iblib/lib 
–I/usr/lib/perl5/5.6.1/i586–linux –I/usr/lib/perl5/5.6.1 test.pl 
1..1 
ok 1

The text executed correctly. You can now install the module for real using the command

$ make install 
Installing /usr/lib/perl5/site_perl/5.6.1/i586–linux/auto/mt_op/mt_op.so 
Installing /usr/lib/perl5/site_perl/5.6.1/i586–linux/auto/mt_op/mt_op.bs 
Files found in blib/arch: installing files in blib/lib into architecture 
dependent library tree 
Installing /usr/lib/perl5/site_perl/5.6.1/i586–linux/mt_op.pm 
Installing /usr/man/man3/mt_op.3 
Writing /usr/lib/perl5/site_perl/5.6.1/i586–linux/auto/mt_op/.packlist 
Appending installation info to /usr/lib/perl5/5.6.1/i586–linux/perllocal.pod

The module is now officially installed and ready for use.

Using the Autoloader

It is possible to generate code with the autoload feature turned on by omitting the –A flag when running h2xs.

By default, the module contains just the function mt_op. If you turn on the autoload feature, it will contain not only the function but all the constant definitions as well (MTREW, MTFSF, and so on).

The code generated also will be more complex.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset