--- ./MANIFEST~	Mon Jul  7 08:17:45 2003
+++ ./MANIFEST	Tue Jul 15 21:19:22 2003
@@ -1114,6 +1114,7 @@ lib/ExtUtils/NOTES		Notes about MakeMake
 lib/ExtUtils/Packlist.pm	Manipulates .packlist files
 lib/ExtUtils/PATCHING		Suggestions for patching MakeMaker
 lib/ExtUtils/README		MakeMaker README
+lib/ExtUtils/TestCompile.pm	Tests C code by compile/link
 lib/ExtUtils/t/00compile.t	See if MakeMaker modules compile
 lib/ExtUtils/t/00setup_dummy.t	Setup MakeMaker test module
 lib/ExtUtils/t/backwards.t	Check MakeMaker's backwards compatibility
@@ -1145,6 +1146,7 @@ lib/ExtUtils/t/problems.t	How MakeMaker 
 lib/ExtUtils/t/prompt.t		See if E::MM::prompt() works
 lib/ExtUtils/t/split_command.t	See if MM's xargs-like function works
 lib/ExtUtils/t/testlib.t	See if ExtUtils::testlib works
+lib/ExtUtils/t/TestCompile.t	See if ExtUtils::TestCompile works
 lib/ExtUtils/t/VERSION_FROM.t	See if MakeMaker's VERSION_FROM works
 lib/ExtUtils/t/vmsish.t	Test ExtUtils::MakeMaker::vmsish
 lib/ExtUtils/t/writemakefile_args.t	See if WriteMakefile works
