Документация
HTML CSS PHP PERL другое

Section 16.2.  Using h2xs

 
Previous
Table of Contents
Next

16.2. Using h2xs

We'll explain the Makefile.PL process using the awkwardly named h2xs.[Section 16.2.  Using h2xs] We use h2xs to create a set of template files that are a starting point for our distribution files. We simply need to say H2xs -XAn, followed by the name of the modulein this case, Island::Plotting::Maps.[Section 16.2.  Using h2xs] Here's what the output looks like:[§]

[Section 16.2.  Using h2xs] The name h2xs has an interesting pedigree. Back in the early days of Perl 5, Larry invented the XS language to describe the glue code that Perl needs to talk to C-language functions and libraries. Originally, this code was written entirely by hand, but the h2xs tool was written to scan simple C-include header files (ending in .h) and generate most of the XS directly. Hence, h 2 (to) XS. Over time, more functions were added, including generating template files for the rest of the distribution. Now here we are, about to describe how to use h2xs for things that aren't either h or XS. Amazing.

[Section 16.2.  Using h2xs] If there's more than one module in the distribution, it should be the name of the most important module. Others can be added later.

[§] The exact behavior and output of h2xs may vary depending upon the version of Perl.

Defaulting to backwards compatibility with perl 5.8.7
If you intend this module to be compatible with earlier perl versions, please
specify a minimum perl version with the -b option.

Writing Island-Plotting-Maps/lib/Island/Plotting/Maps.pm
Writing Island-Plotting-Maps/Makefile.PL
Writing Island-Plotting-Maps/README
Writing Island-Plotting-Maps/t/Island-Plotting-Maps.t
Writing Island-Plotting-Maps/Changes
Writing Island-Plotting-Maps/MANIFEST

16.2.1. MANIFEST

The h2xs program created a directory and several files. These are mostly the same files that the other module creation tools set up for us, so even if you decide not to use h2xs, you still need to understand these files. Let's examine the MANIFEST file, which contains the list of files that the distribution will contain. At the start, our MANIFEST contains:[**]

[**] Again, there may be slight variations based on tool and Perl versions.

Changes
Makefile.PL
MANIFEST
README
t/Island-Plotting-Maps.t
lib/Island/Plotting/Maps.pm

The MANIFEST file is really a table of contents for our distribution. When we decide to bundle the archive, all of the files in MANIFEST go into the archive. When the end user unpacks the distribution, the module installer tool verifies that all of the files in MANIFEST are in the archive. In fact, we're ready to make an archive right now. First, we need to run the Makefile.PL. After that, we find a new file, Makefile, in our directory.

$ perl Makefile.PL
$ make tardist

If we don't want to make a tar achive, we can create a zip file.

$ make ziptest

While maintaining a MANIFEST sounds like it might be painful, we know that we won't accidentally include our "notes to self" in the distribution just because those files happened to be in the wrong directory. Later, we'll show you how to update MANIFEST.

16.2.2. README

The next file is README, which is a standard name for the first bit of information you want all users of your module to read. It's customary to include at least a brief description of the module, installation instructions, and licensing details.

Island-Plotting-Maps version 0.01
=  ==  ==  ==  ==  ==  ==  ==  ==  ==  ==  ==  ==  ==  ==  ==  ==

The README is used to introduce the module and provide instructions on
how to install the module, any machine dependencies it may have (for
example C compilers and installed libraries) and any other information
that should be provided before the module is installed.

A README file 
 is required for CPAN modules since CPAN extracts the
README file from a module distribution so that people browsing the
archive can use it get an idea of the modules uses. It is usually a
good idea to provide version information here so that people can
decide whether fixes for the module are worth downloading.

INSTALLATION

To install this module type the following:

   perl Makefile.PL
   make
   make test
   make install

DEPENDENCIES

This module requires these other modules and libraries:

  blah blah blah

COPYRIGHT AND LICENSE

Put the correct copyright and license information here.

Copyright (C) 2005 by Ginger Grant

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl Version 5.8.7 or,
at your option, any later version of Perl 5 you may have available.

