How2 - create a PPM distribution - 0.2


This is to give you some information on how to make a PPM distribution. This is an unofficial document based on my own findings and suggestions from the mailing list.


The .ppd file may be generated by :

        perl Makefile.PL
        nmake ppd
        nmake ppd BINARY_LOCATION=Module.tar.gz

If you use the first, you'll have to edit the resulting .ppd and add the name of the archive into <CODEBASE HREF=``...'' /> (The HREF should be relative to the location of the ppd file.)

You should specify the AUTHOR and ABSTRACT parameters in the Makefile.PL so that they are present in the ppd and may be searched through! Be forewarned though that these parameters were added only in 5.005 so older perls will not like them. You should pass them to WriteMakefile only if the ($] ge '5.005').

Example Makefile.PL\Makefile.PL :
 use ExtUtils::MakeMaker;
     'NAME'      =? 'Deurl',
     'VERSION_FROM' =? '', # finds $VERSION
     ($] ge '5.005')
     ? (
      'AUTHOR' =? 'Jan Krynicky (',
      'ABSTRACT' =? 'Decode the parameters passed to a CGI',
     : (),


 use ExtUtils::MakeMaker;
 @if5005 = (
     'AUTHOR' => 'Jan Krynicky (',
     'ABSTRACT' => 'Ask for HTTP authentification unless condition holds',
 ) if $] ge '5.005';
    'NAME'      => 'Authent',
    'VERSION_FROM' => '', # finds $VERSION
    'NEEDS_LINKING' => 0,
    'dist' => {COMPRESS => 'gzip -9f', SUFFIX => 'gz'},


The archive referenced in .ppd should contain the blib directory that's created when you run

        perl Makefile.PL

Of course you may use dmake or standard make, but if you do you have to change the settings in ...\perl\lib\ Search for line


and change it to


You may get nmake from .

You should also create a directory ...\blib\html\lib\ and place the HTML documentation for the module there.

For example for Mail::Sender I generate Sender.html by pod2html.bat and save it as ...\blib\html\lib\Mail\Sender.html. This way the documentation will be linked from the module list in ...\perl\html\perltoc.html

The blib directory should then be compressed using tar and gzip. I do include the version number in the name, ActiveState doesn't, it's up to you. Just keep in mind that the .ppd file MUST contain correct archive name!

The archive may be created by

 tar cvf ArchiveName.tar blib
 gzip --best ArchiveName.tar

You can get tar and gzip for example from


To set up a PPM repository all you have to do is to copy the .ppd files and .tar.gz archives to a webserver and enable directory listing to the directory where are the ppd files. You may have both .ppd files and the archives in the same directory (then the <CODEBASE HREF=...> is just the archive name) or in a different directory (then the <CODEBASE HREF=...> is the relative URL of the archive).

If you want to set it up for VPM (Visual Package Manager) as well you need to get default.prk from ActiveState, set it up to be executed as a perl script and save it in the same directory where are the .ppd files.

If you do not want to create your own repository you may send the .ppd and .tar.gz to me and I'll add it to my repository.

My way

I use the script below to generate both ordinary distributions and PPM distributions at once.

This process creates three files :

 ModuleName-version.tar.gz = ordinary distro
 ModuleName.ppd = the ppd description file
 ModuleName-version-PPM.tar.gz = the archive for PPM

If you add line with


into ...\perl\lib\, or to system varibles, it will be used as the directory where you store the archives. For example if you have the ppd files in and the archives in, the variable should contain 'x86'. 2.0
        use FileHandle;
        use File::DosGlob qw(glob);
        use Win32::FileOp;
        END {print "\nDONE -- PRESS ENTER\n";<STDIN>};
        my $has_xs = 0;
        #unixify files
                opendir my $DIR, '.' or die "Can't read current directory: $!\n";
                my $file ;
                while (defined($file = readdir $DIR)) {
                        $has_xs = 1 if $file =~ /\.xs$/i;
                        next unless $file =~ /\.(?:pm|pl|xs|t|html|htm|txt)$/i or $file =~ /^(?:MANIFEST|Changes)$/i;
                        open my $FILE, "<".$file or die "Can't open file $file : $!\n";
                        binmode $FILE;
                        my $line = <$FILE>;
        #               next unless $line =~ /\r/;
                        open my $OUT, ">".$file.".tmp" or die "Can't create file $file.tmp : $!\n";
                        binmode $OUT;
                        while (defined $line) {
                                $line =~ s/\r?\n?$//;
                                print $OUT $line,"\x0A";
                                $line = <$FILE>
                        close $FILE;
                        close $OUT;
                        unlink $file;
                        rename $file.'.tmp' => $file;
        system('perl Makefile.PL');
        system($make) and die "Failed to make!\n";
        system($make, 'dist'); # this creates the ordinary distribution
        # I need the archive to find the version number!
        # If you comment this out, always copy the archive to current directory.
        # this part of code finds the latest distribution, I don't have time to
        # explore how to find the version number
        @archives = grep {!/-PPM\.tar\.gz$/i} <*.tar.gz>;
        $archive = findNewest (@archives);
        ($name = $archive) =~ s/\.tar\.gz$//;
        ($module = $name) =~ s/-[\d.]+$//;
        ($file = $module) =~ s/^.*-(.*?)$/$1/;
        $ppd = $module.".ppd";
        $module =~ s/-/\\/g;
        print "Module name : $file\n";
        print "Newest archive is $archive\n";
        system('perl','Makefile.PL', "BINARY_LOCATION=$name-PPM.tar.gz");
        system($make, 'ppd');
        # you may do something like
        # system($make, 'ppd', "BINARY_LOCATION=$name-PPM.tar.gz");
        # if you do not apply my patch to ExtUtils\
        print (qq{pod2html.bat "-htmlroot=." "$" "-outfile=$file.html"\n});
        system(qq{pod2html.bat "-htmlroot=." "$" "-outfile=$file.html"});
        #mkdir 'blib/html'; # not necessary
        Copy "$file.html" => "$";
        Move "$file.html" => "blib/html/site/lib/$module.html";
        system(qq{pod2text.bat "$" "$"});
        system("tar cvf $name-PPM.tar blib");
        system("gzip --best $name-PPM.tar");
        Delete qw(blib pod2html-dircache pod2html-itemcache pm_to_blib pod2htmd.x~~ pod2htmi.x~~);
        if (! $has_xs) {
                open $PPD, "<$ppd" or die "Can't open the $ppd file: $!\n";
                open $NEWPPD, ">$ppd.tmp" or die "Can't create the $ppd.tmp file: $!\n";
                while (<$PPD>) {
                        next if (/<ARCHITECTURE/);
                        print $NEWPPD $_;
                close $PPD; close $NEWPPD;
                unlink $ppd;
                rename $ppd.'.tmp' => $ppd;
        sub findNewest {
                my $maxitem;
                my $maxver = pack('C4',0,0,0,0);
                foreach my $item (@_) {
                        $item =~ /-(\d+)\.(\d+)\.(?:(\d+)\.(?:(\d+)\.)?)?tar\.gz/;
                        my $ver = pack('C4',$1,$2,$3,$4);
                        if ($ver gt $maxver) {
                                $maxver = $ver;
                                $maxitem = $item;
                return $maxitem;


``Jan Krynicky'' <>


Copyright (c) 2002 ``Jan Krynicky'' <>. All rights reserved.