[win32] add archname to *sitearch in config.{b,g,v}c
[p5sagit/p5-mst-13.2.git] / lib / AutoSplit.pm
1 package AutoSplit;
2
3 require 5.000;
4 require Exporter;
5
6 use Config;
7 use Carp;
8 use File::Path qw(mkpath);
9
10 @ISA = qw(Exporter);
11 @EXPORT = qw(&autosplit &autosplit_lib_modules);
12 @EXPORT_OK = qw($Verbose $Keep $Maxlen $CheckForAutoloader $CheckModTime);
13
14 =head1 NAME
15
16 AutoSplit - split a package for autoloading
17
18 =head1 SYNOPSIS
19
20  perl -e 'use AutoSplit; autosplit_lib_modules(@ARGV)' ...
21
22  use AutoSplit; autosplit($file, $dir, $keep, $check, $modtime);
23
24 for perl versions 5.002 and later:
25
26  perl -MAutoSplit -e 'autosplit($ARGV[0], $ARGV[1], $k, $chk, $modtime)' ...
27
28 =head1 DESCRIPTION
29
30 This function will split up your program into files that the AutoLoader
31 module can handle. It is used by both the standard perl libraries and by
32 the MakeMaker utility, to automatically configure libraries for autoloading.
33
34 The C<autosplit> interface splits the specified file into a hierarchy 
35 rooted at the directory C<$dir>. It creates directories as needed to reflect
36 class hierarchy, and creates the file F<autosplit.ix>. This file acts as
37 both forward declaration of all package routines, and as timestamp for the
38 last update of the hierarchy.
39
40 The remaining three arguments to C<autosplit> govern other options to the
41 autosplitter. If the third argument, I<$keep>, is false, then any pre-existing
42 C<*.al> files in the autoload directory are removed if they are no longer
43 part of the module (obsoleted functions). The fourth argument, I<$check>,
44 instructs C<autosplit> to check the module currently being split to ensure
45 that it does include a C<use> specification for the AutoLoader module, and
46 skips the module if AutoLoader is not detected. Lastly, the I<$modtime>
47 argument specifies that C<autosplit> is to check the modification time of the
48 module against that of the C<autosplit.ix> file, and only split the module
49 if it is newer.
50
51 Typical use of AutoSplit in the perl MakeMaker utility is via the command-line
52 with:
53
54  perl -e 'use AutoSplit; autosplit($ARGV[0], $ARGV[1], 0, 1, 1)'
55
56 Defined as a Make macro, it is invoked with file and directory arguments;
57 C<autosplit> will split the specified file into the specified directory and
58 delete obsolete C<.al> files, after checking first that the module does use
59 the AutoLoader, and ensuring that the module is not already currently split
60 in its current form (the modtime test).
61
62 The C<autosplit_lib_modules> form is used in the building of perl. It takes
63 as input a list of files (modules) that are assumed to reside in a directory
64 B<lib> relative to the current directory. Each file is sent to the 
65 autosplitter one at a time, to be split into the directory B<lib/auto>.
66
67 In both usages of the autosplitter, only subroutines defined following the
68 perl special marker I<__END__> are split out into separate files. Some
69 routines may be placed prior to this marker to force their immediate loading
70 and parsing.
71
72 =head1 CAVEATS
73
74 Currently, C<AutoSplit> cannot handle multiple package specifications
75 within one file.
76
77 =head1 DIAGNOSTICS
78
79 C<AutoSplit> will inform the user if it is necessary to create the top-level
80 directory specified in the invocation. It is preferred that the script or
81 installation process that invokes C<AutoSplit> have created the full directory
82 path ahead of time. This warning may indicate that the module is being split
83 into an incorrect path.
84
85 C<AutoSplit> will warn the user of all subroutines whose name causes potential
86 file naming conflicts on machines with drastically limited (8 characters or
87 less) file name length. Since the subroutine name is used as the file name,
88 these warnings can aid in portability to such systems.
89
90 Warnings are issued and the file skipped if C<AutoSplit> cannot locate either
91 the I<__END__> marker or a "package Name;"-style specification.
92
93 C<AutoSplit> will also emit general diagnostics for inability to create
94 directories or files.
95
96 =cut
97
98 # for portability warn about names longer than $maxlen
99 $Maxlen  = 8;   # 8 for dos, 11 (14-".al") for SYSVR3
100 $Verbose = 1;   # 0=none, 1=minimal, 2=list .al files
101 $Keep    = 0;
102 $CheckForAutoloader = 1;
103 $CheckModTime = 1;
104
105 $IndexFile = "autosplit.ix";    # file also serves as timestamp
106 $maxflen = 255;
107 $maxflen = 14 if $Config{'d_flexfnam'} ne 'define';
108 if (defined (&Dos::UseLFN)) {
109      $maxflen = Dos::UseLFN() ? 255 : 11;
110 }
111 $Is_VMS = ($^O eq 'VMS');
112
113
114 sub autosplit{
115     my($file, $autodir,  $k, $ckal, $ckmt) = @_;
116     # $file    - the perl source file to be split (after __END__)
117     # $autodir - the ".../auto" dir below which to write split subs
118     # Handle optional flags:
119     $keep = $Keep unless defined $k;
120     $ckal = $CheckForAutoloader unless defined $ckal;
121     $ckmt = $CheckModTime unless defined $ckmt;
122     autosplit_file($file, $autodir, $keep, $ckal, $ckmt);
123 }
124
125
126 # This function is used during perl building/installation
127 # ./miniperl -e 'use AutoSplit; autosplit_lib_modules(@ARGV)' ...
128
129 sub autosplit_lib_modules{
130     my(@modules) = @_; # list of Module names
131
132     while(defined($_ = shift @modules)){
133         s#::#/#g;       # incase specified as ABC::XYZ
134         s|\\|/|g;               # bug in ksh OS/2
135         s#^lib/##; # incase specified as lib/*.pm
136         if ($Is_VMS && /[:>\]]/) { # may need to convert VMS-style filespecs
137             my ($dir,$name) = (/(.*])(.*)/);
138             $dir =~ s/.*lib[\.\]]//;
139             $dir =~ s#[\.\]]#/#g;
140             $_ = $dir . $name;
141         }
142         autosplit_file("lib/$_", "lib/auto", $Keep, $CheckForAutoloader, $CheckModTime);
143     }
144     0;
145 }
146
147
148 # private functions
149
150 sub autosplit_file{
151     my($filename, $autodir, $keep, $check_for_autoloader, $check_mod_time) = @_;
152     my(@names);
153     local($_);
154
155     # where to write output files
156     $autodir = "lib/auto" unless $autodir;
157     if ($Is_VMS) {
158         ($autodir = VMS::Filespec::unixpath($autodir)) =~ s{/$}{};
159         $filename = VMS::Filespec::unixify($filename); # may have dirs
160     }
161     unless (-d $autodir){
162         mkpath($autodir,0,0755);
163         # We should never need to create the auto dir here. installperl
164         # (or similar) should have done it. Expecting it to exist is a valuable
165         # sanity check against autosplitting into some random directory by mistake.
166         print "Warning: AutoSplit had to create top-level $autodir unexpectedly.\n";
167     }
168
169     # allow just a package name to be used
170     $filename .= ".pm" unless ($filename =~ m/\.pm$/);
171
172     open(IN, "<$filename") || die "AutoSplit: Can't open $filename: $!\n";
173     my($pm_mod_time) = (stat($filename))[9];
174     my($autoloader_seen) = 0;
175     my($in_pod) = 0;
176     while (<IN>) {
177         # Skip pod text.
178         $in_pod = 1 if /^=/;
179         $in_pod = 0 if /^=cut/;
180         next if ($in_pod || /^=cut/);
181
182         # record last package name seen
183         $package = $1 if (m/^\s*package\s+([\w:]+)\s*;/);
184         ++$autoloader_seen if m/^\s*(use|require)\s+AutoLoader\b/;
185         ++$autoloader_seen if m/\bISA\s*=.*\bAutoLoader\b/;
186         last if /^__END__/;
187     }
188     if ($check_for_autoloader && !$autoloader_seen){
189         print "AutoSplit skipped $filename: no AutoLoader used\n" if ($Verbose>=2);
190         return 0
191     }
192     $_ or die "Can't find __END__ in $filename\n";
193
194     $package or die "Can't find 'package Name;' in $filename\n";
195
196     my($modpname) = $package; 
197     if ($^O eq 'MSWin32') {
198         $modpname =~ s#::#\\#g; 
199     } else {
200         $modpname =~ s#::#/#g;
201     }
202
203     die "Package $package ($modpname.pm) does not match filename $filename"
204             unless ($filename =~ m/\Q$modpname.pm\E$/ or
205                     ($^O eq 'dos') or ($^O eq 'MSWin32') or
206                     $Is_VMS && $filename =~ m/$modpname.pm/i);
207
208     my($al_idx_file) = "$autodir/$modpname/$IndexFile";
209
210     if ($check_mod_time){
211         my($al_ts_time) = (stat("$al_idx_file"))[9] || 1;
212         if ($al_ts_time >= $pm_mod_time){
213             print "AutoSplit skipped ($al_idx_file newer that $filename)\n"
214                 if ($Verbose >= 2);
215             return undef;       # one undef, not a list
216         }
217     }
218
219     my($from) = ($Verbose>=2) ? "$filename => " : "";
220     print "AutoSplitting $package ($from$autodir/$modpname)\n"
221         if $Verbose;
222
223     unless (-d "$autodir/$modpname"){
224         mkpath("$autodir/$modpname",0,0777);
225     }
226
227     # We must try to deal with some SVR3 systems with a limit of 14
228     # characters for file names. Sadly we *cannot* simply truncate all
229     # file names to 14 characters on these systems because we *must*
230     # create filenames which exactly match the names used by AutoLoader.pm.
231     # This is a problem because some systems silently truncate the file
232     # names while others treat long file names as an error.
233
234     # We do not yet deal with multiple packages within one file.
235     # Ideally both of these styles should work.
236     #
237     #   package NAME;
238     #   __END__
239     #   sub AAA { ... }
240     #   package NAME::option1;
241     #   sub BBB { ... }
242     #   package NAME::option2;
243     #   sub BBB { ... }
244     #
245     #   package NAME;
246     #   __END__
247     #   sub AAA { ... }
248     #   sub NAME::option1::BBB { ... }
249     #   sub NAME::option2::BBB { ... }
250     #
251     # For now both of these produce warnings.
252
253     my $Is83 = $maxflen==11;  # plain, case INSENSITIVE dos filenames
254
255     open(OUT,">/dev/null") || open(OUT,">nla0:"); # avoid 'not opened' warning
256     my(@subnames, %proto);
257     my @cache = ();
258     my $caching = 1;
259     while (<IN>) {
260         next if /^=\w/ .. /^=cut/;
261         if (/^package ([\w:]+)\s*;/) {
262             warn "package $1; in AutoSplit section ignored. Not currently supported.";
263         }
264         if (/^sub\s+([\w:]+)(\s*\(.*?\))?/) {
265             print OUT "1;\n";
266             my $subname = $1;
267             $proto{$1} = $2 || '';
268             if ($subname =~ m/::/){
269                 warn "subs with package names not currently supported in AutoSplit section";
270             }
271             push(@subnames, $subname);
272             my($lname, $sname) = ($subname, substr($subname,0,$maxflen-3));
273             my($lpath) = "$autodir/$modpname/$lname.al";
274             my($spath) = "$autodir/$modpname/$sname.al";
275             unless(open(OUT, ">$lpath")){
276                 open(OUT, ">$spath") or die "Can't create $spath: $!\n";
277                 push(@names, $Is83 ? lc $sname : $sname);
278                 print "  writing $spath (with truncated name)\n" if ($Verbose>=1);
279             }else{
280                 push(@names, $Is83 ? lc substr ($lname,0,8) : $lname);
281                 print "  writing $lpath\n" if ($Verbose>=2);
282             }
283             print OUT "# NOTE: Derived from $filename.  ",
284                         "Changes made here will be lost.\n";
285             print OUT "package $package;\n\n";
286             print OUT @cache;
287             @cache = ();
288             $caching = 0;
289         }
290         if($caching) {
291             push(@cache, $_) if @cache || /\S/;
292         }
293         else {
294             print OUT $_;
295         }
296         if(/^}/) {
297             if($caching) {
298                 print OUT @cache;
299                 @cache = ();
300             }
301             print OUT "\n";
302             $caching = 1;
303         }
304     }
305     print OUT @cache,"1;\n";
306     close(OUT);
307     close(IN);
308
309     if (!$keep){  # don't keep any obsolete *.al files in the directory
310         my(%names);
311         @names{@names} = @names;
312         opendir(OUTDIR,"$autodir/$modpname");
313         foreach(sort readdir(OUTDIR)){
314             next unless /\.al$/;
315             my($subname) = m/(.*)\.al$/;
316             next if $names{substr($subname,0,$maxflen-3)};
317             next if ($Is83 && $names{lc substr($subname,0,8)});
318             my($file) = "$autodir/$modpname/$_";
319             print "  deleting $file\n" if ($Verbose>=2);
320             my($deleted,$thistime);  # catch all versions on VMS
321             do { $deleted += ($thistime = unlink $file) } while ($thistime);
322             carp "Unable to delete $file: $!" unless $deleted;
323         }
324         closedir(OUTDIR);
325     }
326
327     open(TS,">$al_idx_file") or
328         carp "AutoSplit: unable to create timestamp file ($al_idx_file): $!";
329     print TS "# Index created by AutoSplit for $filename (file acts as timestamp)\n";
330     print TS "package $package;\n";
331     print TS map("sub $_$proto{$_} ;\n", @subnames);
332     print TS "1;\n";
333     close(TS);
334
335     check_unique($package, $Maxlen, 1, @names);
336
337     @names;
338 }
339
340
341 sub check_unique{
342     my($module, $maxlen, $warn, @names) = @_;
343     my(%notuniq) = ();
344     my(%shorts)  = ();
345     my(@toolong) = grep(length > $maxlen, @names);
346
347     foreach(@toolong){
348         my($trunc) = substr($_,0,$maxlen);
349         $notuniq{$trunc}=1 if $shorts{$trunc};
350         $shorts{$trunc} = ($shorts{$trunc}) ? "$shorts{$trunc}, $_" : $_;
351     }
352     if (%notuniq && $warn){
353         print "$module: some names are not unique when truncated to $maxlen characters:\n";
354         foreach(keys %notuniq){
355             print " $shorts{$_} truncate to $_\n";
356         }
357     }
358     %notuniq;
359 }
360
361 1;
362 __END__
363
364 # test functions so AutoSplit.pm can be applied to itself:
365 sub test1{ "test 1\n"; }
366 sub test2{ "test 2\n"; }
367 sub test3{ "test 3\n"; }
368 sub test4{ "test 4\n"; }
369
370