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