Obviously, you will want to edit this file to be whatever you want it to be. The phrase "blah blah blah" is often used in the templates to indicate things that must be changed.[*] If we leave unchanged the blah blah blah and other placeholder notes from h2xs, potential users will suspect that bugs in our code have also escaped our scrutiny, so we should proofread this stuff (along with our code) before we distribute our module.

[*] When you're bored, you might find it amusing to do a search on CPAN for all places in which blah blah blah occurs.

Pay special attention to the copyright and license section. (It should have your name in place of Ginger's name, unless your machine is very confused about who is sitting at the keyboard.) Your employer may require you to change the copyright notice to include your company name rather than your name, for example. Or, if you're including someone else's code in your module, you may need to mention their copyright (or lack thereof) as well.

The README file also has a special responsibility: the master CPAN archiving tools pull out the README file as a separate entry automatically, permitting the search engines on the various worldwide archives to index them. The CPAN installation tools can download it and display it without downloading the entire distribution. In the CPAN.pm shell, for example, you can say:[Section 16.2.  Using h2xs]

[Section 16.2.  Using h2xs] Well, you would be able to do this, if there were actually a module on CPAN named Island::Plotting::Maps.

$ perl -MCPAN -eshell
cpan> readme Island::Plotting::Maps

In CPANPLUS, the successor to CPAN.pm, we do something similar:

$ perl -MCPANPLUS -eshell
cpanp> r Island::Plotting::Maps

Depending on your version of Perl, you might have the cpan or cpanp programs:

$ cpan
cpan> readme Island::Plotting::Maps

16.2.3. Changes

The Changes file tracks the evolution of our code. Users typically check this file to see what's new with the module and to decide if they want to upgrade.[*] In this file, we note any bugs we fixed, features we added, and how important the changes are (i.e., should everyone upgrade right away?).

[*] Why not upgrade? Some people are content, and rightfully so, with something they already know works. Why chance breaking anything if you don't need to?

$ cat Changes
Revision history for Perl extension Island::Plotting::Maps.

0.01  Wed Oct 16 15:53:23 2002
        - original version; created by h2xs 1.22 with options
                -XAn Island::Plotting::Maps

We need to maintain this file manually unless our interactive development environment has automated tools for such maintenance. We can also use this file to help us track changes and their effects: if we realize that a certain bug turned up three releases back, we can look here to remind ourselves of new features or bug fixes that we introduced in that release.

16.2.4. META.yml

Recent versions of the module tools create a file named META.yml that presents the module information in a human-readable form that is also easy to parse. It uses the YAML format we told you about in Chapter 6.

# http://module-build.sourceforge.net/META-spec.html
#XXXXXXX This is a prototype!!!  It will change in the future!!! XXXXX#
name:         HTTP-Size
version:      0.91
version_from: lib/Size.pm
installdirs:  site
requires:
        HTML::SimpleLinkExtor:         0
        HTTP::Request:                 0
        URI:                           0

distribution_type: module
generated_by: ExtUtils::MakeMaker version 6.17

In this case, ExtUtils::MakeMaker automatically created this file for me. When we create the distribution archive, the Makefile creates this file, ensures that it's in MANIFEST, and includes it in distribution. Other tools and services, including the ones we cover in Chapter 19, can use this file to discover things about the module without having to run any of the distribution code. There is a lot more to this file, and its format documentation reference is right there in the file.

16.2.5. The Prototype Module Itself

Finally we come to the most important part of the distribution, which is the actual code:

package Island::Plotting::Maps;

It looks good so far. The module automatically starts with an appropriate package directive. Following that, we get the standard, good-practice pragmas.

use 5.008007;
use strict;
use warnings;

Now we're declaring that the module is compatible with Perl 5.8.7 or later and that the compiler restrictions and warnings are enabled automatically. We like to encourage good practices. Obviously, we're free to delete or modify anything inappropriate. If we know that our module works with earlier versions of Perl, we can modify the use 5.008007; line (or delete it altogether).

Next comes the mechanism by which we can make our functions and variables show up in the package that called the module. The Exporter function takes care of all of that for us by providing the import method that we talked about in Chapter 15.

require Exporter;

our @ISA = qw(Exporter);

This is fine for non-object-oriented modules, but object-oriented modules typically don't export anything since they require the user to call methods on an object. We'll replace the Exporter lines with one that declares the class that we inherit from, if any.

use base qw(Geo::Maps);

We have to include some information for Exporter, and h2xs sets that up for us. We have to fill in (or not fill in) three variables:

our %EXPORT_TAGS = ( 'all' => [ qw(

) ] );

our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );

