1 # (X)Emacs mode: -*- cperl -*-
8 make - tools for making makefiles with.
12 use constant MOD_REQS =>
14 { name => 'Pod::Usage',
21 { name => 'DBI::Wrap',
22 package => 'DBI-Wrap',
27 use constant EXEC_REQS =>
31 vopt => '--version', },
33 { name => 'mkprofile', },
41 use constant NAME => 'Module-Name';
42 use constant VERSION_FROM => catfile (qw( lib Module Name.pm ));
43 use constant AUTHOR => 'Martyn J. Pearce fluffy@cpan.org';
44 use constant ABSTRACT => 'This module makes chocolate biscuits';
50 This package provides methods and initialization to build standard perl
53 The plan is, you define the requirements, and let the module take care of the
56 The requirements you must define are:
62 An arrayref of hashrefs. Each hashref represents a required Perl module, and
63 has the following keys:
69 B<Mandatory> Name of the module used. The presence of this module is checked,
70 and an exception is raised if it does not exist.
74 B<Optional> Name of the package in which the module is to be found. If not
75 defined, the package is assumed to be present in core Perl.
77 Modules that have been in core Perl since 5.005 need not be listed; the "core
78 perl" default is for modules such as C<Pod::Usage> which have been added to
83 B<Optional> If supplied, the version of the module is checked against this
84 number, and an exception raised if the version found is lower than that
89 B<Optional> If true, then failure to locate the package (or a suitable
90 version) is not an error, but will generate a warning message.
94 If supplied, then this message will be given to the user in case of failure.
104 Name of the executable used. The presence of this executable is checked, and
105 an exception is raised if it does not exist (in the PATH).
109 B<Optional> Name of the package in which the executable is to be found.
113 B<Optional> If supplied, the version of the module is checked against this
114 number, and an exception raised if the version found is lower than that
117 If supplied, the L<vopt> key must also be supplied.
121 B<Optional> This is used only if the C<version> key is also used. This is the
122 option that is passed to the executable to ask for its version number. It may
123 be the empty string if no option is used (but must be defined if C<version> is
128 B<Optional> This is used only if the C<version> key is also used. This is the
129 exit code to expect from the program when polling for its version number.
130 Defaults to 0. This is the exit code (value of C<$?> in the shell) to use,
131 I<not> the value of the C<wait> call.
135 B<Optional> If true, then failure to locate the package (or a suitable
136 version) is not an error, but will generate a warning message.
140 If supplied, then this message will be given to the user in case of failure.
146 The module name. It must conform to the established standard; in particular,
147 it must B<not> contain colon characters. The usual process, when providing a
148 single-package module (e.g., to provide C<MIME::Base64>), is to replace the
149 C<::> occurences with hyphens (hence, C<MIME-Base64>).
153 The module from which to establish the version number. This module must have
154 a line of the form C<$VERSION = '0.01';>. Declarative prefixes (.e.g, C<our>)
155 are fine; C<our> is the usual one, since C<$VERSION> is almost always a
160 The name of the module author(s), along with an email address. This is
161 normally the person primarily responsible for the upkeep of the module.
165 A single (concise!) sentence describing the rough purpose of the module. It
166 is not expected to be mightily accurate, but is for quick browsing of modules.
172 If defined, this must be an arrayref of additional targets to insert into
173 F<Makefile>. Each element must be a hashref, with the following keys:
179 Name of the rule target
183 Arrayref of rule requisites
187 Arrayref of rule lines. Do not precede these with a tab character; this will
188 be inserted for you. Likewise, do not break the lines up.
194 use constant DEPENDS => [
195 { target => 'lib/Class/MethodMaker.pm',
196 reqs => [qw/ cmmg.pl /],
197 rules => [ '$(PERL) $< > $@' ],
203 I<Optional>. If defined, this is expected to be an arrayref of file names
204 (relative to the dist base), that are pm files to be installed.
206 By default, F<make.pm> finds the pms to install by a conducting a C<find> over
207 the F<lib> directory when C<perl Makefile.PL> is run. However, for pm files
208 that are created, that will be insufficient. By specifying extras with this
209 constant, such files may be named (and therefore made), and also cleaned when
210 a C<make clean> is issued. This might well be used in conjunction with the
211 L<DEPENDS|"DEPENDS"> constant to auto-make pm files.
215 use constant DERIVED_PM => [qw( lib/Class/MethodMaker.pm )];
219 use Config qw( %Config );
220 use ExtUtils::MakeMaker qw( WriteMakefile );
221 use File::Find qw( find );
222 use File::Spec qw( );
223 sub catfile { File::Spec->catfile(@_) }
226 # Constants ---------------------------
228 use constant TYPE_EXEC => 'executable';
229 use constant TYPE_MOD => 'module';
230 use constant TYPES => [ TYPE_EXEC, TYPE_MOD ];
232 use constant CONFIG =>
234 TYPE_MOD , { defaults => { package => 'core perl',
236 find => sub { eval "require $_[0]"; $@ eq '' },
239 # Fool emacs indenter
240 my $_x = q={=; my $pv = ${"$_[0]::VERSION"};
241 return defined $pv ? $pv : -1;
244 TYPE_EXEC , { defaults => { vexpect => 0, },
249 for my $path (split /:/, $ENV{PATH}) {
250 my $try = catfile $path, $name;
259 my ($name, $vopt, $expect) = @_;
260 die "Cannot test version of $name without vopt\n"
261 unless defined $vopt;
262 my $cmd = join ' ', $name, $vopt;
263 my $vstr = qx($cmd 2>&1);
265 die sprintf "Command $cmd exited with value: $rv\n"
267 if ( $vstr =~ /(?:^|\D)v?(\d+(?:[._]\d+)+)(?![\d_.])/ ) {
268 (my $version = $1) =~ tr/_/./;
277 # Subrs ----------------------------------------------------------------------
282 my ($type_max) = sort { $b <=> $a } map length $_->{type}, @$missing;
283 my ($name_max) = sort { $b <=> $a } map length $_->{name}, @$missing;
286 my ($type, $name, $pkg, $vers, $pv, $optional, $message) =
287 @{$_}{qw( type name package vers_req vers_fnd optional message )};
290 print STDERR sprintf("%-${type_max}s %${name_max}s requires version " .
294 print STDERR sprintf("Couldn't find %${type_max}s %${name_max}s",
298 print STDERR " (from $pkg)"
302 print STDERR " ...but this isn't fatal\n"
305 if ( defined $message ) {
306 $message =~ s/(^|\n)/$1 /g;
307 $message =~ s/([^\n])$/$1\n/;
309 print STDERR $message;
315 # -------------------------------------
318 my ($items, $verbose) = @_;
320 my ($type_max) = sort { $b <=> $a } map length, @{TYPES()};
321 my ($name_max) = sort { $b <=> $a } map length($_->{name}), @$items;
325 foreach my $item (@$items) {
326 my $type = $item->{type};
327 my $defaults = CONFIG->{$type}->{defaults};
328 $item->{$_} = $defaults->{$_}
329 for grep ! exists $item->{$_}, keys %$defaults;
330 my ($name, $pkg, $vers, $vopt, $vexpect) =
331 @{$item}{qw( name package version vopt vexpect)};
333 printf STDERR "Checking for %-${type_max}s %-${name_max}s...", $type, $name
335 if ( CONFIG->{$type}->{find}->($name) ) {
336 print STDERR " found\n"
339 if ( defined $vers ) {
340 my $vfound = CONFIG->{$type}->{vers}->($name, $vopt, $vexpect);
341 my $str_v_reqd = join '_', map sprintf('%09d',$_), split /\./,$vers;
342 my $str_v_found = join '_', map sprintf('%09d',$_), split /\./,$vfound;
343 push @missing, { type => $type,
348 optional => $item->{optional},
349 message => $item->{message},
351 if $str_v_reqd gt $str_v_found;
354 print STDERR " failed\n"
356 push @missing, { type => $type,
360 optional => $item->{optional},
361 message => $item->{message},
369 # Main -----------------------------------------------------------------------
373 if ( $ENV{MAKE_SELF_TEST} ) {
374 # Find Module (no version)
375 check([{ name => 'integer' , type => TYPE_MOD, }])
376 and die "Internal Check (1) failed\n";
377 # Fail module (no version)
378 check([{ name => 'flubble' , type => TYPE_MOD, }])
379 or die "Internal Check (2) failed\n";
380 # Find module, wrong version
381 check([{ name => 'IO' , type => TYPE_MOD, version => '100.0', }])
382 or die "Internal Check (3) failed\n";
383 # Find module, right version
384 check([{ name => 'IO' , type => TYPE_MOD, version => '1.00', }])
385 and die "Internal Check (4) failed\n";
387 # Find exec (no version)
388 # Use more (common to dog/windoze too!) (mac?)
389 check([{ name => 'more' , type => TYPE_EXEC, }])
390 and die "Internal Check (5) failed\n";
391 # Fail exec (no version)
392 check([{ name => ' wibwib' , type => TYPE_EXEC, }])
393 or die "Internal Check (6) failed\n";
395 # Could do with one that works on dog/windoze/mac...
396 if ( $Config{osname} eq 'linux' ) {
397 # Find exec, wrong version
398 check([{ name => 'cut' , type => TYPE_EXEC,
399 version => '100.0', vopt => '--version', }])
400 or die "Internal Check (7) failed\n";
401 # Find exec, right version
402 check([{ name => 'cut' , type => TYPE_EXEC,
403 version => '1.0', vopt => '--version', }])
404 and die "Internal Check (8) failed\n";
407 # -------------------------------------
413 die "$_ not defined\n"
414 for grep ! defined *$_{CODE}, qw( MOD_REQS EXEC_REQS
415 NAME VERSION_FROM AUTHOR ABSTRACT );
418 die sprintf(<<'END', NAME) unless NAME =~ /^[A-Za-z0-9-]+$/;
419 The module name:%s: is illegal (letters, numbers & hyphens only, please)
422 $_->{type} = TYPE_MOD
424 $_->{type} = TYPE_EXEC
427 push @missing, check(MOD_REQS, 1), check(EXEC_REQS, 1);
429 warn_missing(\@missing);
432 for grep ! $_->{optional}, @missing;
436 $File::Find::prune = 1, return
437 if -d $_ and $_ eq 'CVS';
438 return unless /\.pm$/;
439 (my $target = $File::Find::name) =~
440 s/^$File::Find::topdir/\$(INST_LIBDIR)/;
441 $pm{$File::Find::name} = $target;
453 VERSION_FROM => VERSION_FROM,
455 ABSTRACT => ABSTRACT,
456 PREREQ_PM => { map (($_->{name} => $_->{version} || 0 ),
457 grep ! $_->{optional}, @{MOD_REQS()})},
459 # Need this to stop Makefile treating Build.PL as a producer of Build as a
462 EXE_FILES => [ grep !/(?:CVS|~)$/, glob catfile (qw( bin * )) ],
463 clean => +{ FILES => [qw( Build _build )] },
464 realclean => +{ FILES => [qw( Build.PL META.yml
470 $Config{PREFIX} = *PREFIX{CODE}->()
471 if defined *PREFIX{CODE};
472 push @{$Config{clean}->{FILES}}, @{*EXTRA_CLEAN{CODE}->()}
473 if defined *EXTRA_CLEAN{CODE};
474 push @{$Config{realclean}->{FILES}}, qw( Makefile.PL configure README )
477 if ( defined *DEPENDS{CODE} ) {
478 my $depends = *DEPENDS{CODE}->();
481 my ($target) = $_->{target};
482 my ($reqs) = $_->{reqs};
483 my ($rules) = $_->{rules};
485 $depends{$target} = join("\n\t", join(' ', @$reqs), @$rules) . "\n";
487 $Config{depend} = \%depends;
490 if ( defined *DERIVED_PM{CODE} ) {
491 my $extra = *DERIVED_PM{CODE}->();
492 die sprintf "Don't know how to handle type: %s\n", ref $extra
493 unless UNIVERSAL::isa($extra, 'ARRAY');
496 $Config{PM}->{catfile('lib', $_)} = catfile '$(INST_LIBDIR)', $_;
497 push @{$Config{clean}->{FILES}}, $_;
501 $Config{clean}->{FILES} = join ' ', @{$Config{clean}->{FILES}};
502 $Config{realclean}->{FILES} = join ' ', @{$Config{realclean}->{FILES}};
504 WriteMakefile (%Config);
506 # ----------------------------------------------------------------------------
516 =head1 REPORTING BUGS
522 Martyn J. Pearce C<fluffy@cpan.org>
526 Copyright (c) 2001, 2002, 2003 Martyn J. Pearce. This program is free
527 software; you can redistribute it and/or modify it under the same terms as
536 1; # keep require happy