Stories
Slash Boxes
Comments
NOTE: use Perl; is on undef hiatus. You can read content, but you can't post it. More info will be forthcoming forthcomingly.

All the Perl that's Practical to Extract and Report

use Perl Log In

Log In

[ Create a new account ]

Matts (1087)

Matts
  (email not shown publicly)

I work for MessageLabs [messagelabs.com] in Toronto, ON, Canada. I write spam filters, MTA software, high performance network software, string matching algorithms, and other cool stuff mostly in Perl and C.

Journal of Matts (1087)

Tuesday December 18, 2001
10:57 AM

Makefile.PL best practices

[ #1707 ]

I've been writing a *lot* of perl modules lately (mostly internal stuff), and so I've been thinking a lot about what are the best practices for writing modules... Here's my random thoughts:

1. Don't use h2xs. It just sucks so bad. Here's my recipe for creating a new perl module:

    mkdir <ModuleName>
    cd <ModuleName>
    mkdir t
    mkdir lib
    mkdir lib/<ModuleName> (make any subdirs too)
    touch README MANIFEST MANIFEST.SKIP Makefile.PL Changes

    touch lib/<ModuleName>.pm
    touch t/00basic.t

Note that sometimes there you'll need to make more directories under lib/ if your module is deeply nested.

2. Edit Makefile.PL to look something like:

    use ExtUtils::MakeMaker;
    WriteMakefile(
        'NAME' => '<ModuleName>',
        'VERSION_FROM' => 'lib/<ModuleName>.pm',
        'PREREQ_PM' => {},
        'ABSTRACT_FROM' => 'lib/<ModuleName>.pm',
        'AUTHOR' => 'Matt Sergeant <matt@sergeant.org>',
    );

Note that I don't put any of the *useless* comments in that h2xs gives you... I mean, really do we need VERSION_FROM to have a comment that says "finds $VERSION" ???

3. Edit t/00basic.t to look something like:

    use Test;
    BEGIN { plan tests => 1 }
    END { ok($loaded) }
    use <ModuleName>;
    $loaded++;

4. Edit MANIFEST.SKIP to look something like:

    CVS/.*
    \.bak$
    \.sw[a-z]$
    \.tar$
    \.tgz$
    \.tar\.gz$
    ^mess/
    ^tmp/
    ^blib/
    ^Makefile$
    ^Makefile\.[a-z]+$
    ^pm_to_blib$
    ~$

5. Start editing lib/<ModuleName>.pm

I'm not going to tell you how to write a module here. But once again, a lot of the h2xs cruft I used to manually remove by hand, but now I just write my own module, making sure I use strict, end in "1;", and add some POD.

Now run perl Makefile.PL, then make manifest, then make realclean.

A couple of the "best practices" that the above does, that I consider important are:

1. You get the lib/ structure for your module, rather than the default h2xs method of dumping .pm files in the main directory of your project. This allows you to do fast direct testing using perl -Mlib=lib -M -e 'test code'

2. You start off right away with tests in the t/ directory, and they use the Test.pm module. Note some often un-mentioned features of Test::Harness - the ability to specify TEST_VERBOSE=1 and TEST_FILES=t/01foo.t on the command line, which gives you more verbose output, and the ability to do individual tests without having to run your entire test suite:

    make test TEST_VERBOSE=1 TEST_FILES=t/01foo.t

This will also tell you exactly where the test failure was (a line number) and why it failed, if you're using Test.pm's ok() function (e.g. "got 'flugebar', expected 'dungbeetle'").

The only thing I really miss is the ability to have .xs files deep in the hierarchy. I think this is a MakeMaker bug in not allowing that.

Anyway, hope this helps someone.

The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
 Full
 Abbreviated
 Hidden
More | Login | Reply
Loading... please wait.
  • #!/usr/local/bin/perl5.6.1

    use warnings;
    use strict;

    my($MODNAME) = @ARGV;

    mkdir($MODNAME);
    chdir($MODNAME);
    mkdir("t");
    mkdir("lib");
    mkdir("lib/$MODNAME");
    my $fh;
    foreach my $file (qw(README MANIFEST MANIFEST.SKIP Makefile.PL Changes))
    {
        open($fh, ">$file");
    }
    open($fh, ">lib/$MODNAME.pm");
    open($fh, ">t/00basic.t");

    open($fh, ">Makefile.PL") || die "Can't open Makefile.PL: $!";
    print $fh <<"EOF";
    use ExtUtils::MakeMaker;
    WriteMakefile(
            'N
    --
    J. David works really hard, has a passion for writing good software, and knows many of the world's best Perl programmers
    • Matt, can't tell you how helpful you've been to me in the past. Hope this helps you a little, or at least spurs some further thought. :) Obviously I'll be immediately updating my own personal copy of this not to say matt@sergeant.org for AUTHOR.

      Being the freak that I am, I'll also probably add strict and warnings to the test script, and add the package $MODNAME; and 1; statements into $MODNAME.pm.

      --
      J. David works really hard, has a passion for writing good software, and knows many of the world's best Perl programmers
    • One thing this misses is the schizophrenic relationship in here between module name and module path - something I washed over in my journal entry.
      • Yes. I started thinking about that and then decided I would never get the program written, let alone posted, if I handled that issue.

        But, as the rough rocks in a stream get worn down smooth, I'm sure I will walk across that enough times in the future I (or someone else) will be motivated to fix that.

        Hmmmmm. How about Inline::Files to hold to contents of all those files that get set up?

        --
        J. David works really hard, has a passion for writing good software, and knows many of the world's best Perl programmers
      • Done. :) It's in my journal, but I'm not sure if anyone's seen it. Am I the only one who ever looks at journals at random? I've got the journals slashbox at the top on my page.

        --
        J. David works really hard, has a passion for writing good software, and knows many of the world's best Perl programmers
        • Don't know about other people, but my RSS fetcher regularly grabs the list of most recently changed journals and incorporates them into a news feed. It's somewhat indiscriminate in that it includes everyone, not just 'friends'. But that's good =)

          It would be nice to see a feature that lists journal entries since a particular date.
          --
            ---ict / Spoon