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