This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
ExtUtils::Manifest fix-ups for VMS:
[perl5.git] / lib / ExtUtils / Manifest.pm
1 package ExtUtils::Manifest;
2
3 require Exporter;
4 use Config;
5 use File::Basename;
6 use File::Copy 'copy';
7 use File::Find;
8 use File::Spec;
9 use Carp;
10 use strict;
11
12 use vars qw($VERSION @ISA @EXPORT_OK 
13           $Is_MacOS $Is_VMS 
14           $Debug $Verbose $Quiet $MANIFEST $DEFAULT_MSKIP);
15
16 $VERSION = '1.51_01';
17 @ISA=('Exporter');
18 @EXPORT_OK = qw(mkmanifest
19                 manicheck  filecheck  fullcheck  skipcheck
20                 manifind   maniread   manicopy   maniadd
21                );
22
23 $Is_MacOS = $^O eq 'MacOS';
24 $Is_VMS   = $^O eq 'VMS';
25 require VMS::Filespec if $Is_VMS;
26
27 $Debug   = $ENV{PERL_MM_MANIFEST_DEBUG} || 0;
28 $Verbose = defined $ENV{PERL_MM_MANIFEST_VERBOSE} ?
29                    $ENV{PERL_MM_MANIFEST_VERBOSE} : 1;
30 $Quiet = 0;
31 $MANIFEST = 'MANIFEST';
32
33 $DEFAULT_MSKIP = File::Spec->catfile( dirname(__FILE__), "$MANIFEST.SKIP" );
34
35
36 =head1 NAME
37
38 ExtUtils::Manifest - utilities to write and check a MANIFEST file
39
40 =head1 SYNOPSIS
41
42     use ExtUtils::Manifest qw(...funcs to import...);
43
44     mkmanifest();
45
46     my @missing_files    = manicheck;
47     my @skipped          = skipcheck;
48     my @extra_files      = filecheck;
49     my($missing, $extra) = fullcheck;
50
51     my $found    = manifind();
52
53     my $manifest = maniread();
54
55     manicopy($read,$target);
56
57     maniadd({$file => $comment, ...});
58
59
60 =head1 DESCRIPTION
61
62 =head2 Functions
63
64 ExtUtils::Manifest exports no functions by default.  The following are
65 exported on request
66
67 =over 4
68
69 =item mkmanifest
70
71     mkmanifest();
72
73 Writes all files in and below the current directory to your F<MANIFEST>.
74 It works similar to
75
76     find . > MANIFEST
77
78 All files that match any regular expression in a file F<MANIFEST.SKIP>
79 (if it exists) are ignored.
80
81 Any existing F<MANIFEST> file will be saved as F<MANIFEST.bak>.  Lines
82 from the old F<MANIFEST> file is preserved, including any comments
83 that are found in the existing F<MANIFEST> file in the new one.
84
85 =cut
86
87 sub _sort {
88     return sort { lc $a cmp lc $b } @_;
89 }
90
91 sub mkmanifest {
92     my $manimiss = 0;
93     my $read = (-r 'MANIFEST' && maniread()) or $manimiss++;
94     $read = {} if $manimiss;
95     local *M;
96     my $bakbase = $MANIFEST;
97     $bakbase =~ s/\./_/g if $Is_VMS; # avoid double dots
98     rename $MANIFEST, "$bakbase.bak" unless $manimiss;
99     open M, ">$MANIFEST" or die "Could not open $MANIFEST: $!";
100     my $skip = _maniskip();
101     my $found = manifind();
102     my($key,$val,$file,%all);
103     %all = (%$found, %$read);
104     $all{$MANIFEST} = ($Is_VMS ? "$MANIFEST\t\t" : '') . 'This list of files'
105         if $manimiss; # add new MANIFEST to known file list
106     foreach $file (_sort keys %all) {
107         if ($skip->($file)) {
108             # Policy: only remove files if they're listed in MANIFEST.SKIP.
109             # Don't remove files just because they don't exist.
110             warn "Removed from $MANIFEST: $file\n" if $Verbose and exists $read->{$file};
111             next;
112         }
113         if ($Verbose){
114             warn "Added to $MANIFEST: $file\n" unless exists $read->{$file};
115         }
116         my $text = $all{$file};
117         $file = _unmacify($file);
118         my $tabs = (5 - (length($file)+1)/8);
119         $tabs = 1 if $tabs < 1;
120         $tabs = 0 unless $text;
121         print M $file, "\t" x $tabs, $text, "\n";
122     }
123     close M;
124 }
125
126 # Geez, shouldn't this use File::Spec or File::Basename or something?  
127 # Why so careful about dependencies?
128 sub clean_up_filename {
129   my $filename = shift;
130   $filename =~ s|^\./||;
131   $filename =~ s/^:([^:]+)$/$1/ if $Is_MacOS;
132   return $filename;
133 }
134
135
136 =item manifind
137
138     my $found = manifind();
139
140 returns a hash reference. The keys of the hash are the files found
141 below the current directory.
142
143 =cut
144
145 sub manifind {
146     my $p = shift || {};
147     my $found = {};
148
149     my $wanted = sub {
150         my $name = clean_up_filename($File::Find::name);
151         warn "Debug: diskfile $name\n" if $Debug;
152         return if -d $_;
153         
154         if( $Is_VMS ) {
155             $name =~ s#(.*)\.$#\L$1#;
156             $name = uc($name) if $name =~ /^MANIFEST(\.SKIP)?$/i;
157         }
158         $found->{$name} = "";
159     };
160
161     # We have to use "$File::Find::dir/$_" in preprocess, because 
162     # $File::Find::name is unavailable.
163     # Also, it's okay to use / here, because MANIFEST files use Unix-style 
164     # paths.
165     find({wanted => $wanted},
166          $Is_MacOS ? ":" : ".");
167
168     return $found;
169 }
170
171
172 =item manicheck
173
174     my @missing_files = manicheck();
175
176 checks if all the files within a C<MANIFEST> in the current directory
177 really do exist. If C<MANIFEST> and the tree below the current
178 directory are in sync it silently returns an empty list.
179 Otherwise it returns a list of files which are listed in the
180 C<MANIFEST> but missing from the directory, and by default also
181 outputs these names to STDERR.
182
183 =cut
184
185 sub manicheck {
186     return _check_files();
187 }
188
189
190 =item filecheck
191
192     my @extra_files = filecheck();
193
194 finds files below the current directory that are not mentioned in the
195 C<MANIFEST> file. An optional file C<MANIFEST.SKIP> will be
196 consulted. Any file matching a regular expression in such a file will
197 not be reported as missing in the C<MANIFEST> file. The list of any
198 extraneous files found is returned, and by default also reported to
199 STDERR.
200
201 =cut
202
203 sub filecheck {
204     return _check_manifest();
205 }
206
207
208 =item fullcheck
209
210     my($missing, $extra) = fullcheck();
211
212 does both a manicheck() and a filecheck(), returning then as two array
213 refs.
214
215 =cut
216
217 sub fullcheck {
218     return [_check_files()], [_check_manifest()];
219 }
220
221
222 =item skipcheck
223
224     my @skipped = skipcheck();
225
226 lists all the files that are skipped due to your C<MANIFEST.SKIP>
227 file.
228
229 =cut
230
231 sub skipcheck {
232     my($p) = @_;
233     my $found = manifind();
234     my $matches = _maniskip();
235
236     my @skipped = ();
237     foreach my $file (_sort keys %$found){
238         if (&$matches($file)){
239             warn "Skipping $file\n";
240             push @skipped, $file;
241             next;
242         }
243     }
244
245     return @skipped;
246 }
247
248
249 sub _check_files {
250     my $p = shift;
251     my $dosnames=(defined(&Dos::UseLFN) && Dos::UseLFN()==0);
252     my $read = maniread() || {};
253     my $found = manifind($p);
254
255     my(@missfile) = ();
256     foreach my $file (_sort keys %$read){
257         warn "Debug: manicheck checking from $MANIFEST $file\n" if $Debug;
258         if ($dosnames){
259             $file = lc $file;
260             $file =~ s=(\.(\w|-)+)=substr ($1,0,4)=ge;
261             $file =~ s=((\w|-)+)=substr ($1,0,8)=ge;
262         }
263         unless ( exists $found->{$file} ) {
264             warn "No such file: $file\n" unless $Quiet;
265             push @missfile, $file;
266         }
267     }
268
269     return @missfile;
270 }
271
272
273 sub _check_manifest {
274     my($p) = @_;
275     my $read = maniread() || {};
276     my $found = manifind($p);
277     my $skip  = _maniskip();
278
279     my @missentry = ();
280     foreach my $file (_sort keys %$found){
281         next if $skip->($file);
282         warn "Debug: manicheck checking from disk $file\n" if $Debug;
283         unless ( exists $read->{$file} ) {
284             my $canon = $Is_MacOS ? "\t" . _unmacify($file) : '';
285             warn "Not in $MANIFEST: $file$canon\n" unless $Quiet;
286             push @missentry, $file;
287         }
288     }
289
290     return @missentry;
291 }
292
293
294 =item maniread
295
296     my $manifest = maniread();
297     my $manifest = maniread($manifest_file);
298
299 reads a named C<MANIFEST> file (defaults to C<MANIFEST> in the current
300 directory) and returns a HASH reference with files being the keys and
301 comments being the values of the HASH.  Blank lines and lines which
302 start with C<#> in the C<MANIFEST> file are discarded.
303
304 =cut
305
306 sub maniread {
307     my ($mfile) = @_;
308     $mfile ||= $MANIFEST;
309     my $read = {};
310     local *M;
311     unless (open M, $mfile){
312         warn "Problem opening $mfile: $!";
313         return $read;
314     }
315     local $_;
316     while (<M>){
317         chomp;
318         next if /^\s*#/;
319
320         my($file, $comment) = /^(\S+)\s*(.*)/;
321         next unless $file;
322
323         if ($Is_MacOS) {
324             $file = _macify($file);
325             $file =~ s/\\([0-3][0-7][0-7])/sprintf("%c", oct($1))/ge;
326         }
327         elsif ($Is_VMS) {
328             require File::Basename;
329             my($base,$dir) = File::Basename::fileparse($file);
330             # Resolve illegal file specifications in the same way as tar
331             $dir =~ tr/./_/;
332             my(@pieces) = split(/\./,$base);
333             if (@pieces > 2) { $base = shift(@pieces) . '.' . join('_',@pieces); }
334             my $okfile = "$dir$base";
335             warn "Debug: Illegal name $file changed to $okfile\n" if $Debug;
336             $file = $okfile;
337             $file = lc($file) unless $file =~ /^MANIFEST(\.SKIP)?$/;
338         }
339
340         $read->{$file} = $comment;
341     }
342     close M;
343     $read;
344 }
345
346 # returns an anonymous sub that decides if an argument matches
347 sub _maniskip {
348     my @skip ;
349     my $mfile = "$MANIFEST.SKIP";
350     _check_mskip_directives($mfile) if -f $mfile;
351     local(*M, $_);
352     open M, $mfile or open M, $DEFAULT_MSKIP or return sub {0};
353     while (<M>){
354         chomp;
355         s/\r//;
356         next if /^#/;
357         next if /^\s*$/;
358         push @skip, _macify($_);
359     }
360     close M;
361     return sub {0} unless (scalar @skip > 0);
362
363     my $opts = $Is_VMS ? '(?i)' : '';
364
365     # Make sure each entry is isolated in its own parentheses, in case
366     # any of them contain alternations
367     my $regex = join '|', map "(?:$_)", @skip;
368
369     return sub { $_[0] =~ qr{$opts$regex} };
370 }
371
372 # checks for the special directives
373 #   #!include_default
374 #   #!include /path/to/some/manifest.skip
375 # in a custom MANIFEST.SKIP for, for including
376 # the content of, respectively, the default MANIFEST.SKIP
377 # and an external manifest.skip file
378 sub _check_mskip_directives {
379     my $mfile = shift;
380     local (*M, $_);
381     my @lines = ();
382     my $flag = 0;
383     unless (open M, $mfile) {
384         warn "Problem opening $mfile: $!";
385         return;
386     }
387     while (<M>) {
388         if (/^#!include_default\s*$/) {
389             if (my @default = _include_mskip_file()) {
390                 push @lines, @default;
391                 warn "Debug: Including default MANIFEST.SKIP\n" if $Debug;
392                 $flag++;
393             }
394             next;
395         }
396         if (/^#!include\s+(.*)\s*$/) {
397             my $external_file = $1;
398             if (my @external = _include_mskip_file($external_file)) {
399                 push @lines, @external;
400                 warn "Debug: Including external $external_file\n" if $Debug;
401                 $flag++;
402             }
403             next;
404         }
405         push @lines, $_;
406     }
407     close M;
408     return unless $flag;
409     my $bakbase = $mfile;
410     $bakbase =~ s/\./_/g if $Is_VMS;  # avoid double dots
411     rename $mfile, "$bakbase.bak";
412     warn "Debug: Saving original $mfile as $bakbase.bak\n" if $Debug;
413     unless (open M, ">$mfile") {
414         warn "Problem opening $mfile: $!";
415         return;
416     }
417     print M $_ for (@lines);
418     close M;
419     return;
420 }
421
422 # returns an array containing the lines of an external
423 # manifest.skip file, if given, or $DEFAULT_MSKIP
424 sub _include_mskip_file {
425     my $mskip = shift || $DEFAULT_MSKIP;
426     unless (-f $mskip) {
427         warn qq{Included file "$mskip" not found - skipping};
428         return;
429     }
430     local (*M, $_);
431     unless (open M, $mskip) {
432         warn "Problem opening $mskip: $!";
433         return;
434     }
435     my @lines = ();
436     push @lines, "\n#!start included $mskip\n";
437     push @lines, $_ while <M>;
438     close M;
439     push @lines, "#!end included $mskip\n\n";
440     return @lines;
441 }
442
443 =item manicopy
444
445     manicopy(\%src, $dest_dir);
446     manicopy(\%src, $dest_dir, $how);
447
448 Copies the files that are the keys in %src to the $dest_dir.  %src is
449 typically returned by the maniread() function.
450
451     manicopy( maniread(), $dest_dir );
452
453 This function is useful for producing a directory tree identical to the 
454 intended distribution tree. 
455
456 $how can be used to specify a different methods of "copying".  Valid
457 values are C<cp>, which actually copies the files, C<ln> which creates
458 hard links, and C<best> which mostly links the files but copies any
459 symbolic link to make a tree without any symbolic link.  C<cp> is the 
460 default.
461
462 =cut
463
464 sub manicopy {
465     my($read,$target,$how)=@_;
466     croak "manicopy() called without target argument" unless defined $target;
467     $how ||= 'cp';
468     require File::Path;
469     require File::Basename;
470
471     $target = VMS::Filespec::unixify($target) if $Is_VMS;
472     File::Path::mkpath([ $target ],! $Quiet,$Is_VMS ? undef : 0755);
473     foreach my $file (keys %$read){
474         if ($Is_MacOS) {
475             if ($file =~ m!:!) { 
476                 my $dir = _maccat($target, $file);
477                 $dir =~ s/[^:]+$//;
478                 File::Path::mkpath($dir,1,0755);
479             }
480             cp_if_diff($file, _maccat($target, $file), $how);
481         } else {
482             $file = VMS::Filespec::unixify($file) if $Is_VMS;
483             if ($file =~ m!/!) { # Ilya, that hurts, I fear, or maybe not?
484                 my $dir = File::Basename::dirname($file);
485                 $dir = VMS::Filespec::unixify($dir) if $Is_VMS;
486                 File::Path::mkpath(["$target/$dir"],! $Quiet,$Is_VMS ? undef : 0755);
487             }
488             cp_if_diff($file, "$target/$file", $how);
489         }
490     }
491 }
492
493 sub cp_if_diff {
494     my($from, $to, $how)=@_;
495     -f $from or carp "$0: $from not found";
496     my($diff) = 0;
497     local(*F,*T);
498     open(F,"< $from\0") or die "Can't read $from: $!\n";
499     if (open(T,"< $to\0")) {
500         local $_;
501         while (<F>) { $diff++,last if $_ ne <T>; }
502         $diff++ unless eof(T);
503         close T;
504     }
505     else { $diff++; }
506     close F;
507     if ($diff) {
508         if (-e $to) {
509             unlink($to) or confess "unlink $to: $!";
510         }
511         STRICT_SWITCH: {
512             best($from,$to), last STRICT_SWITCH if $how eq 'best';
513             cp($from,$to), last STRICT_SWITCH if $how eq 'cp';
514             ln($from,$to), last STRICT_SWITCH if $how eq 'ln';
515             croak("ExtUtils::Manifest::cp_if_diff " .
516                   "called with illegal how argument [$how]. " .
517                   "Legal values are 'best', 'cp', and 'ln'.");
518         }
519     }
520 }
521
522 sub cp {
523     my ($srcFile, $dstFile) = @_;
524     my ($access,$mod) = (stat $srcFile)[8,9];
525
526     copy($srcFile,$dstFile);
527     utime $access, $mod + ($Is_VMS ? 1 : 0), $dstFile;
528     _manicopy_chmod($srcFile, $dstFile);
529 }
530
531
532 sub ln {
533     my ($srcFile, $dstFile) = @_;
534     return &cp if $Is_VMS or ($^O eq 'MSWin32' and Win32::IsWin95());
535     link($srcFile, $dstFile);
536
537     unless( _manicopy_chmod($srcFile, $dstFile) ) {
538         unlink $dstFile;
539         return;
540     }
541     1;
542 }
543
544 # 1) Strip off all group and world permissions.
545 # 2) Let everyone read it.
546 # 3) If the owner can execute it, everyone can.
547 sub _manicopy_chmod {
548     my($srcFile, $dstFile) = @_;
549
550     my $perm = 0444 | (stat $srcFile)[2] & 0700;
551     chmod( $perm | ( $perm & 0100 ? 0111 : 0 ), $dstFile );
552 }
553
554 # Files that are often modified in the distdir.  Don't hard link them.
555 my @Exceptions = qw(MANIFEST META.yml SIGNATURE);
556 sub best {
557     my ($srcFile, $dstFile) = @_;
558
559     my $is_exception = grep $srcFile =~ /$_/, @Exceptions;
560     if ($is_exception or !$Config{d_link} or -l $srcFile) {
561         cp($srcFile, $dstFile);
562     } else {
563         ln($srcFile, $dstFile) or cp($srcFile, $dstFile);
564     }
565 }
566
567 sub _macify {
568     my($file) = @_;
569
570     return $file unless $Is_MacOS;
571
572     $file =~ s|^\./||;
573     if ($file =~ m|/|) {
574         $file =~ s|/+|:|g;
575         $file = ":$file";
576     }
577
578     $file;
579 }
580
581 sub _maccat {
582     my($f1, $f2) = @_;
583
584     return "$f1/$f2" unless $Is_MacOS;
585
586     $f1 .= ":$f2";
587     $f1 =~ s/([^:]:):/$1/g;
588     return $f1;
589 }
590
591 sub _unmacify {
592     my($file) = @_;
593
594     return $file unless $Is_MacOS;
595
596     $file =~ s|^:||;
597     $file =~ s|([/ \n])|sprintf("\\%03o", unpack("c", $1))|ge;
598     $file =~ y|:|/|;
599
600     $file;
601 }
602
603
604 =item maniadd
605
606   maniadd({ $file => $comment, ...});
607
608 Adds an entry to an existing F<MANIFEST> unless its already there.
609
610 $file will be normalized (ie. Unixified).  B<UNIMPLEMENTED>
611
612 =cut
613
614 sub maniadd {
615     my($additions) = shift;
616
617     _normalize($additions);
618     _fix_manifest($MANIFEST);
619
620     my $manifest = maniread();
621     my @needed = grep { !exists $manifest->{$_} } keys %$additions;
622     return 1 unless @needed;
623
624     open(MANIFEST, ">>$MANIFEST") or 
625       die "maniadd() could not open $MANIFEST: $!";
626
627     foreach my $file (_sort @needed) {
628         my $comment = $additions->{$file} || '';
629         printf MANIFEST "%-40s %s\n", $file, $comment;
630     }
631     close MANIFEST or die "Error closing $MANIFEST: $!";
632
633     return 1;
634 }
635
636
637 # Sometimes MANIFESTs are missing a trailing newline.  Fix this.
638 sub _fix_manifest {
639     my $manifest_file = shift;
640
641     open MANIFEST, $MANIFEST or die "Could not open $MANIFEST: $!";
642
643     # Yes, we should be using seek(), but I'd like to avoid loading POSIX
644     # to get SEEK_*
645     my @manifest = <MANIFEST>;
646     close MANIFEST;
647
648     unless( $manifest[-1] =~ /\n\z/ ) {
649         open MANIFEST, ">>$MANIFEST" or die "Could not open $MANIFEST: $!";
650         print MANIFEST "\n";
651         close MANIFEST;
652     }
653 }
654
655
656 # UNIMPLEMENTED
657 sub _normalize {
658     return;
659 }
660
661
662 =back
663
664 =head2 MANIFEST
665
666 A list of files in the distribution, one file per line.  The MANIFEST
667 always uses Unix filepath conventions even if you're not on Unix.  This
668 means F<foo/bar> style not F<foo\bar>.
669
670 Anything between white space and an end of line within a C<MANIFEST>
671 file is considered to be a comment.  Any line beginning with # is also
672 a comment.
673
674     # this a comment
675     some/file
676     some/other/file            comment about some/file
677
678
679 =head2 MANIFEST.SKIP
680
681 The file MANIFEST.SKIP may contain regular expressions of files that
682 should be ignored by mkmanifest() and filecheck(). The regular
683 expressions should appear one on each line. Blank lines and lines
684 which start with C<#> are skipped.  Use C<\#> if you need a regular
685 expression to start with a C<#>.
686
687 For example:
688
689     # Version control files and dirs.
690     \bRCS\b
691     \bCVS\b
692     ,v$
693     \B\.svn\b
694
695     # Makemaker generated files and dirs.
696     ^MANIFEST\.
697     ^Makefile$
698     ^blib/
699     ^MakeMaker-\d
700
701     # Temp, old and emacs backup files.
702     ~$
703     \.old$
704     ^#.*#$
705     ^\.#
706
707 If no MANIFEST.SKIP file is found, a default set of skips will be
708 used, similar to the example above.  If you want nothing skipped,
709 simply make an empty MANIFEST.SKIP file.
710
711 In one's own MANIFEST.SKIP file, certain directives
712 can be used to include the contents of other MANIFEST.SKIP
713 files. At present two such directives are recognized.
714
715 =over 4
716
717 =item #!include_default
718
719 This inserts the contents of the default MANIFEST.SKIP file
720
721 =item #!include /Path/to/another/manifest.skip
722
723 This inserts the contents of the specified external file
724
725 =back
726
727 The included contents will be inserted into the MANIFEST.SKIP
728 file in between I<#!start included /path/to/manifest.skip>
729 and I<#!end included /path/to/manifest.skip> markers.
730 The original MANIFEST.SKIP is saved as MANIFEST.SKIP.bak.
731
732 =head2 EXPORT_OK
733
734 C<&mkmanifest>, C<&manicheck>, C<&filecheck>, C<&fullcheck>,
735 C<&maniread>, and C<&manicopy> are exportable.
736
737 =head2 GLOBAL VARIABLES
738
739 C<$ExtUtils::Manifest::MANIFEST> defaults to C<MANIFEST>. Changing it
740 results in both a different C<MANIFEST> and a different
741 C<MANIFEST.SKIP> file. This is useful if you want to maintain
742 different distributions for different audiences (say a user version
743 and a developer version including RCS).
744
745 C<$ExtUtils::Manifest::Quiet> defaults to 0. If set to a true value,
746 all functions act silently.
747
748 C<$ExtUtils::Manifest::Debug> defaults to 0.  If set to a true value,
749 or if PERL_MM_MANIFEST_DEBUG is true, debugging output will be
750 produced.
751
752 =head1 DIAGNOSTICS
753
754 All diagnostic output is sent to C<STDERR>.
755
756 =over 4
757
758 =item C<Not in MANIFEST:> I<file>
759
760 is reported if a file is found which is not in C<MANIFEST>.
761
762 =item C<Skipping> I<file>
763
764 is reported if a file is skipped due to an entry in C<MANIFEST.SKIP>.
765
766 =item C<No such file:> I<file>
767
768 is reported if a file mentioned in a C<MANIFEST> file does not
769 exist.
770
771 =item C<MANIFEST:> I<$!>
772
773 is reported if C<MANIFEST> could not be opened.
774
775 =item C<Added to MANIFEST:> I<file>
776
777 is reported by mkmanifest() if $Verbose is set and a file is added
778 to MANIFEST. $Verbose is set to 1 by default.
779
780 =back
781
782 =head1 ENVIRONMENT
783
784 =over 4
785
786 =item B<PERL_MM_MANIFEST_DEBUG>
787
788 Turns on debugging
789
790 =back
791
792 =head1 SEE ALSO
793
794 L<ExtUtils::MakeMaker> which has handy targets for most of the functionality.
795
796 =head1 AUTHOR
797
798 Andreas Koenig C<andreas.koenig@anima.de>
799
800 Maintained by Michael G Schwern C<schwern@pobox.com> within the
801 ExtUtils-MakeMaker package and, as a separate CPAN package, by
802 Randy Kobes C<r.kobes@uwinnipeg.ca>.
803
804 =cut
805
806 1;