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