our @EXPORT = qw(

);

The @EXPORT array contains the names of all the variables and subroutines that use will automatically import into the caller by default. All of those show up in the calling package unless we tell use otherwise.

use Island::Plotting::Maps;  # import everything in @EXPORT

We won't get anything imported if we give use an empty import list.

use Island::Plotting::Maps (  );  # import nothing

The @EXPORT_OK array contains the names of all the variables and subroutines that use can import if the user asks for them by name (and @EXPORT_OK implicitly contains @EXPORT). If the variables or subroutines are not in one of these arrays, use won't be able to import them.

use Island::Plotting::Maps (  );  # import nothing

The %EXPORT_TAGS hash lets us give names to sets of variables and functions so we can export groups of symbols without making the user type too much. The keys to %EXPORT_TAGS are the group labels, and the hash values are anonymous arrays of symbols that belong to that tag. In the use statement's import list, we include the tag name preceded by a colon.[*]

[*] Technically, you don't need :all because /^/ (include all symbols that match at least a beginning of string) does the same. Many people are familiar with typing :all, and it's far more self-documenting than /^/ is, so include it if you can.

use Island::Plotting::Maps qw(:all)

After the Exporter setup, we get the version number for our new module.

our $VERSION = '0.01';

This version number is important for many reasons, and we need to pay special attention to it. Choose the version number carefully, because many other things use it and depend on it:


Unique identification

The version number identifies a particular release of a particular module as it floats around the Internet.


Filename generation

The archive of the distribution includes the version number of the primary module by default. PAUSE won't let us upload the same filename twice, either, so if our code changes but our version number doesn't, we'll have some trouble there.


Upgrade indication

Generally, numbers that increase numerically supersede previous versions. For this test, the number is considered a floating-point number, so 2.10 (which is really 2.1) is less than 2.9 (which must be the same as 2.90, by the same logic). To avoid confusion, if we've have two digits after the decimal point in one release, we should have two digits in the next release.[Section 16.2.  Using h2xs]

[Section 16.2.  Using h2xs] Perl Best Practices recommends using a three-part version string, such as qv(1.2.3), but their use is not widespread, requires version.pm (a non-core module as of Perl 5.8), does not integrate with common tools yet, and has lexical issues.


Interface stability

Generally, numbers that begin with 0 are alpha or beta, with external interfaces that may still be in flux. Also, most people use a major version number change (from 1.x to 2.x, etc.) to indicate a potential break in upward compatibility.


Recognition by the various CPAN tools

The CPAN distribution management tools use the version number to track a particular release, and the CPAN installation tools can determine missing or out-of-date distributions.


Perl's own operators

The use operator can be given a version number in addition to (or instead of) the import list, forcing the use operation to fail if the imported module is not equal to or greater than that version:

use Island::Plotting::Maps 1.10 qw{ map_debugger };

Generally, you can start with the 0.01 given by the template and increase it consistently with each new test release.[*] Now you're past the header information and down to the core of your module. In the template, it is indicated by a simple comment:

[*] The perlmod page includes an example that extracts the CVS/RCS version number for the module's version number.

# Preloaded methods go here.

What? You didn't think the h2xs tool would even write the module for you, now did you? Anyway, this is where the code goes, usually as a series of subroutines, possibly preceded by some shared module data (using my declarations) and perhaps a few package variables (using our declarations in recent Perl versions). Following the code, you'll find your necessary true value:

1;

so the require (inside the use) doesn't abort.


Previous
Table of Contents
Next
© 2000- NIV