Squirrel Logo

MakeMaker made easy

Johan Vromans
Articles


This document describes how Perl's MakeMaker facility can be used to provide a Makefile to easily install your Perl modules and scripts.

Copyright 1999 Johan Vromans, Squirrel Consultancy.

Introduction

Most Perl modules and scripts come in packages, usually compressed (gzipped) tar archives. To install such a package, the following commands are required (on a Unix system):

    perl Makefile.PL
    make all; make test
    make install

This sounds easy, and, in fact, it is easy. Until you try to roll your own Makefile.PL for your own package...

The quick way

With a couple of simple guidelines a setup can be quickly realised that satisfies the MakeMaker facility. Of course, there is more than one way to do it...

As an example I will use the PostScript::Font package. This package contains three modules, PostScript::Font, PostScript::FontMetrics and PostScript::FontInfo, and three scripts: fontsampler, pfb2pfa and pfa2pfb. For this, I have set up a source directory PostScript-Font, that contains the following directories:

  • lib, a place where the modules are kept,
  • script, where the scripts are kept, and
  • t, where the test programs are kept.

The source directory itself contains the Makefile.PL (more about this file later) and the file MANIFEST, essentially a list of all files that constitute the package.

The module PostScript::Font is phisically located in a file PostScript/Font.pm, likewise for the other modules. The list of files that constitute the package is:

    MANIFEST
    Makefile.PL
    lib/PostScript/Font.pm
    lib/PostScript/FontMetrics.pm
    lib/PostScript/FontInfo.pm
    script/fontsampler
    script/pfb2pfa
    script/pfa2pfb
    t/basic.t

The contents of Makefile.PL are:

    use ExtUtils::MakeMaker;
    WriteMakefile (
       NAME         => 'PostScript::Font',
       VERSION      => "0.03",
       EXE_FILES    => [ qw(script/fontsampler script/pfb2pfa script/pfa2pfb) ],
     );

First of all, the 'use' statement loads the MakeMaker facility and makes it available to Makefile.PL, which is just a little Perl program.

Then the function WriteMakefile is called. This function will write the actual Makefile. It is passed a hash with attributes:

  • NAME, the name of the package. This is used to name the archive for distributions.
  • VERSION, the version number of the package.
  • EXE_FILES, an array reference containing the names of the script files.