--- ./lib/ExtUtils/t/TestCompile.t-pre	Tue Jul 15 21:20:15 2003
+++ ./lib/ExtUtils/t/TestCompile.t	Tue Jul 15 21:17:33 2003
@@ -0,0 +1,40 @@
+#!/usr/bin/perl -w
+
+BEGIN {
+    if( $ENV{PERL_CORE} ) {
+        chdir 't' if -d 't';
+        @INC = '../lib';
+    }
+    else {
+        unshift @INC, 't/lib/';
+    }
+
+    if ($^O =~ /^(uts|uwin)$/i) { # Did not build Time::HiRes, may not work
+      print "1..0 skipped: Time::HiRes was not build, may fail\n";
+      exit 0;
+    }
+    if ($^O eq 'VMS') { # Did not build Time::HiRes, may not work
+      print "1..0 skipped: compiler output can't be silenced\n";
+      exit 0;
+    }
+}
+
+use ExtUtils::TestCompile;
+
+use Test::More tests => 7;
+
+ok try_compile_and_link(1), "trivial C works";
+my $ok = 12;
+ok !try_compile_and_link("---;", 'call' => sub {$ok = shift}),
+  'trivially wrong C is detected';
+ok !$ok, 'callback got correct compile status';
+ok !try_compile_and_link( 'Not_a_Perl_function();' ),
+  'missing function is detected';
+$ok = 0;
+my $res = 0;
+ok try_compile_and_link( 'printf("Extra fine\n")',
+			 'call' => sub {$ok = shift; 
+					$res = (`$_[0]` =~ /^Extra fine$/)} ),
+  'works with a callback';
+ok $ok, 'callback got correct compile status';
+ok $res, 'callback can execute the executable';
--- ./lib/ExtUtils/TestCompile.pm-pre	Tue Jul 15 21:17:26 2003
+++ ./lib/ExtUtils/TestCompile.pm	Tue Jul 15 21:10:04 2003
@@ -0,0 +1,354 @@
+# Extracted from Time::Hires Makefile.PL v1.50
+# Better TMPDIR, catfile
+# pass_cc_error => 0 ignored on VMS
+package ExtUtils::TestCompile;
+require 5.002;
+
+require Exporter;
+@ISA = 'Exporter';
+@EXPORT = 'try_compile_and_link';
+$VERSION = '0.01';
+
+use strict;
+use Config;
+
+my $ld_exeext = ($^O eq 'os2' and $Config{ldflags} =~ /-Zexe\b/) ? '.exe' : '';
+
+# Perls 5.002 and 5.003 did not have File::Spec, fake what we need.
+
+{
+  package ExtUtils::TestCompile::utils;
+  sub my_dirsep {
+    $^O eq 'VMS' ? '.' :
+      $^O =~ /mswin32|netware|djgpp/i ? '\\' :
+	$^O eq 'MacOS' ? ':'
+	  : '/';
+  }
+
+  sub my_catdir {
+    shift;
+    my $catdir = join(my_dirsep, @_);
+    $^O eq 'VMS' ? "[$catdir]" : $catdir;
+  }
+
+  sub my_catfile {
+    shift;
+    return join(my_dirsep, @_) unless $^O eq 'VMS';
+    my $file = pop;
+    return my_catdir (undef, @_) . $file;
+  }
+
+  sub my_updir {
+    shift;
+    $^O eq 'VMS' ? "-" : "..";
+  }
+
+  sub curdir {
+    return $^O eq 'VMS' ? '[]' : '.';
+  }
+}
+
+BEGIN {
+    eval { require File::Spec };
+    if ($@) {
+	*File::Spec::catdir  = \&ExtUtils::TestCompile::utils::my_catdir;
+	*File::Spec::curdir  = \&ExtUtils::TestCompile::utils::my_curdir;
+	*File::Spec::catfile  = \&ExtUtils::TestCompile::utils::my_catfile;
+	*File::Spec::updir   = \&ExtUtils::TestCompile::utils::my_updir;
+    }
+}
+
+# Avoid 'used only once' warnings.
+my $nop1 = *File::Spec::catdir;
+my $nop2 = *File::Spec::updir;
+my $nop3 = *File::Spec::catfile;
+my $nop4 = *File::Spec::curdir;
+
+# if you have 5.004_03 (and some slightly older versions?), xsubpp
+# tries to generate line numbers in the C code generated from the .xs.
+# unfortunately, it is a little buggy around #ifdef'd code.
+# my choice is leave it in and have people with old perls complain
+# about the "Usage" bug, or leave it out and be unable to compile myself
+# without changing it, and then I'd always forget to change it before a
+# release. Sorry, Edward :)
+
+sub TMPDIR {
+    return File::Spec::tmpdir() if defined &File::Spec::tmpdir;
+    my $TMPDIR =
+	(grep(-d $_ && -w _,
+	      ((defined $ENV{'TMPDIR'}	? $ENV{'TMPDIR'} : ()),
+	       (defined $ENV{'TMP'}	? $ENV{'TMP'} : ()),
+	       (defined $ENV{'TEMP'}	? $ENV{'TEMP'} : ()),
+	       qw(/var/tmp /usr/tmp /tmp c:/temp))))[0];
+    $TMPDIR || die "Cannot find writable temporary directory.\n";
+}
+
+sub _try_compile_and_link ($@) {
+    my $c = shift;
+    # cccmd ccflags tmp_dir_basename cc core_incdir (undef OK) print_cccmd
+    my %args = (libs => [], unlink_exe => 1, pass_cc_error => 0,
+		tmp_basename => "tmp$$", @_);
+
+    my ($ok) = 0;
+    my ($tmp) = (($^O eq 'VMS')
+		 ? "sys\$scratch:$args{tmp_basename}"
+		 : File::Spec->catfile(TMPDIR(), $args{tmp_basename}));
+    $tmp = $args{tmp_dir_basename} if defined $args{tmp_dir_basename};
+    local(*TMPC);
+
+    my $obj_ext = $Config{obj_ext} || ".o";
+    unlink("$tmp.c", "$tmp$obj_ext");
+
+    if (open(TMPC, ">$tmp.c")) {
+	print TMPC $c;
+	close(TMPC);
+
+	my $errornull;
+	my $COREincdir;
+	my $corelevel = 0;
+
+	if (defined $args{core_incdir}) {
+	  $COREincdir = "$args{core_incdir}";
+	} elsif (not exists $args{core_incdir}) {
+	  if ($ENV{PERL_CORE}) {
+	    if (-f 'perlapi.h') {
+	      $COREincdir = File::Spec->curdir;
+	    } else {
+	      my $updir = File::Spec->updir;
+	      while (++$corelevel < 10) {
+		$COREincdir = File::Spec->catdir(($updir) x $corelevel);
+		last if -f File::Spec->catfile($COREincdir, 'perlapi.h');
+	      }
+	      die "Can't find Perl build directory upwards of us"
+		unless defined $COREincdir;
+	    }
+	  } elsif ($^O eq 'VMS') {
+	    my $perl_core = $Config{'installarchlib'};
+	    $perl_core =~ s/\]$/.CORE]/;
+	    $COREincdir = "perl_root:[000000],$perl_core";
+	  } else {
+	    $COREincdir = File::Spec->catdir($Config{'archlibexp'}, 'CORE');
+	  }
+	}
+
+	my $ccflags = $args{ccflags};
+	$ccflags = ($^O eq 'VMS' ? '' : $Config{'ccflags'})	# XXXX???
+	  unless defined $ccflags;
+	if (defined $COREincdir) {
+	  if ($^O eq 'VMS') {
+	    $ccflags .= " /include=($COREincdir)";
+	  } else {
+	    $ccflags .= " -I$COREincdir";
+	  }
+	}
+
+        if ($args{pass_cc_error} || $^O eq 'VMS') {
+	    $errornull = '';
+	} else {
+	    $errornull = "2>/dev/null";
+	}
+
+	my $output = ($^O eq 'VMS' ? '' : "-o $tmp");
+
+	my $cccmd = $args{cccmd};
+	my $cc = $args{cc};
+	$cc = $Config{'cc'} unless defined $cc;
+        $cccmd = "$cc $output $ccflags $tmp.c @{$args{libs}} $errornull"
+	    unless defined $cccmd;
+
+       if ($^O eq 'VMS') {
+	    open( CMDFILE, ">$tmp.com" );
+	    print CMDFILE "\$ SET MESSAGE/NOFACILITY/NOSEVERITY/NOIDENT/NOTEXT\n";
+	    print CMDFILE "\$ $cccmd\n";
+	    print CMDFILE "\$ IF \$SEVERITY .NE. 1 THEN EXIT 44\n"; # escalate
+	    close CMDFILE;
+	    system("\@ $tmp.com");
+	    $ok = $?==0;
+	    &{$args{call}}($ok, "$tmp$Config{exe_ext}", $tmp)
+	      if defined $args{call};
+	    for ("$tmp.c", "$tmp$obj_ext", "$tmp.com",
+		 ($args{unlink_exe} ? "$tmp$Config{exe_ext}" : ())) {
+		1 while unlink $_;
+	    }
+        }
+        else
+        {
+	    my $tmp_exe = "$tmp$ld_exeext";
+	    my $print_cccmd = $args{print_cccmd};
+	    $print_cccmd = 'cccmd = ' if $print_cccmd and $print_cccmd eq '1';
+	    printf "$print_cccmd$cccmd\n" if defined $print_cccmd;
+	    my $res = system($cccmd);
+	    $ok = defined($res) && $res==0 && -s $tmp_exe && -x _;
+	    &{$args{call}}($ok, $tmp_exe, $tmp) if defined $args{call};
+	    unlink("$tmp.c", ($args{unlink_exe} ? $tmp_exe : ()));
+        }
+    } else {
+        die "Can't open `$tmp.c' for write"
+    }
+
+    $ok;
+}
+
+sub try_compile_and_link {
+    my ($c, %args) = @_;
+    %args = ( 'perl_preamble' => 1, 'in_main' => 1, 'pre_main' => '', %args);
+
+    my $inc = '';
+    my $incs = $args{extra_includes} || [];
+    die "Expecting even number of args in options{extra_includes}"
+      if @$incs % 2;
+    while (@$incs) {
+      my $include = shift @$incs;
+      my $cond = shift @$incs;
+      my ($pre, $post, $spaces) = ('', '', '');
+      if ($cond ne 1) {
+	$cond = "#ifdef $cond" if $cond =~ /^\w+\Z/;
+	$pre = "$cond\n";
+	$post = "\n#endif";
+	$spaces = "  ";
+      }
+      $inc .= <<EOI
+$pre#${spaces}include <$include>$post
+
+EOI
+    }
+
+    my $preamble = ($args{perl_preamble} ? <<EOP : '');
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+
+EOP
+    my ($pre, $post) = ($preamble ? ('_(', ')') : ('', ''));
+    $c = <<EOC if $args{'in_main'};
+$args{pre_main}
+int main $pre(int argc, char** argv, char** env)$post
+{
+    if (1) {
+	$c;
+    }
+    return 0;
+}
+EOC
+    return _try_compile_and_link("$preamble$inc$c", %args);
+}
+
+
+1;
+
+__END__
+
+=head1 NAME
+
+ExtUtils::TestCompile - check whether a C construct is supported
+
+=head1 SYNOPSIS
+
+  $res = try_compile_and_link( 'some_function()' );
+  my $out;
+  $res = try_compile_and_link( 'printf("%d\n", some_function())',
+			       call => sub { return unless shift;
+					     $out = `$_[0]` } );
+
+=head1 DESCRIPTION
+
+This module exports one function, try_compile_and_link().  It takes as
+an argument C code to compile, and a hash of options.  It returns true
+if the compile/link succeeded; temporary files are removed by default.
+
+The following options are recognized:
+
+=over
+
+=item call
+
+a subroutine to call after the compile/link, but before the removal of
+temporary files.  Three arguments are: the indicator of success of
+compile (true if success), the full name of the executable, and the
+name of the executable without extension.  Default: none.
+
+=item perl_preamble
+
+whether to prepend the Perl C boilerplate before the C code.  Default: true.
+
+=item in_main
+
+whether to put the supplied C code inside a block in main() C
+subroutine (the code is terminated by C<;>).  Default: true.
+
+=item pre_main
+
+C code to put before the main() function (ignored unless C<in_main> is true).
+Default: none.
+
+=item extra_includes
+
+the list of extra headers to C<#include>.  The value is an array
+reference with two elements per include: file name, and the condition.
+If the condition is 1, include is performed unconditionally; if the
+condition is a word, it is considered as C<#ifdef> to guard the
+include; otherwise the condition should be a complete line with C<#if>
+directive.  Default: none.
+
+=item libs
+
+Array reference with extra libraries to link against.  Default: none.
+
+=item print_cccmd
+
+if true, the compile/link cmd will be emited on STDOUT; it will be
+prefixed with the content of the value (unless value is 1, which
+prefixes C<cccmd = >).  Default: false.
+
+=item pass_cc_error
+
+If false, the error output from the compiler is suppressed.  Default: false.
+
+=item unlink_exe
+
+if false, the executable is not unlinked before return.  Default: true.
+
+=item tmp_basename
+
+the basename of the executable to create.  Default: C<"tmp$$">.
+
+=item tmp_dir_basename
+
+The full name of the C file and the executable to create (without
+extension).  Default: created with C<tmp_basename> in temporary
+directory.
+
+=item core_incdir
+
+The include directory with Perl headers; if undef, use none.  Default:
+calculated.
+
+=item cc
+
+compiler to use.  Default:  C<$Config{cc}>
+
+=item ccflags
+
+compiler flags to use.  Default:  C<$Config{ccflags}>, none on VMS.
+
+=item cccmd
+
+The full command line of the link stage.  Default: calculated basing
+on C<cc> and C<ccflags>, the names of the executable and the C file,
+extra libraries, directory of Perl headers, and error message suppression,
+
+=back
+
+=head1 BUGS
+
+Error messages suppression does not work on VMS.  Tests are
+(temporarily?) disabled on UTS and UWin too, since L<Time::Hires> is
+not supported on these architectures.
+
+=head1 AUTHOR
+
+The code is extracted from F<Makefile.PL> for C<Time::HiRes> (with
+significant modularization and cleanup) by Ilya Zakharevich <cpan@ilyaz.org>.
+
+=cut
+
