This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
VMS syntax nit in new MakeMaker test.
[perl5.git] / lib / AutoSplit.pm
... / ...
CommitLineData
1package AutoSplit;
2
3use Exporter ();
4use Config qw(%Config);
5use File::Basename ();
6use File::Path qw(mkpath);
7use File::Spec::Functions qw(curdir catfile catdir);
8use strict;
9our($VERSION, @ISA, @EXPORT, @EXPORT_OK, $Verbose, $Keep, $Maxlen,
10 $CheckForAutoloader, $CheckModTime);
11
12$VERSION = "1.05";
13@ISA = qw(Exporter);
14@EXPORT = qw(&autosplit &autosplit_lib_modules);
15@EXPORT_OK = qw($Verbose $Keep $Maxlen $CheckForAutoloader $CheckModTime);
16
17=head1 NAME
18
19AutoSplit - split a package for autoloading
20
21=head1 SYNOPSIS
22
23 autosplit($file, $dir, $keep, $check, $modtime);
24
25 autosplit_lib_modules(@modules);
26
27=head1 DESCRIPTION
28
29This function will split up your program into files that the AutoLoader
30module can handle. It is used by both the standard perl libraries and by
31the MakeMaker utility, to automatically configure libraries for autoloading.
32
33The C<autosplit> interface splits the specified file into a hierarchy
34rooted at the directory C<$dir>. It creates directories as needed to reflect
35class hierarchy, and creates the file F<autosplit.ix>. This file acts as
36both forward declaration of all package routines, and as timestamp for the
37last update of the hierarchy.
38
39The remaining three arguments to C<autosplit> govern other options to
40the autosplitter.
41
42=over 2
43
44=item $keep
45
46If the third argument, I<$keep>, is false, then any
47pre-existing C<*.al> files in the autoload directory are removed if
48they are no longer part of the module (obsoleted functions).
49$keep defaults to 0.
50
51=item $check
52
53The
54fourth argument, I<$check>, instructs C<autosplit> to check the module
55currently being split to ensure that it includes a C<use>
56specification for the AutoLoader module, and skips the module if
57AutoLoader is not detected.
58$check defaults to 1.
59
60=item $modtime
61
62Lastly, the I<$modtime> argument specifies
63that C<autosplit> is to check the modification time of the module
64against that of the C<autosplit.ix> file, and only split the module if
65it is newer.
66$modtime defaults to 1.
67
68=back
69
70Typical use of AutoSplit in the perl MakeMaker utility is via the command-line
71with:
72
73 perl -e 'use AutoSplit; autosplit($ARGV[0], $ARGV[1], 0, 1, 1)'
74
75Defined as a Make macro, it is invoked with file and directory arguments;
76C<autosplit> will split the specified file into the specified directory and
77delete obsolete C<.al> files, after checking first that the module does use
78the AutoLoader, and ensuring that the module is not already currently split
79in its current form (the modtime test).
80
81The C<autosplit_lib_modules> form is used in the building of perl. It takes
82as input a list of files (modules) that are assumed to reside in a directory
83B<lib> relative to the current directory. Each file is sent to the
84autosplitter one at a time, to be split into the directory B<lib/auto>.
85
86In both usages of the autosplitter, only subroutines defined following the
87perl I<__END__> token are split out into separate files. Some
88routines may be placed prior to this marker to force their immediate loading
89and parsing.
90
91=head2 Multiple packages
92
93As of version 1.01 of the AutoSplit module it is possible to have
94multiple packages within a single file. Both of the following cases
95are supported:
96
97 package NAME;
98 __END__
99 sub AAA { ... }
100 package NAME::option1;
101 sub BBB { ... }
102 package NAME::option2;
103 sub BBB { ... }
104
105 package NAME;
106 __END__
107 sub AAA { ... }
108 sub NAME::option1::BBB { ... }
109 sub NAME::option2::BBB { ... }
110
111=head1 DIAGNOSTICS
112
113C<AutoSplit> will inform the user if it is necessary to create the
114top-level directory specified in the invocation. It is preferred that
115the script or installation process that invokes C<AutoSplit> have
116created the full directory path ahead of time. This warning may
117indicate that the module is being split into an incorrect path.
118
119C<AutoSplit> will warn the user of all subroutines whose name causes
120potential file naming conflicts on machines with drastically limited
121(8 characters or less) file name length. Since the subroutine name is
122used as the file name, these warnings can aid in portability to such
123systems.
124
125Warnings are issued and the file skipped if C<AutoSplit> cannot locate
126either the I<__END__> marker or a "package Name;"-style specification.
127
128C<AutoSplit> will also emit general diagnostics for inability to
129create directories or files.
130
131=cut
132
133# for portability warn about names longer than $maxlen
134$Maxlen = 8; # 8 for dos, 11 (14-".al") for SYSVR3
135$Verbose = 1; # 0=none, 1=minimal, 2=list .al files
136$Keep = 0;
137$CheckForAutoloader = 1;
138$CheckModTime = 1;
139
140my $IndexFile = "autosplit.ix"; # file also serves as timestamp
141my $maxflen = 255;
142$maxflen = 14 if $Config{'d_flexfnam'} ne 'define';
143if (defined (&Dos::UseLFN)) {
144 $maxflen = Dos::UseLFN() ? 255 : 11;
145}
146my $Is_VMS = ($^O eq 'VMS');
147
148# allow checking for valid ': attrlist' attachments.
149# extra jugglery required to support both 5.8 and 5.9/5.10 features
150# (support for 5.8 required for cross-compiling environments)
151
152my $attr_list =
153 $] >= 5.009005 ?
154 eval <<'__QR__'
155 qr{
156 \s* : \s*
157 (?:
158 # one attribute
159 (?> # no backtrack
160 (?! \d) \w+
161 (?<nested> \( (?: [^()]++ | (?&nested)++ )*+ \) ) ?
162 )
163 (?: \s* : \s* | \s+ (?! :) )
164 )*
165 }x
166__QR__
167 :
168 do {
169 # In pre-5.9.5 world we have to do dirty tricks.
170 # (we use 'our' rather than 'my' here, due to the rather complex and buggy
171 # behaviour of lexicals with qr// and (??{$lex}) )
172 our $trick1; # yes, cannot our and assign at the same time.
173 $trick1 = qr{ \( (?: (?> [^()]+ ) | (??{ $trick1 }) )* \) }x;
174 our $trick2 = qr{ (?> (?! \d) \w+ (?:$trick1)? ) (?:\s*\:\s*|\s+(?!\:)) }x;
175 qr{ \s* : \s* (?: $trick2 )* }x;
176 };
177
178sub autosplit{
179 my($file, $autodir, $keep, $ckal, $ckmt) = @_;
180 # $file - the perl source file to be split (after __END__)
181 # $autodir - the ".../auto" dir below which to write split subs
182 # Handle optional flags:
183 $keep = $Keep unless defined $keep;
184 $ckal = $CheckForAutoloader unless defined $ckal;
185 $ckmt = $CheckModTime unless defined $ckmt;
186 autosplit_file($file, $autodir, $keep, $ckal, $ckmt);
187}
188
189sub carp{
190 require Carp;
191 goto &Carp::carp;
192}
193
194# This function is used during perl building/installation
195# ./miniperl -e 'use AutoSplit; autosplit_lib_modules(@ARGV)' ...
196
197sub autosplit_lib_modules {
198 my(@modules) = @_; # list of Module names
199 local $_; # Avoid clobber.
200 while (defined($_ = shift @modules)) {
201 while (m#([^:]+)::([^:].*)#) { # in case specified as ABC::XYZ
202 $_ = catfile($1, $2);
203 }
204 s|\\|/|g; # bug in ksh OS/2
205 s#^lib/##s; # incase specified as lib/*.pm
206 my($lib) = catfile(curdir(), "lib");
207 if ($Is_VMS) { # may need to convert VMS-style filespecs
208 $lib =~ s#^\[\]#.\/#;
209 }
210 s#^$lib\W+##s; # incase specified as ./lib/*.pm
211 if ($Is_VMS && /[:>\]]/) { # may need to convert VMS-style filespecs
212 my ($dir,$name) = (/(.*])(.*)/s);
213 $dir =~ s/.*lib[\.\]]//s;
214 $dir =~ s#[\.\]]#/#g;
215 $_ = $dir . $name;
216 }
217 autosplit_file(catfile($lib, $_), catfile($lib, "auto"),
218 $Keep, $CheckForAutoloader, $CheckModTime);
219 }
220 0;
221}
222
223
224# private functions
225
226my $self_mod_time = (stat __FILE__)[9];
227
228sub autosplit_file {
229 my($filename, $autodir, $keep, $check_for_autoloader, $check_mod_time)
230 = @_;
231 my(@outfiles);
232 local($_);
233 local($/) = "\n";
234
235 # where to write output files
236 $autodir ||= catfile(curdir(), "lib", "auto");
237 if ($Is_VMS) {
238 ($autodir = VMS::Filespec::unixpath($autodir)) =~ s|/\z||;
239 $filename = VMS::Filespec::unixify($filename); # may have dirs
240 }
241 unless (-d $autodir){
242 mkpath($autodir,0,0755);
243 # We should never need to create the auto dir
244 # here. installperl (or similar) should have done
245 # it. Expecting it to exist is a valuable sanity check against
246 # autosplitting into some random directory by mistake.
247 print "Warning: AutoSplit had to create top-level " .
248 "$autodir unexpectedly.\n";
249 }
250
251 # allow just a package name to be used
252 $filename .= ".pm" unless ($filename =~ m/\.pm\z/);
253
254 open(my $in, "<$filename") or die "AutoSplit: Can't open $filename: $!\n";
255 my($pm_mod_time) = (stat($filename))[9];
256 my($autoloader_seen) = 0;
257 my($in_pod) = 0;
258 my($def_package,$last_package,$this_package,$fnr);
259 while (<$in>) {
260 # Skip pod text.
261 $fnr++;
262 $in_pod = 1 if /^=\w/;
263 $in_pod = 0 if /^=cut/;
264 next if ($in_pod || /^=cut/);
265 next if /^\s*#/;
266
267 # record last package name seen
268 $def_package = $1 if (m/^\s*package\s+([\w:]+)\s*;/);
269 ++$autoloader_seen if m/^\s*(use|require)\s+AutoLoader\b/;
270 ++$autoloader_seen if m/\bISA\s*=.*\bAutoLoader\b/;
271 last if /^__END__/;
272 }
273 if ($check_for_autoloader && !$autoloader_seen){
274 print "AutoSplit skipped $filename: no AutoLoader used\n"
275 if ($Verbose>=2);
276 return 0;
277 }
278 $_ or die "Can't find __END__ in $filename\n";
279
280 $def_package or die "Can't find 'package Name;' in $filename\n";
281
282 my($modpname) = _modpname($def_package);
283
284 # this _has_ to match so we have a reasonable timestamp file
285 die "Package $def_package ($modpname.pm) does not ".
286 "match filename $filename"
287 unless ($filename =~ m/\Q$modpname.pm\E$/ or
288 ($^O eq 'dos') or ($^O eq 'MSWin32') or ($^O eq 'NetWare') or
289 $Is_VMS && $filename =~ m/$modpname.pm/i);
290
291 my($al_idx_file) = catfile($autodir, $modpname, $IndexFile);
292
293 if ($check_mod_time){
294 my($al_ts_time) = (stat("$al_idx_file"))[9] || 1;
295 if ($al_ts_time >= $pm_mod_time and
296 $al_ts_time >= $self_mod_time){
297 print "AutoSplit skipped ($al_idx_file newer than $filename)\n"
298 if ($Verbose >= 2);
299 return undef; # one undef, not a list
300 }
301 }
302
303 my($modnamedir) = catdir($autodir, $modpname);
304 print "AutoSplitting $filename ($modnamedir)\n"
305 if $Verbose;
306
307 unless (-d $modnamedir){
308 mkpath($modnamedir,0,0777);
309 }
310
311 # We must try to deal with some SVR3 systems with a limit of 14
312 # characters for file names. Sadly we *cannot* simply truncate all
313 # file names to 14 characters on these systems because we *must*
314 # create filenames which exactly match the names used by AutoLoader.pm.
315 # This is a problem because some systems silently truncate the file
316 # names while others treat long file names as an error.
317
318 my $Is83 = $maxflen==11; # plain, case INSENSITIVE dos filenames
319
320 my(@subnames, $subname, %proto, %package);
321 my @cache = ();
322 my $caching = 1;
323 $last_package = '';
324 my $out;
325 while (<$in>) {
326 $fnr++;
327 $in_pod = 1 if /^=\w/;
328 $in_pod = 0 if /^=cut/;
329 next if ($in_pod || /^=cut/);
330 # the following (tempting) old coding gives big troubles if a
331 # cut is forgotten at EOF:
332 # next if /^=\w/ .. /^=cut/;
333 if (/^package\s+([\w:]+)\s*;/) {
334 $this_package = $def_package = $1;
335 }
336
337 if (/^sub\s+([\w:]+)(\s*(?:\(.*?\))?(?:$attr_list)?)/) {
338 print $out "# end of $last_package\::$subname\n1;\n"
339 if $last_package;
340 $subname = $1;
341 my $proto = $2 || '';
342 if ($subname =~ s/(.*):://){
343 $this_package = $1;
344 } else {
345 $this_package = $def_package;
346 }
347 my $fq_subname = "$this_package\::$subname";
348 $package{$fq_subname} = $this_package;
349 $proto{$fq_subname} = $proto;
350 push(@subnames, $fq_subname);
351 my($lname, $sname) = ($subname, substr($subname,0,$maxflen-3));
352 $modpname = _modpname($this_package);
353 my($modnamedir) = catdir($autodir, $modpname);
354 mkpath($modnamedir,0,0777);
355 my($lpath) = catfile($modnamedir, "$lname.al");
356 my($spath) = catfile($modnamedir, "$sname.al");
357 my $path;
358
359 if (!$Is83 and open($out, ">$lpath")){
360 $path=$lpath;
361 print " writing $lpath\n" if ($Verbose>=2);
362 } else {
363 open($out, ">$spath") or die "Can't create $spath: $!\n";
364 $path=$spath;
365 print " writing $spath (with truncated name)\n"
366 if ($Verbose>=1);
367 }
368 push(@outfiles, $path);
369 my $lineno = $fnr - @cache;
370 print $out <<EOT;
371# NOTE: Derived from $filename.
372# Changes made here will be lost when autosplit is run again.
373# See AutoSplit.pm.
374package $this_package;
375
376#line $lineno "$filename (autosplit into $path)"
377EOT
378 print $out @cache;
379 @cache = ();
380 $caching = 0;
381 }
382 if($caching) {
383 push(@cache, $_) if @cache || /\S/;
384 } else {
385 print $out $_;
386 }
387 if(/^\}/) {
388 if($caching) {
389 print $out @cache;
390 @cache = ();
391 }
392 print $out "\n";
393 $caching = 1;
394 }
395 $last_package = $this_package if defined $this_package;
396 }
397 if ($subname) {
398 print $out @cache,"1;\n# end of $last_package\::$subname\n";
399 close($out);
400 }
401 close($in);
402
403 if (!$keep){ # don't keep any obsolete *.al files in the directory
404 my(%outfiles);
405 # @outfiles{@outfiles} = @outfiles;
406 # perl downcases all filenames on VMS (which upcases all filenames) so
407 # we'd better downcase the sub name list too, or subs with upper case
408 # letters in them will get their .al files deleted right after they're
409 # created. (The mixed case sub name won't match the all-lowercase
410 # filename, and so be cleaned up as a scrap file)
411 if ($Is_VMS or $Is83) {
412 %outfiles = map {lc($_) => lc($_) } @outfiles;
413 } else {
414 @outfiles{@outfiles} = @outfiles;
415 }
416 my(%outdirs,@outdirs);
417 for (@outfiles) {
418 $outdirs{File::Basename::dirname($_)}||=1;
419 }
420 for my $dir (keys %outdirs) {
421 opendir(my $outdir,$dir);
422 foreach (sort readdir($outdir)){
423 next unless /\.al\z/;
424 my($file) = catfile($dir, $_);
425 $file = lc $file if $Is83 or $Is_VMS;
426 next if $outfiles{$file};
427 print " deleting $file\n" if ($Verbose>=2);
428 my($deleted,$thistime); # catch all versions on VMS
429 do { $deleted += ($thistime = unlink $file) } while ($thistime);
430 carp ("Unable to delete $file: $!") unless $deleted;
431 }
432 closedir($outdir);
433 }
434 }
435
436 open(my $ts,">$al_idx_file") or
437 carp ("AutoSplit: unable to create timestamp file ($al_idx_file): $!");
438 print $ts "# Index created by AutoSplit for $filename\n";
439 print $ts "# (file acts as timestamp)\n";
440 $last_package = '';
441 for my $fqs (@subnames) {
442 my($subname) = $fqs;
443 $subname =~ s/.*:://;
444 print $ts "package $package{$fqs};\n"
445 unless $last_package eq $package{$fqs};
446 print $ts "sub $subname $proto{$fqs};\n";
447 $last_package = $package{$fqs};
448 }
449 print $ts "1;\n";
450 close($ts);
451
452 _check_unique($filename, $Maxlen, 1, @outfiles);
453
454 @outfiles;
455}
456
457sub _modpname ($) {
458 my($package) = @_;
459 my $modpname = $package;
460 if ($^O eq 'MSWin32') {
461 $modpname =~ s#::#\\#g;
462 } else {
463 my @modpnames = ();
464 while ($modpname =~ m#(.*?[^:])::([^:].*)#) {
465 push @modpnames, $1;
466 $modpname = $2;
467 }
468 $modpname = catfile(@modpnames, $modpname);
469 }
470 if ($Is_VMS) {
471 $modpname = VMS::Filespec::unixify($modpname); # may have dirs
472 }
473 $modpname;
474}
475
476sub _check_unique {
477 my($filename, $maxlen, $warn, @outfiles) = @_;
478 my(%notuniq) = ();
479 my(%shorts) = ();
480 my(@toolong) = grep(
481 length(File::Basename::basename($_))
482 > $maxlen,
483 @outfiles
484 );
485
486 foreach (@toolong){
487 my($dir) = File::Basename::dirname($_);
488 my($file) = File::Basename::basename($_);
489 my($trunc) = substr($file,0,$maxlen);
490 $notuniq{$dir}{$trunc} = 1 if $shorts{$dir}{$trunc};
491 $shorts{$dir}{$trunc} = $shorts{$dir}{$trunc} ?
492 "$shorts{$dir}{$trunc}, $file" : $file;
493 }
494 if (%notuniq && $warn){
495 print "$filename: some names are not unique when " .
496 "truncated to $maxlen characters:\n";
497 foreach my $dir (sort keys %notuniq){
498 print " directory $dir:\n";
499 foreach my $trunc (sort keys %{$notuniq{$dir}}) {
500 print " $shorts{$dir}{$trunc} truncate to $trunc\n";
501 }
502 }
503 }
504}
505
5061;
507__END__
508
509# test functions so AutoSplit.pm can be applied to itself:
510sub test1 ($) { "test 1\n"; }
511sub test2 ($$) { "test 2\n"; }
512sub test3 ($$$) { "test 3\n"; }
513sub testtesttesttest4_1 { "test 4\n"; }
514sub testtesttesttest4_2 { "duplicate test 4\n"; }
515sub Just::Another::test5 { "another test 5\n"; }
516sub test6 { return join ":", __FILE__,__LINE__; }
517package Yet::Another::AutoSplit;
518sub testtesttesttest4_1 ($) { "another test 4\n"; }
519sub testtesttesttest4_2 ($$) { "another duplicate test 4\n"; }
520package Yet::More::Attributes;
521sub test_a1 ($) : locked :locked { 1; }
522sub test_a2 : locked { 1; }