Makefile.PL as a modulino

A Perl distribution’s build file is often a neglected program. The community has standards for code in the modules, but we ignore quality (or kwalitee) in Makefile.PL, the test programs, and other ancillary code.

Much of my work in CPAN Archeology has dealt with figuring out what data goes into WriteMakefile. In Test::Prereq, I took the heavy-handed and ham-fisted approach of monkey patching ExtUtils::MakeMaker just to intercept its arguments. In MyCPAN::Indexer, I run the build file and look at the generated META files. That comes with many other problems.

It struck me, yesterday, that this is a perfect candidate for a modulino, a program that can act like a module. If I call it as a program, it acts like the build program. If I load it as a module, however, I can access the arguments that it would pass to WriteMakefile without triggering the build.

I’m trying this with ReturnValue, a small module to return structured results. You can see more about that in Return error objects instead of throwing exceptions, my StackOverflow answer to Is Try::Tiny still recommended for exception handling in Perl 5.14 or later?, and my PrePAN entry for that module. The particulars of the module don’t matter for this post though.

Here’s how I put it together:

#!perl
use v5.014;
use utf8;

package ReturnValue;
use strict;
use warnings;


my $github    = 'https://github.com/briandfoy/ReturnValue';
my $main_file = 'lib/ReturnValue.pm';

my %WriteMakefile = (
	'NAME'	        => 'ReturnValue',
	...
	);

sub arguments { \%WriteMakefile }

do_it() unless caller;
sub do_it {
	my $MM ='ExtUtils::MakeMaker';
	my $MM_version =
		eval{ "$MM " . $WriteMakefile{'CONFIGURE_REQUIRES'}{'ExtUtils::MakeMaker'} }
			//
		"$MM 6.64";
	eval "use $MM_version";
	eval "use Test::Manifest 1.21";
	WriteMakefile( %WriteMakefile );
	}


no warnings;
__PACKAGE__;

Now it’s a modulino. I develop the data structure but don’t do anything with it. I can load it as a module:

my $package = require 'Makefile.PL';

my $write_makefile_hash = $package->arguments;

I now have that information without going through everything to create the META files. I can use this from tools that go through several distributions to check things.

I expect this to work for almost all of my distributions. If the file needs all sorts of tricky configuration and module loading, this is problem too much of a hassle. In those cases, though, I can probably make other improvements to get around that.