Note that the modules are not mentioned. This is because WriteMakefile looks for modules (files with names that end with '*.pm', in the current directory as well as in a subdirectory lib. And that is precisely where the module files are kept.

Let's give it a try.

    % perl Makefile.PL
    Checking if your kit is complete...
    Looks good
    Writing Makefile for PostScript::Font

What happened? MakeMaker has first checked if your kit is complete. It does that by reading the file MANIFEST and veify that each file mentioned in here is present. Then it wrote the Makefile. So now we can do a make.

    % make
    mkdir blib
    mkdir blib/lib
    mkdir blib/lib/PostScript
    mkdir ...some more directories...
    mkdir blib/man1
    mkdir blib/man3
    cp lib/PostScript/FontMetrics.pm blib/lib/PostScript/FontMetrics.pm
    cp lib/PostScript/Font.pm blib/lib/PostScript/Font.pm
    cp lib/PostScript/FontInfo.pm blib/lib/PostScript/FontInfo.pm
    Manifying blib/man3/PostScript::FontMetrics.3
    Manifying blib/man3/PostScript::Font.3
    Manifying blib/man1/pfb2pfa.1
    Manifying blib/man1/pfa2pfb.1
    Manifying blib/man3/PostScript::FontInfo.3
    Manifying blib/man1/fontsampler.1
    mkdir blib/script
    cp script/pfa2pfb blib/script/pfa2pfb
    perl -MExtUtils::MakeMaker -e "MY->fixin(shift)" blib/script/pfa2pfb
    cp script/pfb2pfa blib/script/pfb2pfa
    perl -MExtUtils::MakeMaker -e "MY->fixin(shift)" blib/script/pfb2pfa
    cp script/fontsampler blib/script/fontsampler
    perl -MExtUtils::MakeMaker -e "MY->fixin(shift)" blib/script/fontsampler

Impressive, isn't it? We see that the following things happened:

  • A new directory blib is created, with a lot of subdirectories. This is where everything gets prepared.
  • The modules from the lib directory are copied into the lib directory under blib. We see that MakeMaker did find all of our modules.
  • Unix-style man (manual) pages are produced from the embedded documentation in the modules and scripts.
  • The scripts are copied from the script directory to blib/script, and Perl is invoked with another of MakeMaker's facilities. fixin will adjust the first line of the script, usually containing something like '#!perl', to the value required for the current Perl installation, e.g. '#!/usr/local/bin/perl'.

Next, we can test the package:

    % make test
    perl -Iblib/lib -e 'use Test::Harness; runtests @ARGV;' t/*.t
    t/basic.............ok
    All tests successful. Files=1,  Tests=6

What happens is that Perl runs all scripts in the directory t with names '*.t' using a special testing harness. Only one test was supplied, and it completed okay. So it is now safe to install the package. This usually requires super user privilege:

    # make install
    Installing /usr/lib/perl5/site_perl/5.005/PostScript/FontMetrics.pm
    Installing /usr/lib/perl5/site_perl/5.005/PostScript/Font.pm
    Installing /usr/lib/perl5/site_perl/5.005/PostScript/FontInfo.pm
    Installing /usr/man/man1/pfb2pfa.1
    Installing /usr/man/man1/pfa2pfb.1
    Installing /usr/man/man1/fontsampler.1
    Installing /usr/lib/perl5/5.00502/man/man3/PostScript::FontMetrics.3
    Installing /usr/lib/perl5/5.00502/man/man3/PostScript::Font.3
    Installing /usr/lib/perl5/5.00502/man/man3/PostScript::FontInfo.3
    Installing /usr/bin/pfa2pfb
    Installing /usr/bin/pfb2pfa
    Installing /usr/bin/fontsampler
    Writing /usr/lib/perl5/site_perl/5.005/i586-linux/auto/PostScript/Font/.packlist
    Appending installation info to /usr/lib/perl5/5.00502/i586-linux/perllocal.pod

Another thing we can do is create a new package for distribution:

    % make tardist
    rm -rf PostScript-Font-0.03
    perl -MExtUtils::Manifest=manicopy,maniread \
      -e "manicopy(maniread(),'PostScript-Font-0.03', 'best');"
    mkdir PostScript-Font-0.03
    mkdir PostScript-Font-0.03/lib
    mkdir PostScript-Font-0.03/lib/PostScript
    mkdir PostScript-Font-0.03/script
    mkdir PostScript-Font-0.03/t
    tar cvf PostScript-Font-0.03.tar PostScript-Font-0.03
    PostScript-Font-0.03/
    PostScript-Font-0.03/lib/
    PostScript-Font-0.03/lib/PostScript/
    PostScript-Font-0.03/lib/PostScript/Font.pm
    PostScript-Font-0.03/lib/PostScript/FontMetrics.pm
    PostScript-Font-0.03/lib/PostScript/FontInfo.pm
    PostScript-Font-0.03/script/
    PostScript-Font-0.03/script/pfa2pfb
    PostScript-Font-0.03/script/pfb2pfa
    PostScript-Font-0.03/script/fontsampler
    PostScript-Font-0.03/t/basic.t
    PostScript-Font-0.03/MANIFEST
    PostScript-Font-0.03/Makefile.PL
    PostScript-Font-0.03/README
    rm -rf PostScript-Font-0.03
    gzip --best PostScript-Font-0.03.tar

Using the Manifest facility, a temporary, directory hierarchy is set up named PostScript-Font-0.03. This name is formed from the NAME and VERSION attributes that were passed to WriteMakefile in the Makefile.PL. Perl copies all files that constitute the package into this directory, and creates a gzipped tar archive with name PostScript-Font-0.03.tar.gz from it. It then cleans up the temporary directory.

Writing the test scripts

Test scripts are important, since they can verify that a package was correctly installed. Writing test scripts can be quite complex, depending on the functionality of the package.

With regard to the test harness that runs the test scripts, each script has to print a line to the standard output that denotes the number of tests in this script, for example: '1..6', meaning that there are 6 tests, numbered from 1 through 6. For each test that runs okay, the script must produce a single line of output: 'ok n', where n is the number of the test. Any other output is considered test failure.

Real life

Reality is not always as simple. Although everything described above is perfectly okay, my real set up is a little more complicated, though not much.

First of all, I have a directory src in which I maintain all sources, the modules and the scripts. The files under the lib and script directories are just symlinks to the actual sources.

Also, all sources are under version control. In the main directory a subdirectory RCS keeps the version control files. For convenience, in directory src, a symlink is made to the upper RCS directory.

Finally, I have a README file, and a directory Released that contains the packages (the gzipped tar files) of every version I released to the Internet. So this is the actual list of files:

    MANIFEST
    Makefile.PL
    RCS/Font.pm,v
    RCS/FontInfo.pm,v
    RCS/FontMetrics.pm,v
    RCS/MANIFEST,v
    RCS/Makefile.PL,v
    RCS/fontsampler.pl,v
    RCS/pfb2pfa.pl,v
    README
    Released/PostScript-Font-0.02.tar.gz
    Released/PostScript-Font-0.03.tar.gz
    lib/PostScript/Font.pm -> ../../../src/Font.pm
    lib/PostScript/FontInfo.pm -> ../../../src/FontInfo.pm
    lib/PostScript/FontMetrics.pm -> ../../../src/FontMetrics.pm
    script/fontsampler -> ../../src/fontsampler.pl
    script/pfa2pfb -> ../../src/pfb2pfa.pl
    script/pfb2pfa -> ../../src/pfb2pfa.pl
    src/Font.pm
    src/FontInfo.pm
    src/FontMetrics.pm
    src/RCS -> ../RCS
    src/fontsampler.pl
    src/pfb2pfa.pl

Indeed, pfb2pfa and pfa2pfb are one single program.

Also, Makefile.PL has a little bit more info in it:

    # Verify perl version.
    require 5.000;
    use ExtUtils::MakeMaker;
    my @scripts = qw(fontsampler pfb2pfa pfa2pfb);
    WriteMakefile
      (
       NAME      => 'PostScript::Font',
       ($[ >= 5.005) ?
       (AUTHOR   => 'Johan Vromans (jvromans@squirrel.nl)',
        ABSTRACT => 'Modules to get info from PostScript fonts') : (),
       VERSION   => "0.03",
       PREREQ_PM => { 'Getopt::Long' => 2.00, 'IO' => 0 },
       EXE_FILES => [ map { "script/$_" } @scripts ],
       # *.pm files will be picked up automatically from ./lib
     );

Major additions are:

  • Checking the Perl version.
  • Using an array @scripts to hold the names of the scripts. A map is used to prepend 'script/' in front of each name for the EXE_FILES attribute.
  • An AUTHOR and ABSTRACT attribute, but only if Perl is 5.005 or newer.
  • A PREREQ_PM attribute that defines which modules are required by this package, and optionally the version this module must at least have.

Pitfalls

WriteMakefile does a great job in making one's life easy. Unfortunately, it can be too helpful.

Do not place files with extension '.pl' or '.pm' in the main directory, or they will be picked up by WriteMakefile and produce unexpected results.

Also, do not place any Makefile.PL in any other directory (notably not in the src directory), for the same reason.

Copyright 1998,2004 Squirrel Consultancy.
Creative Commons License
This work is licensed under a Creative Commons License.


© Copyright 2003-2018 Johan Vromans. All Rights Reserved.
articles/makemaker.html last modified 21:51:10 26-Feb-2007