1
by Chris Weyl
perl v5.20.2, from upstream tag |
1 |
#!./miniperl
|
2 |
use strict; |
|
3 |
use warnings; |
|
4 |
use Config; |
|
5 |
use constant IS_CROSS => defined $Config::Config{usecrosscompile} ? 1 : 0; |
|
6 |
||
7 |
my $is_Win32 = $^O eq 'MSWin32'; |
|
8 |
my $is_VMS = $^O eq 'VMS'; |
|
9 |
my $is_Unix = !$is_Win32 && !$is_VMS; |
|
10 |
||
11 |
my @ext_dirs = qw(cpan dist ext); |
|
12 |
my $ext_dirs_re = '(?:' . join('|', @ext_dirs) . ')'; |
|
13 |
||
14 |
# This script acts as a simple interface for building extensions.
|
|
15 |
||
16 |
# It's actually a cut and shut of the Unix version ext/utils/makeext and the
|
|
17 |
# Windows version win32/build_ext.pl hence the two invocation styles.
|
|
18 |
||
19 |
# On Unix, it primarily used by the perl Makefile one extension at a time:
|
|
20 |
#
|
|
21 |
# d_dummy $(dynamic_ext): miniperl preplibrary FORCE
|
|
22 |
# @$(RUN) ./miniperl make_ext.pl --target=dynamic $@ MAKE=$(MAKE) LIBPERL_A=$(LIBPERL)
|
|
23 |
#
|
|
24 |
# On Windows or VMS,
|
|
25 |
# If '--static' is specified, static extensions will be built.
|
|
26 |
# If '--dynamic' is specified, dynamic extensions will be built.
|
|
27 |
# If '--nonxs' is specified, nonxs extensions will be built.
|
|
28 |
# If '--dynaloader' is specified, DynaLoader will be built.
|
|
29 |
# If '--all' is specified, all extensions will be built.
|
|
30 |
#
|
|
31 |
# make_ext.pl "MAKE=make [-make_opts]" --dir=directory [--target=target] [--static|--dynamic|--all] +ext2 !ext1
|
|
32 |
#
|
|
33 |
# E.g.
|
|
34 |
#
|
|
35 |
# make_ext.pl "MAKE=nmake -nologo" --dir=..\ext
|
|
36 |
#
|
|
37 |
# make_ext.pl "MAKE=nmake -nologo" --dir=..\ext --target=clean
|
|
38 |
#
|
|
39 |
# make_ext.pl MAKE=dmake --dir=..\ext
|
|
40 |
#
|
|
41 |
# make_ext.pl MAKE=dmake --dir=..\ext --target=clean
|
|
42 |
#
|
|
43 |
# Will skip building extensions which are marked with an '!' char.
|
|
44 |
# Mostly because they still not ported to specified platform.
|
|
45 |
#
|
|
46 |
# If any extensions are listed with a '+' char then only those
|
|
47 |
# extensions will be built, but only if they aren't countermanded
|
|
48 |
# by an '!ext' and are appropriate to the type of building being done.
|
|
49 |
# An extensions follows the format of Foo/Bar, which would be extension Foo::Bar
|
|
50 |
||
51 |
# It may be deleted in a later release of perl so try to
|
|
52 |
# avoid using it for other purposes.
|
|
53 |
||
54 |
my (%excl, %incl, %opts, @extspec, @pass_through); |
|
55 |
||
56 |
foreach (@ARGV) { |
|
57 |
if (/^!(.*)$/) { |
|
58 |
$excl{$1} = 1; |
|
59 |
} elsif (/^\+(.*)$/) { |
|
60 |
$incl{$1} = 1; |
|
61 |
} elsif (/^--([\w\-]+)$/) { |
|
62 |
$opts{$1} = 1; |
|
63 |
} elsif (/^--([\w\-]+)=(.*)$/) { |
|
64 |
push @{$opts{$1}}, $2; |
|
65 |
} elsif (/=/) { |
|
66 |
push @pass_through, $_; |
|
67 |
} elsif (length) { |
|
68 |
push @extspec, $_; |
|
69 |
}
|
|
70 |
}
|
|
71 |
||
72 |
my $static = $opts{static} || $opts{all}; |
|
73 |
my $dynamic = $opts{dynamic} || $opts{all}; |
|
74 |
my $nonxs = $opts{nonxs} || $opts{all}; |
|
75 |
my $dynaloader = $opts{dynaloader} || $opts{all}; |
|
76 |
||
77 |
# The Perl Makefile.SH will expand all extensions to
|
|
78 |
# lib/auto/X/X.a (or lib/auto/X/Y/Y.a if nested)
|
|
79 |
# A user wishing to run make_ext might use
|
|
80 |
# X (or X/Y or X::Y if nested)
|
|
81 |
||
82 |
# canonise into X/Y form (pname)
|
|
83 |
||
84 |
foreach (@extspec) { |
|
85 |
if (s{^lib/auto/}{}) { |
|
86 |
# Remove lib/auto prefix and /*.* suffix
|
|
87 |
s{/[^/]+\.[^/]+$}{}; |
|
88 |
} elsif (s{^$ext_dirs_re/}{}) { |
|
89 |
# Remove ext/ prefix and /pm_to_blib suffix
|
|
90 |
s{/pm_to_blib$}{}; |
|
91 |
# Targets are given as files on disk, but the extension spec is still
|
|
92 |
# written using /s for each ::
|
|
93 |
tr!-!/!; |
|
94 |
} elsif (s{::}{\/}g) { |
|
95 |
# Convert :: to /
|
|
96 |
} else { |
|
97 |
s/\..*o//; |
|
98 |
}
|
|
99 |
}
|
|
100 |
||
101 |
my $makecmd = shift @pass_through; # Should be something like MAKE=make |
|
102 |
unshift @pass_through, 'PERL_CORE=1'; |
|
103 |
||
104 |
my @dirs = @{$opts{dir} || \@ext_dirs}; |
|
105 |
my $target = $opts{target}[0]; |
|
106 |
$target = 'all' unless defined $target; |
|
107 |
||
108 |
# Previously, $make was taken from config.sh. However, the user might
|
|
109 |
# instead be running a possibly incompatible make. This might happen if
|
|
110 |
# the user types "gmake" instead of a plain "make", for example. The
|
|
111 |
# correct current value of MAKE will come through from the main perl
|
|
112 |
# makefile as MAKE=/whatever/make in $makecmd. We'll be cautious in
|
|
113 |
# case third party users of this script (are there any?) don't have the
|
|
114 |
# MAKE=$(MAKE) argument, which was added after 5.004_03.
|
|
115 |
unless(defined $makecmd and $makecmd =~ /^MAKE=(.*)$/) { |
|
116 |
die "$0: WARNING: Please include MAKE=\$(MAKE) in \@ARGV\n"; |
|
117 |
}
|
|
118 |
||
119 |
# This isn't going to cope with anything fancy, such as spaces inside command
|
|
120 |
# names, but neither did what it replaced. Once there is a use case that needs
|
|
121 |
# it, please supply patches. Until then, I'm sticking to KISS
|
|
122 |
my @make = split ' ', $1 || $Config{make} || $ENV{MAKE}; |
|
123 |
||
124 |
||
125 |
if ($target eq '') { |
|
126 |
die "make_ext: no make target specified (eg all or clean)\n"; |
|
127 |
} elsif ($target !~ /^(?:all|clean|distclean|realclean|veryclean)$/) { |
|
128 |
# we are strict about what make_ext is used for because we emulate these
|
|
129 |
# targets for simple modules:
|
|
130 |
die "$0: unknown make target '$target'\n"; |
|
131 |
}
|
|
132 |
||
133 |
if (!@extspec and !$static and !$dynamic and !$nonxs and !$dynaloader) { |
|
134 |
die "$0: no extension specified\n"; |
|
135 |
}
|
|
136 |
||
137 |
my $perl; |
|
138 |
my %extra_passthrough; |
|
139 |
||
140 |
if ($is_Win32) { |
|
141 |
require Cwd; |
|
142 |
require FindExt; |
|
143 |
my $build = Cwd::getcwd(); |
|
144 |
$perl = $^X; |
|
145 |
if ($perl =~ m#^\.\.#) { |
|
146 |
my $here = $build; |
|
147 |
$here =~ s{/}{\\}g; |
|
148 |
$perl = "$here\\$perl"; |
|
149 |
}
|
|
150 |
(my $topdir = $perl) =~ s/\\[^\\]+$//; |
|
151 |
# miniperl needs to find perlglob and pl2bat
|
|
152 |
$ENV{PATH} = "$topdir;$topdir\\win32\\bin;$ENV{PATH}"; |
|
153 |
my $pl2bat = "$topdir\\win32\\bin\\pl2bat"; |
|
154 |
unless (-f "$pl2bat.bat") { |
|
155 |
my @args = ($perl, "-I$topdir\\lib", ("$pl2bat.pl") x 2); |
|
156 |
print "@args\n"; |
|
157 |
system(@args) unless IS_CROSS; |
|
158 |
}
|
|
159 |
||
160 |
print "In $build"; |
|
161 |
foreach my $dir (@dirs) { |
|
162 |
chdir($dir) or die "Cannot cd to $dir: $!\n"; |
|
163 |
(my $ext = Cwd::getcwd()) =~ s{/}{\\}g; |
|
164 |
FindExt::scan_ext($ext); |
|
165 |
FindExt::set_static_extensions(split ' ', $Config{static_ext}); |
|
166 |
chdir $build |
|
167 |
or die "Couldn't chdir to '$build': $!"; # restore our start directory |
|
168 |
}
|
|
169 |
||
170 |
my @ext; |
|
171 |
push @ext, FindExt::static_ext() if $static; |
|
172 |
push @ext, FindExt::dynamic_ext() if $dynamic; |
|
173 |
push @ext, FindExt::nonxs_ext() if $nonxs; |
|
174 |
push @ext, 'DynaLoader' if $dynaloader; |
|
175 |
||
176 |
foreach (sort @ext) { |
|
177 |
if (%incl and !exists $incl{$_}) { |
|
178 |
#warn "Skipping extension $_, not in inclusion list\n";
|
|
179 |
next; |
|
180 |
}
|
|
181 |
if (exists $excl{$_}) { |
|
182 |
warn "Skipping extension $_, not ported to current platform"; |
|
183 |
next; |
|
184 |
}
|
|
185 |
push @extspec, $_; |
|
186 |
if($_ eq 'DynaLoader' and $target !~ /clean$/) { |
|
187 |
# No, we don't know why nmake can't work out the dependency chain
|
|
188 |
push @{$extra_passthrough{$_}}, 'DynaLoader.c'; |
|
189 |
} elsif(FindExt::is_static($_)) { |
|
190 |
push @{$extra_passthrough{$_}}, 'LINKTYPE=static'; |
|
191 |
}
|
|
192 |
}
|
|
193 |
||
194 |
chdir '..' |
|
195 |
or die "Couldn't chdir to build directory: $!"; # now in the Perl build |
|
196 |
}
|
|
197 |
elsif ($is_VMS) { |
|
198 |
$perl = $^X; |
|
199 |
push @extspec, (split ' ', $Config{static_ext}) if $static; |
|
200 |
push @extspec, (split ' ', $Config{dynamic_ext}) if $dynamic; |
|
201 |
push @extspec, (split ' ', $Config{nonxs_ext}) if $nonxs; |
|
202 |
push @extspec, 'DynaLoader' if $dynaloader; |
|
203 |
}
|
|
204 |
||
205 |
{
|
|
206 |
# Cwd needs to be built before Encode recurses into subdirectories.
|
|
207 |
# Pod::Simple needs to be built before Pod::Functions
|
|
208 |
# This seems to be the simplest way to ensure this ordering:
|
|
209 |
my (@first, @other); |
|
210 |
foreach (@extspec) { |
|
211 |
if ($_ eq 'Cwd' || $_ eq 'Pod/Simple') { |
|
212 |
push @first, $_; |
|
213 |
} else { |
|
214 |
push @other, $_; |
|
215 |
}
|
|
216 |
}
|
|
217 |
@extspec = (@first, @other); |
|
218 |
}
|
|
219 |
||
220 |
if ($Config{osname} eq 'catamount' and @extspec) { |
|
221 |
# Snowball's chance of building extensions.
|
|
222 |
die "This is $Config{osname}, not building $extspec[0], sorry.\n"; |
|
223 |
}
|
|
224 |
||
225 |
foreach my $spec (@extspec) { |
|
226 |
my $mname = $spec; |
|
227 |
$mname =~ s!/!::!g; |
|
228 |
my $ext_pathname; |
|
229 |
||
230 |
# Try new style ext/Data-Dumper/ first
|
|
231 |
my $copy = $spec; |
|
232 |
$copy =~ tr!/!-!; |
|
233 |
||
234 |
# List/Util.xs lives in Scalar-List-Utils, Cwd.xs lives in PathTools
|
|
235 |
$copy = 'Scalar-List-Utils' if $copy eq 'List-Util'; |
|
236 |
$copy = 'PathTools' if $copy eq 'Cwd'; |
|
237 |
||
238 |
foreach my $dir (@ext_dirs) { |
|
239 |
if (-d "$dir/$copy") { |
|
240 |
$ext_pathname = "$dir/$copy"; |
|
241 |
last; |
|
242 |
}
|
|
243 |
}
|
|
244 |
||
245 |
if (!defined $ext_pathname) { |
|
246 |
if (-d "ext/$spec") { |
|
247 |
# Old style ext/Data/Dumper/
|
|
248 |
$ext_pathname = "ext/$spec"; |
|
249 |
} else { |
|
250 |
warn "Can't find extension $spec in any of @ext_dirs"; |
|
251 |
next; |
|
252 |
}
|
|
253 |
}
|
|
254 |
||
255 |
print "\tMaking $mname ($target)\n"; |
|
256 |
||
257 |
build_extension($ext_pathname, $perl, $mname, $target, |
|
258 |
[@pass_through, @{$extra_passthrough{$spec} || []}]); |
|
259 |
}
|
|
260 |
||
261 |
sub build_extension { |
|
262 |
my ($ext_dir, $perl, $mname, $target, $pass_through) = @_; |
|
263 |
||
264 |
unless (chdir "$ext_dir") { |
|
265 |
warn "Cannot cd to $ext_dir: $!"; |
|
266 |
return; |
|
267 |
}
|
|
268 |
||
269 |
my $up = $ext_dir; |
|
270 |
$up =~ s![^/]+!..!g; |
|
271 |
||
272 |
$perl ||= "$up/miniperl"; |
|
273 |
my $return_dir = $up; |
|
274 |
my $lib_dir = "$up/lib"; |
|
275 |
$ENV{PERL_CORE} = 1; |
|
276 |
||
277 |
my $makefile; |
|
278 |
if ($is_VMS) { |
|
279 |
$makefile = 'descrip.mms'; |
|
280 |
if ($target =~ /clean$/ |
|
281 |
&& !-f $makefile |
|
282 |
&& -f "${makefile}_old") { |
|
283 |
$makefile = "${makefile}_old"; |
|
284 |
}
|
|
285 |
} else { |
|
286 |
$makefile = 'Makefile'; |
|
287 |
}
|
|
288 |
||
289 |
if (-f $makefile) { |
|
290 |
open my $mfh, $makefile or die "Cannot open $makefile: $!"; |
|
291 |
while (<$mfh>) { |
|
292 |
# Plagiarised from CPAN::Distribution
|
|
293 |
last if /MakeMaker post_initialize section/; |
|
294 |
next unless /^#\s+VERSION_FROM\s+=>\s+(.+)/; |
|
295 |
my $vmod = eval $1; |
|
296 |
my $oldv; |
|
297 |
while (<$mfh>) { |
|
298 |
next unless /^XS_VERSION = (\S+)/; |
|
299 |
$oldv = $1; |
|
300 |
last; |
|
301 |
}
|
|
302 |
last unless defined $oldv; |
|
303 |
require ExtUtils::MM_Unix; |
|
304 |
defined (my $newv = parse_version MM $vmod) or last; |
|
305 |
if ($newv ne $oldv) { |
|
306 |
close $mfh or die "close $makefile: $!"; |
|
307 |
_unlink($makefile); |
|
308 |
{
|
|
309 |
no warnings 'deprecated'; |
|
310 |
goto NO_MAKEFILE; |
|
311 |
}
|
|
312 |
}
|
|
313 |
}
|
|
314 |
||
315 |
if (IS_CROSS) { |
|
316 |
# If we're cross-compiling, it's possible that the host's
|
|
317 |
# Makefiles are around.
|
|
318 |
seek($mfh, 0, 0) or die "Cannot seek $makefile: $!"; |
|
319 |
||
320 |
my $cross_makefile; |
|
321 |
while (<$mfh>) { |
|
322 |
# XXX This might not be throughout enough.
|
|
323 |
# For example, it's possible to cause a false-positive
|
|
324 |
# if cross compiling on and for the Raspberry Pi,
|
|
325 |
# which is insane but plausible.
|
|
326 |
# False positives are really not troublesome, though;
|
|
327 |
# all they mean is that the module gets rebuilt.
|
|
328 |
if (/^CC = \Q$Config{cc}\E/) { |
|
329 |
$cross_makefile = 1; |
|
330 |
last; |
|
331 |
}
|
|
332 |
}
|
|
333 |
||
334 |
if (!$cross_makefile) { |
|
335 |
print "Deleting non-Cross makefile\n"; |
|
336 |
close $mfh or die "close $makefile: $!"; |
|
337 |
_unlink($makefile); |
|
338 |
}
|
|
339 |
}
|
|
340 |
}
|
|
341 |
||
342 |
if (!-f $makefile) { |
|
343 |
NO_MAKEFILE:
|
|
344 |
if (!-f 'Makefile.PL') { |
|
345 |
unless (just_pm_to_blib($target, $ext_dir, $mname, $return_dir)) { |
|
346 |
# No problems returned, so it has faked everything for us. :-)
|
|
347 |
chdir $return_dir || die "Cannot cd to $return_dir: $!"; |
|
348 |
return; |
|
349 |
}
|
|
350 |
||
351 |
print "\nCreating Makefile.PL in $ext_dir for $mname\n"; |
|
352 |
my ($fromname, $key, $value); |
|
353 |
if ($mname eq 'podlators') { |
|
354 |
# We need to special case this somewhere, and this is fewer
|
|
355 |
# lines of code than a core-only Makefile.PL, and no more
|
|
356 |
# complex
|
|
357 |
$fromname = 'VERSION'; |
|
358 |
$key = 'DISTNAME'; |
|
359 |
$value = 'podlators'; |
|
360 |
$mname = 'Pod'; |
|
361 |
} else { |
|
362 |
$key = 'ABSTRACT_FROM'; |
|
363 |
# We need to cope well with various possible layouts
|
|
364 |
my @dirs = split /::/, $mname; |
|
365 |
my $leaf = pop @dirs; |
|
366 |
my $leafname = "$leaf.pm"; |
|
367 |
my $pathname = join '/', @dirs, $leafname; |
|
368 |
my @locations = ($leafname, $pathname, "lib/$pathname"); |
|
369 |
unshift @locations, 'lib/IO/Compress/Base.pm' if $mname eq 'IO::Compress'; |
|
370 |
foreach (@locations) { |
|
371 |
if (-f $_) { |
|
372 |
$fromname = $_; |
|
373 |
last; |
|
374 |
}
|
|
375 |
}
|
|
376 |
||
377 |
unless ($fromname) { |
|
378 |
die "For $mname tried @locations in in $ext_dir but can't find source"; |
|
379 |
}
|
|
380 |
($value = $fromname) =~ s/\.pm\z/.pod/; |
|
381 |
$value = $fromname unless -e $value; |
|
382 |
}
|
|
383 |
open my $fh, '>', 'Makefile.PL' |
|
384 |
or die "Can't open Makefile.PL for writing: $!"; |
|
385 |
printf $fh <<'EOM', $0, $mname, $fromname, $key, $value; |
|
386 |
#-*- buffer-read-only: t -*-
|
|
387 |
||
388 |
# This Makefile.PL was written by %s.
|
|
389 |
# It will be deleted automatically by make realclean
|
|
390 |
||
391 |
use strict; |
|
392 |
use ExtUtils::MakeMaker; |
|
393 |
||
394 |
# This is what the .PL extracts to. Not the ultimate file that is installed.
|
|
395 |
# (ie Win32 runs pl2bat after this)
|
|
396 |
||
397 |
# Doing this here avoids all sort of quoting issues that would come from
|
|
398 |
# attempting to write out perl source with literals to generate the arrays and
|
|
399 |
# hash.
|
|
400 |
my @temps = 'Makefile.PL'; |
|
401 |
foreach (glob('scripts/pod*.PL')) { |
|
402 |
# The various pod*.PL extractors change directory. Doing that with relative
|
|
403 |
# paths in @INC breaks. It seems the lesser of two evils to copy (to avoid)
|
|
404 |
# the chdir doing anything, than to attempt to convert lib paths to
|
|
405 |
# absolute, and potentially run into problems with quoting special
|
|
406 |
# characters in the path to our build dir (such as spaces)
|
|
407 |
require File::Copy; |
|
408 |
||
409 |
my $temp = $_; |
|
410 |
$temp =~ s!scripts/!!; |
|
411 |
File::Copy::copy($_, $temp) or die "Can't copy $temp to $_: $!"; |
|
412 |
push @temps, $temp; |
|
413 |
}
|
|
414 |
||
415 |
my $script_ext = $^O eq 'VMS' ? '.com' : ''; |
|
416 |
my %%pod_scripts; |
|
417 |
foreach (glob('pod*.PL')) { |
|
418 |
my $script = $_; |
|
419 |
s/.PL$/$script_ext/i; |
|
420 |
$pod_scripts{$script} = $_; |
|
421 |
}
|
|
422 |
my @exe_files = values %%pod_scripts; |
|
423 |
||
424 |
WriteMakefile( |
|
425 |
NAME => '%s', |
|
426 |
VERSION_FROM => '%s', |
|
427 |
%-13s => '%s', |
|
428 |
realclean => { FILES => "@temps" }, |
|
429 |
(%%pod_scripts ? ( |
|
430 |
PL_FILES => \%%pod_scripts, |
|
431 |
EXE_FILES => \@exe_files, |
|
432 |
clean => { FILES => "@exe_files" }, |
|
433 |
) : ()), |
|
434 |
);
|
|
435 |
||
436 |
# ex: set ro:
|
|
437 |
EOM
|
|
438 |
close $fh or die "Can't close Makefile.PL: $!"; |
|
439 |
# As described in commit 23525070d6c0e51f:
|
|
440 |
# Push the atime and mtime of generated Makefile.PLs back 4
|
|
441 |
# seconds. In certain circumstances ( on virtual machines ) the
|
|
442 |
# generated Makefile.PL can produce a Makefile that is older than
|
|
443 |
# the Makefile.PL. Altering the atime and mtime backwards by 4
|
|
444 |
# seconds seems to resolve the issue.
|
|
445 |
eval { |
|
446 |
my $ftime = (stat('Makefile.PL'))[9] - 4; |
|
447 |
utime $ftime, $ftime, 'Makefile.PL'; |
|
448 |
};
|
|
449 |
} elsif ($mname =~ /\A(?:Carp |
|
450 |
|ExtUtils::CBuilder
|
|
451 |
|Safe
|
|
452 |
|Search::Dict)\z/x) { |
|
453 |
# An explicit list of dual-life extensions that have a Makefile.PL
|
|
454 |
# for CPAN, but we have verified can also be built using the fakery.
|
|
455 |
my ($problem) = just_pm_to_blib($target, $ext_dir, $mname, $return_dir); |
|
456 |
# We really need to sanity test that we can fake it.
|
|
457 |
# Otherwise "skips" will go undetected, and the build slow down for
|
|
458 |
# everyone, defeating the purpose.
|
|
459 |
if (defined $problem) { |
|
460 |
if (-d "$return_dir/.git") { |
|
461 |
# Get the list of files that git isn't ignoring:
|
|
462 |
my @files = `git ls-files --cached --others --exclude-standard 2>/dev/null`; |
|
463 |
# on error (eg no git) we get nothing, but that's not a
|
|
464 |
# problem. The goal is to see if git thinks that the problem
|
|
465 |
# file is interesting, by getting a positive match with
|
|
466 |
# something git told us about, and if so bail out:
|
|
467 |
foreach (@files) { |
|
468 |
chomp; |
|
469 |
# We really need to sanity test that we can fake it.
|
|
470 |
# The intent is that this should only fail because
|
|
471 |
# you've just added a file to the dual-life dist that
|
|
472 |
# we can't handle. In which case you should either
|
|
473 |
# 1) remove the dist from the regex a few lines above.
|
|
474 |
# or
|
|
475 |
# 2) add the file to regex of "safe" filenames earlier
|
|
476 |
# in this function, that starts with ChangeLog
|
|
477 |
die "FATAL - $0 has $mname in the list of simple extensions, but it now contains file '$problem' which we can't handle" |
|
478 |
if $problem eq $_; |
|
479 |
}
|
|
480 |
# There's an unexpected file, but it seems to be something
|
|
481 |
# that git will ignore. So fall through to the regular
|
|
482 |
# Makefile.PL handling code below, on the assumption that
|
|
483 |
# we won't get here for a clean build.
|
|
484 |
}
|
|
485 |
warn "WARNING - $0 is building $mname using EU::MM, as it found file '$problem'"; |
|
486 |
} else { |
|
487 |
# It faked everything for us.
|
|
488 |
chdir $return_dir || die "Cannot cd to $return_dir: $!"; |
|
489 |
return; |
|
490 |
}
|
|
491 |
}
|
|
492 |
||
493 |
# We are going to have to use Makefile.PL:
|
|
494 |
print "\nRunning Makefile.PL in $ext_dir\n"; |
|
495 |
||
496 |
my @args = ("-I$lib_dir", 'Makefile.PL'); |
|
497 |
if ($is_VMS) { |
|
498 |
my $libd = VMS::Filespec::vmspath($lib_dir); |
|
499 |
push @args, "INST_LIB=$libd", "INST_ARCHLIB=$libd"; |
|
500 |
} else { |
|
501 |
push @args, 'INSTALLDIRS=perl', 'INSTALLMAN1DIR=none', |
|
502 |
'INSTALLMAN3DIR=none'; |
|
503 |
}
|
|
504 |
push @args, @$pass_through; |
|
505 |
_quote_args(\@args) if $is_VMS; |
|
506 |
print join(' ', $perl, @args), "\n"; |
|
507 |
my $code = system $perl, @args; |
|
508 |
warn "$code from $ext_dir\'s Makefile.PL" if $code; |
|
509 |
||
510 |
# Right. The reason for this little hack is that we're sitting inside
|
|
511 |
# a program run by ./miniperl, but there are tasks we need to perform
|
|
512 |
# when the 'realclean', 'distclean' or 'veryclean' targets are run.
|
|
513 |
# Unfortunately, they can be run *after* 'clean', which deletes
|
|
514 |
# ./miniperl
|
|
515 |
# So we do our best to leave a set of instructions identical to what
|
|
516 |
# we would do if we are run directly as 'realclean' etc
|
|
517 |
# Whilst we're perfect, unfortunately the targets we call are not, as
|
|
518 |
# some of them rely on a $(PERL) for their own distclean targets.
|
|
519 |
# But this always used to be a problem with the old /bin/sh version of
|
|
520 |
# this.
|
|
521 |
if ($is_Unix) { |
|
522 |
foreach my $clean_target ('realclean', 'veryclean') { |
|
523 |
fallback_cleanup($return_dir, $clean_target, <<"EOS"); |
|
524 |
cd $ext_dir |
|
525 |
if test ! -f Makefile -a -f Makefile.old; then |
|
526 |
echo "Note: Using Makefile.old" |
|
527 |
make -f Makefile.old $clean_target MAKE='@make' @pass_through |
|
528 |
else
|
|
529 |
if test ! -f Makefile ; then |
|
530 |
echo "Warning: No Makefile!" |
|
531 |
fi
|
|
532 |
make $clean_target MAKE='@make' @pass_through |
|
533 |
fi
|
|
534 |
cd $return_dir |
|
535 |
EOS
|
|
536 |
}
|
|
537 |
}
|
|
538 |
}
|
|
539 |
||
540 |
if (not -f $makefile) { |
|
541 |
print "Warning: No Makefile!\n"; |
|
542 |
}
|
|
543 |
||
544 |
if ($is_VMS) { |
|
545 |
_quote_args($pass_through); |
|
546 |
@$pass_through = ( |
|
547 |
"/DESCRIPTION=$makefile", |
|
548 |
'/MACRO=(' . join(',',@$pass_through) . ')' |
|
549 |
);
|
|
550 |
}
|
|
551 |
||
552 |
if (!$target or $target !~ /clean$/) { |
|
553 |
# Give makefile an opportunity to rewrite itself.
|
|
554 |
# reassure users that life goes on...
|
|
555 |
my @args = ('config', @$pass_through); |
|
556 |
system(@make, @args) and print "@make @args failed, continuing anyway...\n"; |
|
557 |
}
|
|
558 |
my @targ = ($target, @$pass_through); |
|
559 |
print "Making $target in $ext_dir\n@make @targ\n"; |
|
560 |
my $code = system(@make, @targ); |
|
561 |
die "Unsuccessful make($ext_dir): code=$code" if $code != 0; |
|
562 |
||
563 |
chdir $return_dir || die "Cannot cd to $return_dir: $!"; |
|
564 |
}
|
|
565 |
||
566 |
sub _quote_args { |
|
567 |
my $args = shift; # must be array reference |
|
568 |
||
569 |
# Do not quote qualifiers that begin with '/'.
|
|
570 |
map { if (!/^\//) { |
|
571 |
$_ =~ s/\"/""/g; # escape C<"> by doubling |
|
572 |
$_ = q(").$_.q("); |
|
573 |
}
|
|
574 |
} @{$args} |
|
575 |
;
|
|
576 |
}
|
|
577 |
||
578 |
#guarentee that a file is deleted or die, void _unlink($filename)
|
|
579 |
#xxx replace with _unlink_or_rename from EU::Install?
|
|
580 |
sub _unlink { |
|
581 |
1 while unlink $_[0]; |
|
582 |
my $err = $!; |
|
583 |
die "Can't unlink $_[0]: $err" if -f $_[0]; |
|
584 |
}
|
|
585 |
||
586 |
# Figure out if this extension is simple enough that it would only use
|
|
587 |
# ExtUtils::MakeMaker's pm_to_blib target. If we're confident that it would,
|
|
588 |
# then do all the work ourselves (returning an empty list), else return the
|
|
589 |
# name of a file that we identified as beyond our ability to handle.
|
|
590 |
#
|
|
591 |
# While this is clearly quite a bit more work than just letting
|
|
592 |
# ExtUtils::MakeMaker do it, and effectively is some code duplication, the time
|
|
593 |
# savings are impressive.
|
|
594 |
||
595 |
sub just_pm_to_blib { |
|
596 |
my ($target, $ext_dir, $mname, $return_dir) = @_; |
|
597 |
my ($has_lib, $has_top, $has_topdir); |
|
598 |
my ($last) = $mname =~ /([^:]+)$/; |
|
599 |
my ($first) = $mname =~ /^([^:]+)/; |
|
600 |
||
601 |
my $pm_to_blib = $is_VMS ? 'pm_to_blib.ts' : 'pm_to_blib'; |
|
602 |
||
603 |
foreach my $leaf (<*>) { |
|
604 |
if (-d $leaf) { |
|
605 |
$leaf =~ s/\.DIR\z//i |
|
606 |
if $is_VMS; |
|
607 |
next if $leaf =~ /\A(?:\.|\.\.|t|demo)\z/; |
|
608 |
if ($leaf eq 'lib') { |
|
609 |
++$has_lib; |
|
610 |
next; |
|
611 |
}
|
|
612 |
if ($leaf eq $first) { |
|
613 |
++$has_topdir; |
|
614 |
next; |
|
615 |
}
|
|
616 |
}
|
|
617 |
return $leaf |
|
618 |
unless -f _; |
|
619 |
$leaf =~ s/\.\z// |
|
620 |
if $is_VMS; |
|
621 |
# Makefile.PL is "safe" to ignore because we will only be called for
|
|
622 |
# directories that hold a Makefile.PL if they are in the exception list.
|
|
623 |
next
|
|
624 |
if $leaf =~ /\A(ChangeLog |
|
625 |
|Changes
|
|
626 |
|LICENSE
|
|
627 |
|Makefile\.PL
|
|
628 |
|MANIFEST
|
|
629 |
|META\.yml
|
|
630 |
|\Q$pm_to_blib\E
|
|
631 |
|README
|
|
632 |
|README\.patching
|
|
633 |
|README\.release
|
|
634 |
)\z/xi; # /i to deal with case munging systems. |
|
635 |
if ($leaf eq "$last.pm") { |
|
636 |
++$has_top; |
|
637 |
next; |
|
638 |
}
|
|
639 |
return $leaf; |
|
640 |
}
|
|
641 |
return 'no lib/' |
|
642 |
unless $has_lib || $has_top; |
|
643 |
die "Inconsistent module $mname has both lib/ and $first/" |
|
644 |
if $has_lib && $has_topdir; |
|
645 |
||
646 |
print "\nRunning pm_to_blib for $ext_dir directly\n"; |
|
647 |
||
648 |
my %pm; |
|
649 |
if ($has_top) { |
|
650 |
my $to = $mname =~ s!::!/!gr; |
|
651 |
$pm{"$last.pm"} = "../../lib/$to.pm"; |
|
652 |
}
|
|
653 |
if ($has_lib || $has_topdir) { |
|
654 |
# strictly ExtUtils::MakeMaker uses the pm_to_blib target to install
|
|
655 |
# .pm, pod and .pl files. We're just going to do it for .pm and .pod
|
|
656 |
# files, to avoid problems on case munging file systems. Specifically,
|
|
657 |
# _pm.PL which ExtUtils::MakeMaker should run munges to _PM.PL, and
|
|
658 |
# looks a lot like a regular foo.pl (ie FOO.PL)
|
|
659 |
my @found; |
|
660 |
require File::Find; |
|
661 |
unless (eval { |
|
662 |
File::Find::find({ |
|
663 |
no_chdir => 1, |
|
664 |
wanted => sub { |
|
665 |
return if -d $_; |
|
666 |
# Bail out immediately with the problem file:
|
|
667 |
die \$_ |
|
668 |
unless -f _; |
|
669 |
die \$_ |
|
670 |
unless /\A[^.]+\.(?:pm|pod)\z/i; |
|
671 |
push @found, $_; |
|
672 |
}
|
|
673 |
}, $has_lib ? 'lib' : $first); |
|
674 |
1; |
|
675 |
}) { |
|
676 |
# Problem files aren't really errors:
|
|
677 |
return ${$@} |
|
678 |
if ref $@ eq 'SCALAR'; |
|
679 |
# But anything else is:
|
|
680 |
die $@; |
|
681 |
}
|
|
682 |
if ($has_lib) { |
|
683 |
$pm{$_} = "../../$_" |
|
684 |
foreach @found; |
|
685 |
} else { |
|
686 |
$pm{$_} = "../../lib/$_" |
|
687 |
foreach @found; |
|
688 |
}
|
|
689 |
}
|
|
690 |
# This is running under miniperl, so no autodie
|
|
691 |
if ($target eq 'all') { |
|
692 |
require ExtUtils::Install; |
|
693 |
ExtUtils::Install::pm_to_blib(\%pm, '../../lib/auto'); |
|
694 |
open my $fh, '>', $pm_to_blib |
|
695 |
or die "Can't open '$pm_to_blib': $!"; |
|
696 |
print $fh "$0 has handled pm_to_blib directly\n"; |
|
697 |
close $fh |
|
698 |
or die "Can't close '$pm_to_blib': $!"; |
|
699 |
if ($is_Unix) { |
|
700 |
# Fake the fallback cleanup
|
|
701 |
my $fallback |
|
702 |
= join '', map {s!^\.\./\.\./!!; "rm -f $_\n"} sort values %pm; |
|
703 |
foreach my $clean_target ('realclean', 'veryclean') { |
|
704 |
fallback_cleanup($return_dir, $clean_target, $fallback); |
|
705 |
}
|
|
706 |
}
|
|
707 |
} else { |
|
708 |
# A clean target.
|
|
709 |
# For now, make the targets behave the same way as ExtUtils::MakeMaker
|
|
710 |
# does
|
|
711 |
_unlink($pm_to_blib); |
|
712 |
unless ($target eq 'clean') { |
|
713 |
# but cheat a bit, by relying on the top level Makefile clean target
|
|
714 |
# to take out our directory lib/auto/...
|
|
715 |
# (which it has to deal with, as cpan/foo/bar creates
|
|
716 |
# lib/auto/foo/bar, but the EU::MM rule will only
|
|
717 |
# rmdir lib/auto/foo/bar, leaving lib/auto/foo
|
|
718 |
_unlink($_) |
|
719 |
foreach sort values %pm; |
|
720 |
}
|
|
721 |
}
|
|
722 |
return; |
|
723 |
}
|
|
724 |
||
725 |
sub fallback_cleanup { |
|
726 |
my ($dir, $clean_target, $contents) = @_; |
|
727 |
my $file = "$dir/$clean_target.sh"; |
|
728 |
open my $fh, '>>', $file or die "open $file: $!"; |
|
729 |
# Quite possible that we're being run in parallel here.
|
|
730 |
# Can't use Fcntl this early to get the LOCK_EX
|
|
731 |
flock $fh, 2 or warn "flock $file: $!"; |
|
732 |
print $fh $contents or die "print $file: $!"; |
|
733 |
close $fh or die "close $file: $!"; |
|
734 |
}
|