#!/usr/bin/perl # # In general we trust %Config, but for nanosleep() this trust # may be misplaced (it may be linkable but not really functional). # Use $ENV{FORCE_NANOSLEEP_SCAN} to force rescanning whether there # really is hope. { use 5.006; } use Config; use ExtUtils::MakeMaker; use strict; my $VERBOSE = $ENV{VERBOSE}; my $DEFINE; my $LIBS = []; my $XSOPT = ''; my $SYSCALL_H; our $self; # Used in 'sourcing' the hints. # TBD: Can we just use $Config(exe_ext) here instead of this complex # expression? my $ld_exeext = ($^O eq 'cygwin' || $^O eq 'os2' && $Config{ldflags} =~ /-Zexe\b/) ? '.exe' : (($^O eq 'vos') ? $Config{exe_ext} : ''); unless($ENV{PERL_CORE}) { $ENV{PERL_CORE} = 1 if grep { $_ eq 'PERL_CORE=1' } @ARGV; } # Perls 5.002 and 5.003 did not have File::Spec, fake what we need. 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' ? "-" : ".."; } BEGIN { eval { require File::Spec }; if ($@) { *File::Spec::catdir = \&my_catdir; *File::Spec::updir = \&my_updir; *File::Spec::catfile = \&my_catfile; } } # Avoid 'used only once' warnings. my $nop1 = *File::Spec::catdir; my $nop2 = *File::Spec::updir; my $nop3 = *File::Spec::catfile; # 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 try_compile_and_link { my ($c, %args) = @_; my ($ok) = 0; my ($tmp) = "tmp$$"; 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 $cccmd = $args{cccmd}; my $errornull; my $COREincdir; if ($ENV{PERL_CORE}) { my $updir = File::Spec->updir; $COREincdir = File::Spec->catdir(($updir) x 2); } else { $COREincdir = File::Spec->catdir($Config{'archlibexp'}, 'CORE'); } if ($ENV{PERL_CORE}) { unless (-f File::Spec->catfile($COREincdir, "EXTERN.h")) { die <<__EOD__; Your environment variable PERL_CORE is '$ENV{PERL_CORE}' but there is no EXTERN.h in $COREincdir. Cannot continue, aborting. __EOD__ } } my $ccflags = $Config{'ccflags'} . ' ' . "-I$COREincdir" . ' -DPERL_NO_INLINE_FUNCTIONS'; if ($^O eq 'VMS') { $cccmd = "$Config{'cc'} /include=($COREincdir) $tmp.c"; } if ($args{silent} || !$VERBOSE) { $errornull = "2>/dev/null" unless defined $errornull; } else { $errornull = ''; } $cccmd = "$Config{'cc'} -o $tmp $ccflags $tmp.c @$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; for ("$tmp.c", "$tmp$obj_ext", "$tmp.com", "$tmp$Config{exe_ext}") { 1 while unlink $_; } } else { my $tmp_exe = "$tmp$ld_exeext"; printf "cccmd = $cccmd\n" if $VERBOSE; my $res = system($cccmd); $ok = defined($res) && $res == 0 && -s $tmp_exe && -x _; if ( $ok && exists $args{run} && $args{run} && !$ENV{TIME_HIRES_DONT_RUN_PROBES} ) { my $tmp_exe = File::Spec->catfile(File::Spec->curdir, $tmp_exe); my @run = $tmp_exe; unshift @run, $Config{run} if $Config{run} && -e $Config{run}; printf "Running $tmp_exe..." if $VERBOSE; if (system(@run) == 0) { $ok = 1; } else { $ok = 0; my $errno = $? >> 8; local $! = $errno; printf < #endif #ifdef I_SYS_TIME # include #endif #ifdef I_SYS_SELECT # include /* struct timeval might be hidden in here */ #endif EOH sub has_gettimeofday { # confusing but true (if condition true ==> -DHAS_GETTIMEOFDAY already) return 0 if $Config{d_gettimeod}; return 1 if try_compile_and_link(< #endif #ifdef I_SYS_TYPES # include #endif #ifdef I_SYS_TIME # include #endif int main(int argc, char** argv) { $x; } EOM return 0; } sub has_nanosleep { print "testing... "; return 1 if try_compile_and_link(< 1); #include #include #include #include #include /* int nanosleep(const struct timespec *rqtp, struct timespec *rmtp); */ int main(int argc, char** argv) { struct timespec ts1, ts2; int ret; ts1.tv_sec = 0; ts1.tv_nsec = 750000000; ts2.tv_sec = 0; ts2.tv_nsec = 0; errno = 0; ret = nanosleep(&ts1, &ts2); /* E.g. in AIX nanosleep() fails and sets errno to ENOSYS. */ ret == 0 ? exit(0) : exit(errno ? errno : -1); } EOM } sub has_include { my ($inc) = @_; return 1 if try_compile_and_link(< int main(int argc, char** argv) { return 0; } EOM return 0; } sub has_clock_xxx_syscall { my $x = shift; return 0 unless defined $SYSCALL_H; return 1 if try_compile_and_link(< 1); #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include #include <$SYSCALL_H> int main(int argc, char** argv) { struct timespec ts; /* Many Linuxes get ENOSYS even though the syscall exists. */ /* All implementations are supposed to support CLOCK_REALTIME. */ int ret = syscall(SYS_clock_$x, CLOCK_REALTIME, &ts); ret == 0 ? exit(0) : exit(errno ? errno : -1); } EOM } sub has_clock_xxx { my $xxx = shift; return 1 if try_compile_and_link(< 1); #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include int main(int argc, char** argv) { struct timespec ts; int ret = clock_$xxx(CLOCK_REALTIME, &ts); /* Many Linuxes get ENOSYS. */ /* All implementations are supposed to support CLOCK_REALTIME. */ ret == 0 ? exit(0) : exit(errno ? errno : -1); } EOM } sub has_clock { return 1 if try_compile_and_link(< 1); #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include int main(int argc, char** argv) { clock_t tictoc; clock_t ret = clock(); ret == (clock_t)-1 ? exit(errno ? errno : -1) : exit(0); } EOM } sub has_clock_nanosleep { return 1 if try_compile_and_link(< 1); #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include int main(int argc, char** argv) { int ret; struct timespec ts1; struct timespec ts2; ts1.tv_sec = 0; ts1.tv_nsec = 750000000;; /* All implementations are supposed to support CLOCK_REALTIME. */ ret = clock_nanosleep(CLOCK_REALTIME, 0, &ts1, &ts2); ret == 0 ? exit(0) : exit(errno ? errno : -1); } EOM } sub has_futimens { return 1 if try_compile_and_link(< int main(int argc, char** argv) { int ret; struct timespec ts[2]; ret = futimens(0, ts); ret == 0 ? exit(0) : exit(errno ? errno : -1); } EOM } sub has_utimensat{ return 1 if try_compile_and_link(< #include int main(int argc, char** argv) { int ret; struct timespec ts[2]; ret = utimensat(AT_FDCWD, 0, ts, 0); ret == 0 ? exit(0) : exit(errno ? errno : -1); } EOM } sub has_clockid_t{ return 1 if try_compile_and_link(< int main(int argc, char** argv) { clockid_t id = CLOCK_REALTIME; exit(id == CLOCK_REALTIME ? 1 : 0); } EOM } sub DEFINE { my ($def, $val) = @_; my $define = defined $val ? "$def=$val" : $def ; unless ($DEFINE =~ /(?:^| )-D\Q$define\E(?: |$)/) { $DEFINE .= " -D$define"; } } sub init { my $hints = File::Spec->catfile("hints", "$^O.pl"); if (-f $hints) { print "Using hints $hints...\n"; local $self; do $hints; if (exists $self->{LIBS}) { $LIBS = $self->{LIBS}; print "Extra libraries: @$LIBS...\n"; } } $DEFINE = ''; if ($Config{d_syscall}) { print "Have syscall()... looking for syscall.h... "; if (has_include('syscall.h')) { $SYSCALL_H = 'syscall.h'; } elsif (has_include('sys/syscall.h')) { $SYSCALL_H = 'sys/syscall.h'; } } else { print "No syscall()...\n"; } if ($Config{d_syscall}) { if (defined $SYSCALL_H) { print "found <$SYSCALL_H>.\n"; } else { print "NOT found.\n"; } } print "Looking for gettimeofday()... "; my $has_gettimeofday; if (exists $Config{d_gettimeod}) { $has_gettimeofday++ if $Config{d_gettimeod}; } elsif (has_gettimeofday()) { $DEFINE .= ' -DHAS_GETTIMEOFDAY'; $has_gettimeofday++; } if ($has_gettimeofday) { print "found.\n"; } else { die < int main(int argc, char** argv) { struct stat st; st.st_atimespec.tv_nsec = 0; } EOM $has_stat_st_xtimespec++; DEFINE('TIME_HIRES_STAT_ST_XTIMESPEC'); # 1 } if ($has_stat_st_xtimespec) { print "found.\n"; } else { print "NOT found.\n"; } print "Trying struct stat st_atimensec..."; my $has_stat_st_xtimensec; if (try_compile_and_link(< int main(int argc, char** argv) { struct stat st; st.st_atimensec = 0; } EOM $has_stat_st_xtimensec++; DEFINE('TIME_HIRES_STAT_ST_XTIMENSEC'); # 2 } if ($has_stat_st_xtimensec) { print "found.\n"; } else { print "NOT found.\n"; } print "Trying struct stat st_atime_n..."; my $has_stat_st_xtime_n; if (try_compile_and_link(< int main(int argc, char** argv) { struct stat st; st.st_atime_n = 0; } EOM $has_stat_st_xtime_n++; DEFINE('TIME_HIRES_STAT_ST_XTIME_N'); # 3 } if ($has_stat_st_xtime_n) { print "found.\n"; } else { print "NOT found.\n"; } print "Trying struct stat st_atim.tv_nsec..."; my $has_stat_st_xtim; if (try_compile_and_link(< int main(int argc, char** argv) { struct stat st; st.st_atim.tv_nsec = 0; } EOM $has_stat_st_xtim++; DEFINE('TIME_HIRES_STAT_XTIM'); # 4 } if ($has_stat_st_xtim) { print "found.\n"; } else { print "NOT found.\n"; } print "Trying struct stat st_uatime..."; my $has_stat_st_uxtime; if (try_compile_and_link(< int main(int argc, char** argv) { struct stat st; st.st_uatime = 0; } EOM $has_stat_st_uxtime++; DEFINE('TIME_HIRES_STAT_ST_UXTIME'); # 5 } if ($has_stat_st_uxtime) { print "found.\n"; } else { print "NOT found.\n"; } # See HiRes.xs hrstatns() if ($has_stat_st_xtimespec) { DEFINE('TIME_HIRES_STAT', 1); } elsif ($has_stat_st_xtimensec) { DEFINE('TIME_HIRES_STAT', 2); } elsif ($has_stat_st_xtime_n) { DEFINE('TIME_HIRES_STAT', 3); } elsif ($has_stat_st_xtim) { DEFINE('TIME_HIRES_STAT', 4); } elsif ($has_stat_st_uxtime) { DEFINE('TIME_HIRES_STAT', 5); } if ($DEFINE =~ /-DTIME_HIRES_STAT=\d+/) { print "You seem to have stat() subsecond timestamps.\n"; print "(Your struct stat has them, but the filesystems must help.)\n"; } else { print "You do not seem to have stat subsecond timestamps.\n"; } my $has_w32api_windows_h; if ($^O eq 'cygwin') { print "Looking for ... "; if (has_include('w32api/windows.h')) { $has_w32api_windows_h++; DEFINE('HAS_W32API_WINDOWS_H'); } if ($has_w32api_windows_h) { print "found.\n"; } else { print "NOT found.\n"; } } if ($DEFINE) { $DEFINE =~ s/^\s+//; if (open(XDEFINE, '>', 'xdefine')) { print XDEFINE $DEFINE, "\n"; close(XDEFINE); } } } sub doMakefile { my @makefileopts = (); if ($] >= 5.005) { push (@makefileopts, 'AUTHOR' => 'Jarkko Hietaniemi ', 'ABSTRACT_FROM' => 'HiRes.pm', ); DEFINE('ATLEASTFIVEOHOHFIVE'); } push (@makefileopts, 'NAME' => 'Time::HiRes', 'VERSION_FROM' => 'HiRes.pm', # finds $VERSION 'LIBS' => $LIBS, # e.g., '-lm' 'DEFINE' => $DEFINE, # e.g., '-DHAS_SOMETHING' 'XSOPT' => $XSOPT, # Do not even think about 'INC' => '-I/usr/ucbinclude', # Solaris will avenge. 'INC' => '', # e.g., '-I/usr/include/other' 'INSTALLDIRS' => ($] >= 5.008 && $] < 5.011 ? 'perl' : 'site'), 'PREREQ_PM' => { 'Carp' => 0, 'Config' => 0, 'DynaLoader' => 0, 'Exporter' => 0, 'ExtUtils::MakeMaker' => 0, 'Test::More' => 0, 'strict' => 0, }, 'dist' => { 'CI' => 'ci -l', 'COMPRESS' => 'gzip -9f', 'SUFFIX' => 'gz', }, clean => { FILES => "xdefine" }, realclean => { FILES=> 'const-c.inc const-xs.inc' }, ); if ($^O eq "MSWin32" && !(grep { /\ALD[A-Z]*=/ } @ARGV)) { my $libperl = $Config{libperl} || ""; my $gccversion = $Config{gccversion} || ""; if ($gccversion =~ /\A3\.4\.[0-9]+/ and $libperl =~ /\.lib\z/) { # Avoid broken linkage with ActivePerl, by linking directly # against the Perl DLL rather than the import library. (my $llibperl = "-l$libperl") =~ s/\.lib\z//; my $lddlflags = $Config{lddlflags} || ""; my $ldflags = $Config{ldflags} || ""; s/-L(?:".*?"|\S+)//g foreach $lddlflags, $ldflags; my $libdirs = join ' ', map { s/(? { LDDLFLAGS => "$lddlflags $libdirs $llibperl", LDFLAGS => "$ldflags $libdirs $llibperl", PERL_ARCHIVE => "", }; } } if ($ENV{PERL_CORE}) { push @makefileopts, MAN3PODS => {}; } if ($ExtUtils::MakeMaker::VERSION >= 6.48) { push @makefileopts, (MIN_PERL_VERSION => '5.008',); } if ($ExtUtils::MakeMaker::VERSION >= 6.31) { push @makefileopts, (LICENSE => 'perl_5'); } WriteMakefile(@makefileopts); } sub doConstants { if (eval {require ExtUtils::Constant; 1}) { my @names = qw( CLOCKS_PER_SEC CLOCK_BOOTTIME CLOCK_HIGHRES CLOCK_MONOTONIC CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC_PRECISE CLOCK_MONOTONIC_RAW CLOCK_PROCESS_CPUTIME_ID CLOCK_REALTIME CLOCK_REALTIME_COARSE CLOCK_REALTIME_FAST CLOCK_REALTIME_PRECISE CLOCK_SECOND CLOCK_SOFTTIME CLOCK_THREAD_CPUTIME_ID CLOCK_TIMEOFDAY CLOCK_UPTIME CLOCK_UPTIME_FAST CLOCK_UPTIME_PRECISE ITIMER_PROF ITIMER_REAL ITIMER_REALPROF ITIMER_VIRTUAL TIMER_ABSTIME ); foreach (qw (d_usleep d_ualarm d_gettimeofday d_getitimer d_setitimer d_nanosleep d_clock_gettime d_clock_getres d_clock d_clock_nanosleep d_hires_stat d_futimens d_utimensat d_hires_utime)) { my $macro = $_; if ($macro =~ /^(d_nanosleep|d_clock)$/) { $macro =~ s/^d_(.+)/TIME_HIRES_\U$1/; } elsif ($macro =~ /^(d_hires_stat)$/) { my $d_hires_stat = 0; $d_hires_stat = $1 if ($DEFINE =~ /-DTIME_HIRES_STAT=(\d+)/); push @names, {name => $_, macro => "TIME_HIRES_STAT", value => $d_hires_stat, default => ["IV", "0"]}; next; } elsif ($macro =~ /^(d_hires_utime)$/) { my $d_hires_utime = ($DEFINE =~ /-DHAS_FUTIMENS/ || $DEFINE =~ /-DHAS_UTIMENSAT/) ? 1 : 0; push @names, {name => $_, macro => "TIME_HIRES_UTIME", value => $d_hires_utime, default => ["IV", "0"]}; next; } elsif ($macro =~ /^(d_clock_gettime|d_clock_getres|d_clock_nanosleep)$/) { $macro =~ s/^d_(.+)/TIME_HIRES_\U$1/; my $val = ($DEFINE =~ /-D$macro\b/) ? 1 : 0; push @names, {name => $_, macro => $macro, value => $val, default => ["IV", "0"]}; next; } else { $macro =~ s/^d_(.+)/HAS_\U$1/; } push @names, {name => $_, macro => $macro, value => 1, default => ["IV", "0"]}; } ExtUtils::Constant::WriteConstants( NAME => 'Time::HiRes', NAMES => \@names, ); } else { my $file; foreach $file ('const-c.inc', 'const-xs.inc') { my $fallback = File::Spec->catfile('fallback', $file); local $/; open IN, '<', $fallback or die "Can't open $fallback: $!"; open OUT, '>', $file or die "Can't open $file: $!"; print OUT or die $!; close OUT or die "Can't close $file: $!"; close IN or die "Can't close $fallback: $!"; } } } sub main { if (-f "xdefine" && !(@ARGV && $ARGV[0] eq '--configure')) { print qq[$0: The "xdefine" exists, skipping the configure step.\n]; print qq[("$^X $0 --configure" to force the configure step)\n]; } else { print "Configuring Time::HiRes...\n"; 1 while unlink("define"); if ($^O =~ /Win32/i) { DEFINE('SELECT_IS_BROKEN'); $LIBS = []; print "System is $^O, skipping full configure...\n"; open(XDEFINE, '>', 'xdefine') or die "$0: Cannot create xdefine: $!\n"; close(XDEFINE); } else { init(); } doMakefile; doConstants; } my $make = $Config{'make'} || "make"; unless (exists $ENV{PERL_CORE} && $ENV{PERL_CORE}) { print <