xref: /openbsd-src/gnu/usr.bin/perl/cpan/ExtUtils-MakeMaker/t/lib/MakeMaker/Test/Utils.pm (revision ae3cb403620ab940fbaabb3055fac045a63d56b7)
1package MakeMaker::Test::Utils;
2
3use File::Spec;
4use strict;
5use Config;
6
7require Exporter;
8our @ISA = qw(Exporter);
9
10our $Is_VMS     = $^O eq 'VMS';
11our $Is_MacOS   = $^O eq 'MacOS';
12our $Is_FreeBSD = $^O eq 'freebsd';
13
14our @EXPORT = qw(which_perl perl_lib makefile_name makefile_backup
15                 make make_run run make_macro calibrate_mtime
16                 have_compiler slurp
17                 $Is_VMS $Is_MacOS
18                 run_ok
19                );
20
21
22# Setup the code to clean out %ENV
23{
24    # Environment variables which might effect our testing
25    my @delete_env_keys = qw(
26        PERL_MM_OPT
27        PERL_MM_USE_DEFAULT
28        HARNESS_TIMER
29        HARNESS_OPTIONS
30        HARNESS_VERBOSE
31        PREFIX
32        MAKEFLAGS
33        PERL_INSTALL_QUIET
34    );
35
36    my %default_env_keys;
37
38    # Inform the BSDPAN hacks not to register modules installed for testing.
39    $default_env_keys{PORTOBJFORMAT} = 1 if $Is_FreeBSD;
40
41    # https://github.com/Perl-Toolchain-Gang/ExtUtils-MakeMaker/issues/65
42    $default_env_keys{ACTIVEPERL_CONFIG_SILENT} = 1;
43
44    # Remember the ENV values because on VMS %ENV is global
45    # to the user, not the process.
46    my %restore_env_keys;
47
48    sub clean_env {
49        for my $key (keys %default_env_keys) {
50            $ENV{$key} = $default_env_keys{$key} unless $ENV{$key};
51        }
52
53        for my $key (@delete_env_keys) {
54            if( exists $ENV{$key} ) {
55                $restore_env_keys{$key} = delete $ENV{$key};
56            }
57            else {
58                delete $ENV{$key};
59            }
60        }
61    }
62
63    END {
64        while( my($key, $val) = each %restore_env_keys ) {
65            $ENV{$key} = $val;
66        }
67    }
68}
69clean_env();
70
71
72=head1 NAME
73
74MakeMaker::Test::Utils - Utility routines for testing MakeMaker
75
76=head1 SYNOPSIS
77
78  use MakeMaker::Test::Utils;
79
80  my $perl     = which_perl;
81  perl_lib;
82
83  my $makefile      = makefile_name;
84  my $makefile_back = makefile_backup;
85
86  my $make          = make;
87  my $make_run      = make_run;
88  make_macro($make, $targ, %macros);
89
90  my $mtime         = calibrate_mtime;
91
92  my $out           = run($cmd);
93
94  my $have_compiler = have_compiler();
95
96  my $text          = slurp($filename);
97
98
99=head1 DESCRIPTION
100
101A consolidation of little utility functions used throughout the
102MakeMaker test suite.
103
104=head2 Functions
105
106The following are exported by default.
107
108=over 4
109
110=item B<which_perl>
111
112  my $perl = which_perl;
113
114Returns a path to perl which is safe to use in a command line, no
115matter where you chdir to.
116
117=cut
118
119sub which_perl {
120    my $perl = $^X;
121    $perl ||= 'perl';
122
123    # VMS should have 'perl' aliased properly
124    return $perl if $Is_VMS;
125
126    $perl .= $Config{exe_ext} unless $perl =~ m/$Config{exe_ext}$/i;
127
128    my $perlpath = File::Spec->rel2abs( $perl );
129    unless( $Is_MacOS || -x $perlpath ) {
130        # $^X was probably 'perl'
131
132        # When building in the core, *don't* go off and find
133        # another perl
134        die "Can't find a perl to use (\$^X=$^X), (\$perlpath=$perlpath)"
135          if $ENV{PERL_CORE};
136
137        foreach my $path (File::Spec->path) {
138            $perlpath = File::Spec->catfile($path, $perl);
139            last if -x $perlpath;
140        }
141    }
142    $perlpath = qq{"$perlpath"}; # "safe... in a command line" even with spaces
143
144    return $perlpath;
145}
146
147=item B<perl_lib>
148
149  perl_lib;
150
151Sets up environment variables so perl can find its libraries.
152
153=cut
154
155my $old5lib = $ENV{PERL5LIB};
156my $had5lib = exists $ENV{PERL5LIB};
157sub perl_lib {
158                               # perl-src/t/
159    my $lib =  $ENV{PERL_CORE} ? qq{../lib}
160                               # ExtUtils-MakeMaker/t/
161                               : qq{../blib/lib};
162    $lib = File::Spec->rel2abs($lib);
163    my @libs = ($lib);
164    push @libs, $ENV{PERL5LIB} if exists $ENV{PERL5LIB};
165    $ENV{PERL5LIB} = join($Config{path_sep}, @libs);
166    unshift @INC, $lib;
167}
168
169END {
170    if( $had5lib ) {
171        $ENV{PERL5LIB} = $old5lib;
172    }
173    else {
174        delete $ENV{PERL5LIB};
175    }
176}
177
178
179=item B<makefile_name>
180
181  my $makefile = makefile_name;
182
183MakeMaker doesn't always generate 'Makefile'.  It returns what it
184should generate.
185
186=cut
187
188sub makefile_name {
189    return $Is_VMS ? 'Descrip.MMS' : 'Makefile';
190}
191
192=item B<makefile_backup>
193
194  my $makefile_old = makefile_backup;
195
196Returns the name MakeMaker will use for a backup of the current
197Makefile.
198
199=cut
200
201sub makefile_backup {
202    my $makefile = makefile_name;
203    return $Is_VMS ? "$makefile".'_old' : "$makefile.old";
204}
205
206=item B<make>
207
208  my $make = make;
209
210Returns a good guess at the make to run.
211
212=cut
213
214sub make {
215    my $make = $Config{make};
216    $make = $ENV{MAKE} if exists $ENV{MAKE};
217
218    return $Is_VMS ? $make : qq{"$make"};
219}
220
221=item B<make_run>
222
223  my $make_run = make_run;
224
225Returns the make to run as with make() plus any necessary switches.
226
227=cut
228
229sub make_run {
230    my $make = make;
231    $make .= ' -nologo' if $make eq 'nmake';
232
233    return $make;
234}
235
236=item B<make_macro>
237
238    my $make_cmd = make_macro($make, $target, %macros);
239
240Returns the command necessary to run $make on the given $target using
241the given %macros.
242
243  my $make_test_verbose = make_macro(make_run(), 'test',
244                                     TEST_VERBOSE => 1);
245
246This is important because VMS's make utilities have a completely
247different calling convention than Unix or Windows.
248
249%macros is actually a list of tuples, so the order will be preserved.
250
251=cut
252
253sub make_macro {
254    my($make, $target) = (shift, shift);
255
256    my $is_mms = $make =~ /^MM(K|S)/i;
257
258    my $cmd = $make;
259    my $macros = '';
260    while( my($key,$val) = splice(@_, 0, 2) ) {
261        if( $is_mms ) {
262            $macros .= qq{/macro="$key=$val"};
263        }
264        else {
265            $macros .= qq{ $key=$val};
266        }
267    }
268
269    return $is_mms ? "$make$macros $target" : "$make $target $macros";
270}
271
272=item B<calibrate_mtime>
273
274  my $mtime = calibrate_mtime;
275
276When building on NFS, file modification times can often lose touch
277with reality.  This returns the mtime of a file which has just been
278touched.
279
280=cut
281
282sub calibrate_mtime {
283    open(FILE, ">calibrate_mtime.tmp") || die $!;
284    print FILE "foo";
285    close FILE;
286    my($mtime) = (stat('calibrate_mtime.tmp'))[9];
287    unlink 'calibrate_mtime.tmp';
288    return $mtime;
289}
290
291=item B<run>
292
293  my $out = run($command);
294  my @out = run($command);
295
296Runs the given $command as an external program returning at least STDOUT
297as $out.  If possible it will return STDOUT and STDERR combined as you
298would expect to see on a screen.
299
300=cut
301
302sub run {
303    my $cmd = shift;
304
305    use ExtUtils::MM;
306
307    # Unix, modern Windows and OS/2 from 5.005_54 up can handle 2>&1
308    # This makes our failure diagnostics nicer to read.
309    if (MM->can_redirect_error) {
310        return `$cmd 2>&1`;
311    }
312    else {
313        return `$cmd`;
314    }
315}
316
317
318=item B<run_ok>
319
320  my @out = run_ok($cmd);
321
322Like run() but it tests that the result exited normally.
323
324The output from run() will be used as a diagnostic if it fails.
325
326=cut
327
328sub run_ok {
329    my $tb = Test::Builder->new;
330
331    my @out = run(@_);
332
333    $tb->cmp_ok( $?, '==', 0, "run(@_)" ) || $tb->diag(@out);
334
335    return wantarray ? @out : join "", @out;
336}
337
338=item have_compiler
339
340  $have_compiler = have_compiler;
341
342Returns true if there is a compiler available for XS builds.
343
344=cut
345
346sub have_compiler {
347    my $have_compiler = 0;
348
349    # ExtUtils::CBuilder prints its compilation lines to the screen.
350    # Shut it up.
351    use TieOut;
352    local *STDOUT = *STDOUT;
353    local *STDERR = *STDERR;
354
355    tie *STDOUT, 'TieOut';
356    tie *STDERR, 'TieOut';
357
358    eval {
359	require ExtUtils::CBuilder;
360	my $cb = ExtUtils::CBuilder->new;
361
362	$have_compiler = $cb->have_compiler;
363    };
364
365    return $have_compiler;
366}
367
368=item slurp
369
370  $contents = slurp($filename);
371
372Returns the $contents of $filename.
373
374Will die if $filename cannot be opened.
375
376=cut
377
378sub slurp {
379    my $filename = shift;
380
381    local $/ = undef;
382    open my $fh, $filename or die "Can't open $filename for reading: $!";
383    my $text = <$fh>;
384    close $fh;
385
386    return $text;
387}
388
389=back
390
391=head1 AUTHOR
392
393Michael G Schwern <schwern@pobox.com>
394
395=cut
396
3971;
398