Update to use $^O
[p5sagit/p5-mst-13.2.git] / lib / AutoSplit.pm
CommitLineData
a0d0e21e 1package AutoSplit;
2
3require 5.000;
4require Exporter;
5
6use Config;
7use Carp;
8
9@ISA = qw(Exporter);
10@EXPORT = qw(&autosplit &autosplit_lib_modules);
3edbfbe5 11@EXPORT_OK = qw($Verbose $Keep $Maxlen $CheckForAutoloader $CheckModTime);
a0d0e21e 12
f06db76b 13=head1 NAME
14
15AutoSplit - split a package for autoloading
16
cb1a09d0 17=head1 SYNOPSIS
18
19 perl -e 'use AutoSplit; autosplit_modules(@ARGV)' ...
20
f06db76b 21=head1 DESCRIPTION
22
23This function will split up your program into files that the AutoLoader
24module can handle. Normally only used to build autoloading Perl library
25modules, especially extensions (like POSIX). You should look at how
26they're built out for details.
27
28=cut
29
a0d0e21e 30# for portability warn about names longer than $maxlen
31$Maxlen = 8; # 8 for dos, 11 (14-".al") for SYSVR3
32$Verbose = 1; # 0=none, 1=minimal, 2=list .al files
33$Keep = 0;
3edbfbe5 34$CheckForAutoloader = 1;
35$CheckModTime = 1;
a0d0e21e 36
3edbfbe5 37$IndexFile = "autosplit.ix"; # file also serves as timestamp
a0d0e21e 38$maxflen = 255;
39$maxflen = 14 if $Config{'d_flexfnam'} ne 'define';
c6538b72 40$Is_VMS = ($^O eq 'VMS');
a0d0e21e 41
3edbfbe5 42
a0d0e21e 43sub autosplit{
75f92628 44 my($file, $autodir, $k, $ckal, $ckmt) = @_;
45 # $file - the perl source file to be split (after __END__)
46 # $autodir - the ".../auto" dir below which to write split subs
47 # Handle optional flags:
48 $keep = $Keep unless defined $k;
49 $ckal = $CheckForAutoloader unless defined $ckal;
50 $ckmt = $CheckModTime unless defined $ckmt;
51 autosplit_file($file, $autodir, $keep, $ckal, $ckmt);
a0d0e21e 52}
53
54
a0d0e21e 55# This function is used during perl building/installation
56# ./miniperl -e 'use AutoSplit; autosplit_modules(@ARGV)' ...
57
58sub autosplit_lib_modules{
59 my(@modules) = @_; # list of Module names
60
61 foreach(@modules){
62 s#::#/#g; # incase specified as ABC::XYZ
4633a7c4 63 s|\\|/|g; # bug in ksh OS/2
a0d0e21e 64 s#^lib/##; # incase specified as lib/*.pm
c6538b72 65 if ($Is_VMS && /[:>\]]/) { # may need to convert VMS-style filespecs
a0d0e21e 66 my ($dir,$name) = (/(.*])(.*)/);
67 $dir =~ s/.*lib[\.\]]//;
68 $dir =~ s#[\.\]]#/#g;
69 $_ = $dir . $name;
70 }
3edbfbe5 71 autosplit_file("lib/$_", "lib/auto", $Keep, $CheckForAutoloader, $CheckModTime);
a0d0e21e 72 }
73 0;
74}
75
76
77# private functions
78
79sub autosplit_file{
80 my($filename, $autodir, $keep, $check_for_autoloader, $check_mod_time) = @_;
81 my(@names);
82
83 # where to write output files
84 $autodir = "lib/auto" unless $autodir;
c6538b72 85 ($autodir = VMS::Filespec::unixpath($autodir)) =~ s#/$## if $Is_VMS;
3edbfbe5 86 unless (-d $autodir){
87 local($", @p)="/";
88 foreach(split(/\//,$autodir)){
89 push(@p, $_);
90 next if -d "@p/";
91 mkdir("@p",0755) or die "AutoSplit unable to mkdir @p: $!";
92 }
93 # We should never need to create the auto dir here. installperl
94 # (or similar) should have done it. Expecting it to exist is a valuable
95 # sanity check against autosplitting into some random directory by mistake.
96 print "Warning: AutoSplit had to create top-level $autodir unexpectedly.\n";
97 }
a0d0e21e 98
99 # allow just a package name to be used
100 $filename .= ".pm" unless ($filename =~ m/\.pm$/);
101
102 open(IN, "<$filename") || die "AutoSplit: Can't open $filename: $!\n";
103 my($pm_mod_time) = (stat($filename))[9];
104 my($autoloader_seen) = 0;
f06db76b 105 my($in_pod) = 0;
a0d0e21e 106 while (<IN>) {
f06db76b 107 # Skip pod text.
108 $in_pod = 1 if /^=/;
109 $in_pod = 0 if /^=cut/;
110 next if ($in_pod || /^=cut/);
111
a0d0e21e 112 # record last package name seen
113 $package = $1 if (m/^\s*package\s+([\w:]+)\s*;/);
3edbfbe5 114 ++$autoloader_seen if m/^\s*(use|require)\s+AutoLoader\b/;
a0d0e21e 115 ++$autoloader_seen if m/\bISA\s*=.*\bAutoLoader\b/;
116 last if /^__END__/;
117 }
3edbfbe5 118 if ($check_for_autoloader && !$autoloader_seen){
119 print "AutoSplit skipped $filename: no AutoLoader used\n" if ($Verbose>=2);
120 return 0
121 }
a0d0e21e 122 $_ or die "Can't find __END__ in $filename\n";
123
124 $package or die "Can't find 'package Name;' in $filename\n";
125
126 my($modpname) = $package; $modpname =~ s#::#/#g;
127 my($al_idx_file) = "$autodir/$modpname/$IndexFile";
128
129 die "Package $package does not match filename $filename"
130 unless ($filename =~ m/$modpname.pm$/ or
c6538b72 131 $Is_VMS && $filename =~ m/$modpname.pm/i);
a0d0e21e 132
133 if ($check_mod_time){
134 my($al_ts_time) = (stat("$al_idx_file"))[9] || 1;
135 if ($al_ts_time >= $pm_mod_time){
136 print "AutoSplit skipped ($al_idx_file newer that $filename)\n"
137 if ($Verbose >= 2);
138 return undef; # one undef, not a list
139 }
140 }
141
142 my($from) = ($Verbose>=2) ? "$filename => " : "";
143 print "AutoSplitting $package ($from$autodir/$modpname)\n"
144 if $Verbose;
145
146 unless (-d "$autodir/$modpname"){
147 local($", @p)="/";
148 foreach(split(/\//,"$autodir/$modpname")){
149 push(@p, $_);
42793c05 150 next if -d "@p/";
a0d0e21e 151 mkdir("@p",0777) or die "AutoSplit unable to mkdir @p: $!";
152 }
153 }
154
155 # We must try to deal with some SVR3 systems with a limit of 14
156 # characters for file names. Sadly we *cannot* simply truncate all
157 # file names to 14 characters on these systems because we *must*
158 # create filenames which exactly match the names used by AutoLoader.pm.
159 # This is a problem because some systems silently truncate the file
160 # names while others treat long file names as an error.
161
162 # We do not yet deal with multiple packages within one file.
163 # Ideally both of these styles should work.
164 #
165 # package NAME;
166 # __END__
167 # sub AAA { ... }
168 # package NAME::option1;
169 # sub BBB { ... }
170 # package NAME::option2;
171 # sub BBB { ... }
172 #
173 # package NAME;
174 # __END__
175 # sub AAA { ... }
176 # sub NAME::option1::BBB { ... }
177 # sub NAME::option2::BBB { ... }
178 #
179 # For now both of these produce warnings.
180
181 open(OUT,">/dev/null") || open(OUT,">nla0:"); # avoid 'not opened' warning
4633a7c4 182 my(@subnames, %proto);
a0d0e21e 183 while (<IN>) {
184 if (/^package ([\w:]+)\s*;/) {
185 warn "package $1; in AutoSplit section ignored. Not currently supported.";
186 }
4633a7c4 187 if (/^sub\s+([\w:]+)(\s*\(.*?\))?/) {
a0d0e21e 188 print OUT "1;\n";
4633a7c4 189 my $subname = $1;
190 $proto{$1} = $2 or '';
a0d0e21e 191 if ($subname =~ m/::/){
192 warn "subs with package names not currently supported in AutoSplit section";
193 }
194 push(@subnames, $subname);
195 my($lname, $sname) = ($subname, substr($subname,0,$maxflen-3));
196 my($lpath) = "$autodir/$modpname/$lname.al";
197 my($spath) = "$autodir/$modpname/$sname.al";
198 unless(open(OUT, ">$lpath")){
199 open(OUT, ">$spath") or die "Can't create $spath: $!\n";
200 push(@names, $sname);
201 print " writing $spath (with truncated name)\n"
202 if ($Verbose>=1);
203 }else{
204 push(@names, $lname);
205 print " writing $lpath\n" if ($Verbose>=2);
206 }
207 print OUT "# NOTE: Derived from $filename. ",
208 "Changes made here will be lost.\n";
209 print OUT "package $package;\n\n";
210 }
211 print OUT $_;
212 }
213 print OUT "1;\n";
214 close(OUT);
215 close(IN);
216
217 if (!$keep){ # don't keep any obsolete *.al files in the directory
218 my(%names);
219 @names{@names} = @names;
220 opendir(OUTDIR,"$autodir/$modpname");
221 foreach(sort readdir(OUTDIR)){
222 next unless /\.al$/;
223 my($subname) = m/(.*)\.al$/;
224 next if $names{substr($subname,0,$maxflen-3)};
225 my($file) = "$autodir/$modpname/$_";
226 print " deleting $file\n" if ($Verbose>=2);
f06db76b 227 my($deleted,$thistime); # catch all versions on VMS
228 do { $deleted += ($thistime = unlink $file) } while ($thistime);
229 carp "Unable to delete $file: $!" unless $deleted;
a0d0e21e 230 }
231 closedir(OUTDIR);
232 }
233
234 open(TS,">$al_idx_file") or
235 carp "AutoSplit: unable to create timestamp file ($al_idx_file): $!";
236 print TS "# Index created by AutoSplit for $filename (file acts as timestamp)\n";
f06db76b 237 print TS "package $package;\n";
4633a7c4 238 print TS map("sub $_$proto{$_} ;\n", @subnames);
f06db76b 239 print TS "1;\n";
a0d0e21e 240 close(TS);
241
242 check_unique($package, $Maxlen, 1, @names);
243
244 @names;
245}
246
247
248sub check_unique{
249 my($module, $maxlen, $warn, @names) = @_;
250 my(%notuniq) = ();
251 my(%shorts) = ();
252 my(@toolong) = grep(length > $maxlen, @names);
253
254 foreach(@toolong){
255 my($trunc) = substr($_,0,$maxlen);
256 $notuniq{$trunc}=1 if $shorts{$trunc};
257 $shorts{$trunc} = ($shorts{$trunc}) ? "$shorts{$trunc}, $_" : $_;
258 }
259 if (%notuniq && $warn){
260 print "$module: some names are not unique when truncated to $maxlen characters:\n";
261 foreach(keys %notuniq){
262 print " $shorts{$_} truncate to $_\n";
263 }
264 }
265 %notuniq;
266}
267
2681;
269__END__
270
271# test functions so AutoSplit.pm can be applied to itself:
272sub test1{ "test 1\n"; }
273sub test2{ "test 2\n"; }
274sub test3{ "test 3\n"; }
275sub test4{ "test 4\n"; }
276
277