#!/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. require 5.002; use Config; use ExtUtils::MakeMaker; use strict; my $VERBOSE = $ENV{VERBOSE}; my $DEFINE; my $LIBS = []; my $XSOPT = ''; my $SYSCALL_H; use vars qw($self); # Used in 'sourcing' the hints. my $ld_exeext = ($^O eq 'cygwin' || $^O eq 'os2' && $Config{ldflags} =~ /-Zexe\b/) ? '.exe' : ''; 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 3); } else { $COREincdir = File::Spec->catdir($Config{'archlibexp'}, 'CORE'); } my $ccflags = $Config{'ccflags'} . ' ' . "-I$COREincdir"; if ($^O eq 'VMS') { if ($ENV{PERL_CORE}) { # Fragile if the extensions change hierarchy within # the Perl core but this should do for now. $cccmd = "$Config{'cc'} /include=([---]) $tmp.c"; } else { my $perl_core = $Config{'installarchlib'}; $perl_core =~ s/\]$/.CORE]/; $cccmd = "$Config{'cc'} /include=(perl_root:[000000],$perl_core) $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}) { my $tmp_exe = File::Spec->catfile(File::Spec->curdir, $tmp_exe); printf "Running $tmp_exe..." if $VERBOSE; if (system($tmp_exe) == 0) { $ok = 1; } else { $ok = 0; my $errno = $? >> 8; local $! = $errno; printf < -DHAS_GETTIMEOFDAY already) return 0 if $Config{d_gettimeod}; return 1 if try_compile_and_link(< #endif #ifdef I_SYS_TIME # include #endif #ifdef I_SYS_SELECT # include /* struct timeval might be hidden in here */ #endif static int foo() { struct timeval tv; gettimeofday(&tv, 0); } int main _((int argc, char** argv, char** env)) { foo(); } EOM return 0; } sub has_x { my ($x, %args) = @_; 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, char** env)) { $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() { 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, char** env)) { return 0; } EOM return 0; } sub has_clock_x_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 <$SYSCALL_H> int main _((int argc, char** argv, char** env)) { 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_x { my $x = shift; return 1 if try_compile_and_link(< 1); #include "EXTERN.h" #include "perl.h" #include "XSUB.h" int main _((int argc, char** argv, char** env)) { struct timespec ts; int ret = clock_$x(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 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'; } } 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 <... "; if (has_include('w32api/windows.h')) { $has_w32api_windows_h++; $DEFINE .= ' -DHAS_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 .= " -DATLEASTFIVEOHOHFIVE"; } 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 ? 'perl' : 'site'), 'dist' => { 'CI' => 'ci -l', 'COMPRESS' => 'gzip -9f', 'SUFFIX' => 'gz', }, clean => { FILES => "xdefine" }, realclean => { FILES=> 'const-c.inc const-xs.inc' }, ); if ($ENV{PERL_CORE}) { push @makefileopts, MAN3PODS => {}; } WriteMakefile(@makefileopts); } sub doConstants { if (eval {require ExtUtils::Constant; 1}) { my @names = (qw(CLOCK_HIGHRES CLOCK_MONOTONIC CLOCK_PROCESS_CPUTIME_ID CLOCK_REALTIME CLOCK_THREAD_CPUTIME_ID CLOCK_TIMEOFDAY ITIMER_REAL ITIMER_VIRTUAL ITIMER_PROF ITIMER_REALPROF)); foreach (qw (d_usleep d_ualarm d_gettimeofday d_getitimer d_setitimer d_nanosleep d_clock_gettime d_clock_getres)) { my $macro = $_; if ($macro =~ /^(d_nanosleep|d_clock_gettime|d_clock_getres)$/) { $macro =~ s/^d_(.+)/TIME_HIRES_\U$1/; } 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 { print "Configuring Time::HiRes...\n"; if ($] == 5.007002) { die "Cannot Configure Time::HiRes for Perl $], aborting.\n"; } if ($^O =~ /Win32/i) { $DEFINE = '-DSELECT_IS_BROKEN'; $LIBS = []; } else { init(); } doMakefile; doConstants; my $make = $Config{'make'} || "make"; unless (exists $ENV{PERL_CORE} && $ENV{PERL_CORE}) { print <