1#!/usr/bin/perl
2#
3# In general we trust %Config, but for nanosleep() this trust
4# may be misplaced (it may be linkable but not really functional).
5# Use $ENV{FORCE_NANOSLEEP_SCAN} to force rescanning whether there
6# really is hope.
7
8{ use 5.006; }
9
10use Config;
11use ExtUtils::MakeMaker;
12use strict;
13
14use File::Spec;
15
16my $VERBOSE = $ENV{VERBOSE};
17my $DEFINE;
18my $LIBS = [];
19my $XSOPT = '';
20my $SYSCALL_H;
21
22our $self; # Used in 'sourcing' the hints.
23
24# TBD: Can we just use $Config(exe_ext) here instead of this complex
25#      expression?
26my $ld_exeext = ($^O eq 'cygwin' ||
27                 $^O eq 'os2' && $Config{ldflags} =~ /-Zexe\b/) ? '.exe' :
28                (($^O eq 'vos') ? $Config{exe_ext} : '');
29
30unless($ENV{PERL_CORE}) {
31    $ENV{PERL_CORE} = 1 if grep { $_ eq 'PERL_CORE=1' } @ARGV;
32}
33
34sub try_compile_and_link {
35    my ($c, %args) = @_;
36
37    my ($ok) = 0;
38    my ($tmp) = "tmp$$";
39    local(*TMPC);
40
41    my $obj_ext = $Config{obj_ext} || ".o";
42    unlink("$tmp.c", "$tmp$obj_ext");
43
44    if (open(TMPC, '>', "$tmp.c")) {
45        print TMPC $c;
46        close(TMPC);
47
48        my $cccmd = $args{cccmd};
49
50        my $errornull;
51
52        my $COREincdir;
53
54        if ($ENV{PERL_CORE}) {
55            my $updir = File::Spec->updir;
56            $COREincdir = File::Spec->catdir(($updir) x 2);
57        } else {
58            $COREincdir = File::Spec->catdir($Config{'archlibexp'}, 'CORE');
59        }
60
61        if ($ENV{PERL_CORE}) {
62            unless (-f File::Spec->catfile($COREincdir, "EXTERN.h")) {
63                die <<__EOD__;
64Your environment variable PERL_CORE is '$ENV{PERL_CORE}' but there
65is no EXTERN.h in $COREincdir.
66Cannot continue, aborting.
67__EOD__
68            }
69        }
70
71        my $ccflags = $Config{'ccflags'} . ' ';
72        my @osvers = split /\./, $Config{osvers};
73        if ($^O eq "darwin"
74            && $^X eq "/usr/bin/perl"
75            && $osvers[0] >= 18) {
76            $ccflags .= qq(-iwithsysroot "$COREincdir");
77        }
78        else {
79            $ccflags .= "-I$COREincdir"
80        }
81        $ccflags .= ' -DPERL_NO_INLINE_FUNCTIONS';
82
83        if ($^O eq 'VMS') {
84            $cccmd = "$Config{'cc'} $Config{'ccflags'} /include=($COREincdir) $tmp.c";
85        }
86
87        if ($args{silent} || !$VERBOSE) {
88            $errornull = "2>/dev/null" unless defined $errornull;
89        } else {
90            $errornull = '';
91        }
92
93        $cccmd = "$Config{'cc'} -o $tmp $ccflags $tmp.c @$LIBS $errornull"
94            unless defined $cccmd;
95
96       if ($^O eq 'VMS') {
97            open( CMDFILE, '>', "$tmp.com" );
98            print CMDFILE "\$ SET MESSAGE/NOFACILITY/NOSEVERITY/NOIDENT/NOTEXT\n";
99            print CMDFILE "\$ $cccmd\n";
100            print CMDFILE "\$ IF \$SEVERITY .NE. 1 THEN EXIT 44\n"; # escalate
101            close CMDFILE;
102            system("\@ $tmp.com");
103            $ok = $?==0;
104            for ("$tmp.c", "$tmp$obj_ext", "$tmp.com", "$tmp$Config{exe_ext}") {
105                1 while unlink $_;
106            }
107        }
108        else
109        {
110            my $tmp_exe = "$tmp$ld_exeext";
111            printf "cccmd = $cccmd\n" if $VERBOSE;
112            my $res = system($cccmd);
113            $ok = defined($res) && $res == 0 && -s $tmp_exe && -x _;
114
115            if ( $ok && exists $args{run} && $args{run} && !$ENV{TIME_HIRES_DONT_RUN_PROBES} ) {
116                my $tmp_exe =
117                    File::Spec->catfile(File::Spec->curdir, $tmp_exe);
118                my @run = $tmp_exe;
119                unshift @run, $Config{run} if $Config{run} && -e $Config{run};
120                printf "Running $tmp_exe..." if $VERBOSE;
121                if (system(@run) == 0) {
122                    $ok = 1;
123                } else {
124                    $ok = 0;
125                    my $errno = $? >> 8;
126                    local $! = $errno;
127                    printf <<EOF;
128
129*** The test run of '$tmp_exe' failed: status $?
130*** (the status means: errno = $errno or '$!')
131*** DO NOT PANIC: this just means that *some* functionality will be missing.
132EOF
133                }
134            }
135            unlink("$tmp.c", $tmp_exe);
136        }
137    }
138
139    return $ok;
140}
141
142my $TIME_HEADERS = <<EOH;
143#include "EXTERN.h"
144#include "perl.h"
145#include "XSUB.h"
146#ifdef I_SYS_TYPES
147#   include <sys/types.h>
148#endif
149#ifdef I_SYS_TIME
150#   include <sys/time.h>
151#endif
152#ifdef I_SYS_SELECT
153#   include <sys/select.h>      /* struct timeval might be hidden in here */
154#endif
155EOH
156
157sub has_gettimeofday {
158    # confusing but true (if condition true ==> -DHAS_GETTIMEOFDAY already)
159    return 0 if $Config{d_gettimeod};
160    return 1 if try_compile_and_link(<<EOM);
161$TIME_HEADERS
162static int foo()
163{
164    struct timeval tv;
165    gettimeofday(&tv, 0);
166}
167int main(int argc, char** argv)
168{
169    foo();
170}
171EOM
172    return 0;
173}
174
175sub has_x {
176    my ($x, %args) = @_;
177
178    return 1 if
179    try_compile_and_link(<<EOM, %args);
180#include "EXTERN.h"
181#include "perl.h"
182#include "XSUB.h"
183
184#ifdef I_UNISTD
185#   include <unistd.h>
186#endif
187
188#ifdef I_SYS_TYPES
189#   include <sys/types.h>
190#endif
191
192#ifdef I_SYS_TIME
193#   include <sys/time.h>
194#endif
195
196int main(int argc, char** argv)
197{
198        $x;
199}
200EOM
201    return 0;
202}
203
204sub has_nanosleep {
205    print "testing... ";
206    return 1 if
207    try_compile_and_link(<<EOM, run => 1);
208#include <time.h>
209#include <sys/time.h>
210#include <stdio.h>
211#include <stdlib.h>
212#include <errno.h>
213
214/* int nanosleep(const struct timespec *rqtp, struct timespec *rmtp); */
215
216int main(int argc, char** argv) {
217    struct timespec ts1, ts2;
218    int ret;
219    ts1.tv_sec  = 0;
220    ts1.tv_nsec = 750000000;
221    ts2.tv_sec  = 0;
222    ts2.tv_nsec = 0;
223    errno = 0;
224    ret = nanosleep(&ts1, &ts2); /* E.g. in AIX nanosleep() fails and sets errno to ENOSYS. */
225    ret == 0 ? exit(0) : exit(errno ? errno : -1);
226}
227EOM
228}
229
230sub has_include {
231    my ($inc) = @_;
232    return 1 if
233    try_compile_and_link(<<EOM);
234#include "EXTERN.h"
235#include "perl.h"
236#include "XSUB.h"
237
238#include <$inc>
239int main(int argc, char** argv)
240{
241        return 0;
242}
243EOM
244    return 0;
245}
246
247sub has_clock_xxx_syscall {
248    my $x = shift;
249    return 0 unless defined $SYSCALL_H;
250    return 1 if
251    try_compile_and_link(<<EOM, run => 1);
252#include "EXTERN.h"
253#include "perl.h"
254#include "XSUB.h"
255#include <time.h>
256#include <$SYSCALL_H>
257int main(int argc, char** argv)
258{
259    struct timespec ts;
260    /* Many Linuxes get ENOSYS even though the syscall exists. */
261    /* All implementations are supposed to support CLOCK_REALTIME. */
262    int ret = syscall(SYS_clock_$x, CLOCK_REALTIME, &ts);
263    ret == 0 ? exit(0) : exit(errno ? errno : -1);
264}
265EOM
266}
267
268sub has_clock_xxx {
269    my $xxx = shift;
270    return 1 if
271    try_compile_and_link(<<EOM, run => 1);
272#include "EXTERN.h"
273#include "perl.h"
274#include "XSUB.h"
275#include <time.h>
276int main(int argc, char** argv)
277{
278    struct timespec ts;
279    int ret = clock_$xxx(CLOCK_REALTIME, &ts); /* Many Linuxes get ENOSYS. */
280    /* All implementations are supposed to support CLOCK_REALTIME. */
281    ret == 0 ? exit(0) : exit(errno ? errno : -1);
282}
283EOM
284}
285
286sub has_clock {
287    return 1 if
288    try_compile_and_link(<<EOM, run => 1);
289#include "EXTERN.h"
290#include "perl.h"
291#include "XSUB.h"
292#include <time.h>
293int main(int argc, char** argv)
294{
295    clock_t tictoc;
296    clock_t ret = clock();
297    ret == (clock_t)-1 ? exit(errno ? errno : -1) : exit(0);
298}
299EOM
300}
301
302sub has_clock_nanosleep {
303    return 1 if
304    try_compile_and_link(<<EOM, run => 1);
305#include "EXTERN.h"
306#include "perl.h"
307#include "XSUB.h"
308#include <time.h>
309int main(int argc, char** argv)
310{
311    int ret;
312    struct timespec ts1;
313    struct timespec ts2;
314    ts1.tv_sec  = 0;
315    ts1.tv_nsec = 750000000;;
316    /* All implementations are supposed to support CLOCK_REALTIME. */
317    ret = clock_nanosleep(CLOCK_REALTIME, 0, &ts1, &ts2);
318    ret == 0 ? exit(0) : exit(errno ? errno : -1);
319}
320EOM
321}
322
323sub has_futimens {
324    return 1 if
325    try_compile_and_link(<<EOM);
326#include "EXTERN.h"
327#include "perl.h"
328#include "XSUB.h"
329#include <sys/stat.h>
330int main(int argc, char** argv)
331{
332    int ret1, ret2;
333    struct timespec ts1[2], ts2[2];
334    ret1 = futimens(0, ts1);
335    char buf[1];
336    read(0, buf, 0); /* Assuming reading nothing updates atime (the [0]) */
337    ret2 = futimens(0, ts2);
338    ret1 == 0 && ret2 == 0 && (ts1[0].tv_nsec != 0 || ts2[0].tv_nsec != 0) ?
339        exit(0) : exit(errno ? errno : -1);
340}
341EOM
342}
343
344sub has_utimensat{
345    return 1 if
346    try_compile_and_link(<<EOM);
347#include "EXTERN.h"
348#include "perl.h"
349#include "XSUB.h"
350#include <sys/stat.h>
351#include <fcntl.h>
352int main(int argc, char** argv)
353{
354    int ret1, ret2;
355    struct timespec ts1[2], ts2[2];
356    /* We make the brave but probably foolish assumption that systems
357     * modern enough to have utimensat also have the /dev/stdin. */
358    ret1 = utimensat(AT_FDCWD, "/dev/stdin", ts1, 0);
359    char buf[1];
360    read(0, buf, 0); /* Assuming reading nothing updates atime (the [0]) */
361    ret2 = utimensat(AT_FDCWD, "/dev/stdin", ts2, 0);
362    ret1 == 0 && ret2 == 0 && (ts1[0].tv_nsec != 0 || ts2[0].tv_nsec != 0) ?
363        exit(0) : exit(errno ? errno : -1);
364}
365EOM
366}
367
368sub has_clockid_t{
369    return 1 if
370    try_compile_and_link(<<EOM);
371#include "EXTERN.h"
372#include "perl.h"
373#include "XSUB.h"
374#include <time.h>
375int main(int argc, char** argv)
376{
377    clockid_t id = CLOCK_REALTIME;
378    exit(id == CLOCK_REALTIME ? 1 : 0);
379}
380EOM
381}
382
383sub DEFINE {
384    my ($def, $val) = @_;
385    my $define = defined $val ? "$def=$val" : $def ;
386    unless ($DEFINE =~ /(?:^| )-D\Q$define\E(?: |$)/) {
387        $DEFINE .= " -D$define";
388    }
389}
390
391sub init {
392    my $hints = File::Spec->catfile("hints", "$^O.pl");
393    if (-f $hints) {
394        print "Using hints $hints...\n";
395        local $self;
396        do "./$hints";
397        if (exists $self->{LIBS}) {
398            $LIBS = $self->{LIBS};
399            print "Extra libraries: @$LIBS...\n";
400        }
401    }
402
403    $DEFINE = '';
404
405    if ($Config{d_syscall}) {
406        print "Have syscall()... looking for syscall.h... ";
407        if (has_include('syscall.h')) {
408            $SYSCALL_H = 'syscall.h';
409        } elsif (has_include('sys/syscall.h')) {
410            $SYSCALL_H = 'sys/syscall.h';
411        }
412    } else {
413        print "No syscall()...\n";
414    }
415
416    if ($Config{d_syscall}) {
417        if (defined $SYSCALL_H) {
418            print "found <$SYSCALL_H>.\n";
419        } else {
420            print "NOT found.\n";
421        }
422    }
423
424    print "Looking for gettimeofday()... ";
425    my $has_gettimeofday;
426    if (exists $Config{d_gettimeod}) {
427        $has_gettimeofday++ if $Config{d_gettimeod};
428    } elsif (has_gettimeofday()) {
429        $DEFINE .= ' -DHAS_GETTIMEOFDAY';
430        $has_gettimeofday++;
431    }
432
433    if ($has_gettimeofday) {
434        print "found.\n";
435    } else {
436        die <<EOD
437Your operating system does not seem to have the gettimeofday() function.
438(or, at least, I cannot find it)
439
440There is no way Time::HiRes is going to work.
441
442I am awfully sorry but I cannot go further.
443
444Aborting configuration.
445
446EOD
447    }
448
449    print "Looking for setitimer()... ";
450    my $has_setitimer;
451    if (exists $Config{d_setitimer}) {
452        $has_setitimer++ if $Config{d_setitimer};
453    } elsif (has_x("setitimer(ITIMER_REAL, 0, 0)")) {
454        $has_setitimer++;
455        $DEFINE .= ' -DHAS_SETITIMER';
456    }
457
458    if ($has_setitimer) {
459        print "found.\n";
460    } else {
461        print "NOT found.\n";
462    }
463
464    print "Looking for getitimer()... ";
465    my $has_getitimer;
466    if (exists $Config{'d_getitimer'}) {
467        $has_getitimer++ if $Config{'d_getitimer'};
468    } elsif (has_x("getitimer(ITIMER_REAL, 0)")) {
469        $has_getitimer++;
470        $DEFINE .= ' -DHAS_GETITIMER';
471    }
472
473    if ($has_getitimer) {
474        print "found.\n";
475    } else {
476        print "NOT found.\n";
477    }
478
479    if ($has_setitimer && $has_getitimer) {
480        print "You have interval timers (both setitimer and getitimer).\n";
481    } else {
482        print "You do NOT have interval timers.\n";
483    }
484
485    print "Looking for ualarm()... ";
486    my $has_ualarm;
487    if (exists $Config{d_ualarm}) {
488        $has_ualarm++ if $Config{d_ualarm};
489    } elsif (has_x ("ualarm (0, 0)")) {
490        $has_ualarm++;
491        $DEFINE .= ' -DHAS_UALARM';
492    }
493
494    if ($has_ualarm) {
495        print "found.\n";
496    } else {
497        print "NOT found.\n";
498        if ($has_setitimer) {
499            print "But you have setitimer().\n";
500            print "We can make a Time::HiRes::ualarm().\n";
501        }
502    }
503
504    print "Looking for usleep()... ";
505    my $has_usleep;
506    if (exists $Config{d_usleep}) {
507        $has_usleep++ if $Config{d_usleep};
508    } elsif (has_x ("usleep (0)")) {
509        $has_usleep++;
510        $DEFINE .= ' -DHAS_USLEEP';
511    }
512
513    if ($has_usleep) {
514        print "found.\n";
515    } else {
516        print "NOT found.\n";
517        print "Let's see if you have select()... ";
518        if ($Config{'d_select'}) {
519            print "found.\n";
520            print "We can make a Time::HiRes::usleep().\n";
521        } else {
522            print "NOT found.\n";
523            print "You won't have a Time::HiRes::usleep().\n";
524        }
525    }
526
527    print "Looking for nanosleep()... ";
528    my $has_nanosleep;
529    if ($ENV{FORCE_NANOSLEEP_SCAN}) {
530        print "forced scan... ";
531        if (has_nanosleep()) {
532            $has_nanosleep++;
533            $DEFINE .= ' -DTIME_HIRES_NANOSLEEP';
534        }
535    }
536    elsif (exists $Config{d_nanosleep}) {
537        print "believing \$Config{d_nanosleep}... ";
538        if ($Config{d_nanosleep}) {
539            $has_nanosleep++;
540            $DEFINE .= ' -DTIME_HIRES_NANOSLEEP';
541        }
542    } else {
543        if (has_nanosleep()) {
544            $has_nanosleep++;
545            $DEFINE .= ' -DTIME_HIRES_NANOSLEEP';
546        }
547    }
548
549    if ($has_nanosleep) {
550        print "found.\n";
551        print "You can mix subsecond sleeps with signals, if you want to.\n";
552        print "(It's still not portable, though.)\n";
553    } else {
554        print "NOT found.\n";
555        my $nt = ($^O eq 'os2' ? '' : 'not');
556        print "You can$nt mix subsecond sleeps with signals.\n";
557        print "(It would not be portable anyway.)\n";
558    }
559
560    print "Looking for clockid_t... ";
561    my $has_clockid_t;
562    if (has_clockid_t()) {
563        print "found.\n";
564        $has_clockid_t++;
565        $DEFINE .= ' -DTIME_HIRES_CLOCKID_T';
566    } else {
567        print "NOT found, will use int.\n";
568    }
569
570    print "Looking for clock_gettime()... ";
571    my $has_clock_gettime;
572    my $has_clock_gettime_emulation;
573    if (exists $Config{d_clock_gettime}) {
574        if ($Config{d_clock_gettime}) { # possibly set for cross-compilation
575            $has_clock_gettime++;
576            $DEFINE .= ' -DTIME_HIRES_CLOCK_GETTIME';
577        }
578    } elsif (has_clock_xxx('gettime')) {
579        $has_clock_gettime++;
580        $DEFINE .= ' -DTIME_HIRES_CLOCK_GETTIME';
581    } elsif (defined $SYSCALL_H && has_clock_xxx_syscall('gettime')) {
582        $has_clock_gettime++;
583        $DEFINE .= ' -DTIME_HIRES_CLOCK_GETTIME -DTIME_HIRES_CLOCK_GETTIME_SYSCALL';
584    } elsif ($^O eq 'darwin') {
585       $has_clock_gettime_emulation++;
586       $has_clock_gettime++;
587       $DEFINE .= ' -DTIME_HIRES_CLOCK_GETTIME -DTIME_HIRES_CLOCK_GETTIME_EMULATION';
588    }
589
590    if ($has_clock_gettime) {
591        if ($DEFINE =~ /-DTIME_HIRES_CLOCK_GETTIME_SYSCALL/) {
592            print "found (via syscall).\n";
593        } elsif ($has_clock_gettime_emulation) {
594            print "found (via emulation).\n";
595        } else {
596            print "found.\n";
597        }
598    } else {
599        print "NOT found.\n";
600    }
601
602    print "Looking for clock_getres()... ";
603    my $has_clock_getres;
604    my $has_clock_getres_emulation;
605    if (exists $Config{d_clock_getres}) {
606        if ($Config{d_clock_getres}) { # possibly set for cross-compilation
607            $has_clock_getres++;
608            $DEFINE .= ' -DTIME_HIRES_CLOCK_GETRES';
609        }
610    } elsif (has_clock_xxx('getres')) {
611        $has_clock_getres++;
612        $DEFINE .= ' -DTIME_HIRES_CLOCK_GETRES';
613    } elsif (defined $SYSCALL_H && has_clock_xxx_syscall('getres')) {
614        $has_clock_getres++;
615        $DEFINE .= ' -DTIME_HIRES_CLOCK_GETRES -DTIME_HIRES_CLOCK_GETRES_SYSCALL';
616    } elsif ($^O eq 'darwin') {
617       $has_clock_getres_emulation++;
618       $has_clock_getres++;
619       $DEFINE .= ' -DTIME_HIRES_CLOCK_GETRES -DTIME_HIRES_CLOCK_GETRES_EMULATION';
620    }
621
622    if ($has_clock_getres) {
623        if ($DEFINE =~ /-DTIME_HIRES_CLOCK_GETRES_SYSCALL/) {
624            print "found (via syscall).\n";
625        } elsif ($has_clock_getres_emulation) {
626            print "found (via emulation).\n";
627        } else {
628            print "found.\n";
629        }
630    } else {
631        print "NOT found.\n";
632    }
633
634    print "Looking for clock_nanosleep()... ";
635    my $has_clock_nanosleep;
636    my $has_clock_nanosleep_emulation;
637    if (exists $Config{d_clock_nanosleep}) {
638        if ($Config{d_clock_nanosleep}) { # possibly set for cross-compilation
639            $has_clock_nanosleep++;
640            $DEFINE .= ' -DTIME_HIRES_CLOCK_NANOSLEEP';
641        }
642    } elsif (has_clock_nanosleep()) {
643        $has_clock_nanosleep++;
644        $DEFINE .= ' -DTIME_HIRES_CLOCK_NANOSLEEP';
645    } elsif ($^O eq 'darwin') {
646        $has_clock_nanosleep++;
647        $has_clock_nanosleep_emulation++;
648        $DEFINE .= ' -DTIME_HIRES_CLOCK_NANOSLEEP -DTIME_HIRES_CLOCK_NANOSLEEP_EMULATION';
649    }
650
651    if ($has_clock_nanosleep) {
652        if ($has_clock_nanosleep_emulation) {
653            print "found (via emulation).\n";
654        } else {
655            print "found.\n";
656        }
657    } else {
658        print "NOT found.\n";
659    }
660
661    print "Looking for clock()... ";
662    my $has_clock;
663    if (exists $Config{d_clock}) {
664        if ($Config{d_clock}) { # possibly set for cross-compilation
665            $has_clock++;
666            $DEFINE .= ' -DTIME_HIRES_CLOCK';
667        }
668    } elsif (has_clock()) {
669        $has_clock++;
670        $DEFINE .= ' -DTIME_HIRES_CLOCK';
671    }
672
673    if ($has_clock) {
674        print "found.\n";
675    } else {
676        print "NOT found.\n";
677    }
678
679    print "Looking for working futimens()... ";
680    my $has_futimens;
681    if (has_futimens()) {
682        $has_futimens++;
683        $DEFINE .= ' -DHAS_FUTIMENS';
684    }
685
686    if ($has_futimens) {
687        print "found.\n";
688    } else {
689        print "NOT found.\n";
690    }
691
692    print "Looking for working utimensat()... ";
693    my $has_utimensat;
694    if (has_utimensat()) {
695        $has_utimensat++;
696        $DEFINE .= ' -DHAS_UTIMENSAT';
697    }
698
699    if ($has_utimensat) {
700        print "found.\n";
701    } else {
702        print "NOT found.\n";
703    }
704
705    my $has_hires_utime = ($has_futimens && $has_utimensat);
706    if ($has_hires_utime) {
707        $DEFINE .= ' -DTIME_HIRES_UTIME';
708        print "You seem to have subsecond timestamp setting.\n";
709    } else {
710        print "You do NOT seem to have subsecond timestamp setting.\n";
711    }
712
713    print "Looking for stat() subsecond timestamps...\n";
714
715    print "Trying struct stat st_atimespec.tv_nsec...";
716    my $has_stat_st_xtimespec;
717    if (try_compile_and_link(<<EOM)) {
718$TIME_HEADERS
719#include <sys/stat.h>
720int main(int argc, char** argv) {
721    struct stat st;
722    st.st_atimespec.tv_nsec = 0;
723}
724EOM
725      $has_stat_st_xtimespec++;
726      DEFINE('TIME_HIRES_STAT_ST_XTIMESPEC');  # 1
727    }
728
729    if ($has_stat_st_xtimespec) {
730        print "found.\n";
731    } else {
732        print "NOT found.\n";
733    }
734
735    print "Trying struct stat st_atimensec...";
736    my $has_stat_st_xtimensec;
737    if (try_compile_and_link(<<EOM)) {
738$TIME_HEADERS
739#include <sys/stat.h>
740int main(int argc, char** argv) {
741    struct stat st;
742    st.st_atimensec = 0;
743}
744EOM
745      $has_stat_st_xtimensec++;
746      DEFINE('TIME_HIRES_STAT_ST_XTIMENSEC');  # 2
747    }
748
749    if ($has_stat_st_xtimensec) {
750        print "found.\n";
751    } else {
752        print "NOT found.\n";
753    }
754
755    print "Trying struct stat st_atime_n...";
756    my $has_stat_st_xtime_n;
757    if (try_compile_and_link(<<EOM)) {
758$TIME_HEADERS
759#include <sys/stat.h>
760int main(int argc, char** argv) {
761    struct stat st;
762    st.st_atime_n = 0;
763}
764EOM
765      $has_stat_st_xtime_n++;
766      DEFINE('TIME_HIRES_STAT_ST_XTIME_N');  # 3
767    }
768
769    if ($has_stat_st_xtime_n) {
770        print "found.\n";
771    } else {
772        print "NOT found.\n";
773    }
774
775    print "Trying struct stat st_atim.tv_nsec...";
776    my $has_stat_st_xtim;
777    if (try_compile_and_link(<<EOM)) {
778$TIME_HEADERS
779#include <sys/stat.h>
780int main(int argc, char** argv) {
781    struct stat st;
782    st.st_atim.tv_nsec = 0;
783}
784EOM
785      $has_stat_st_xtim++;
786      DEFINE('TIME_HIRES_STAT_XTIM');  # 4
787    }
788
789    if ($has_stat_st_xtim) {
790        print "found.\n";
791    } else {
792        print "NOT found.\n";
793    }
794
795    print "Trying struct stat st_uatime...";
796    my $has_stat_st_uxtime;
797    if (try_compile_and_link(<<EOM)) {
798$TIME_HEADERS
799#include <sys/stat.h>
800int main(int argc, char** argv) {
801    struct stat st;
802    st.st_uatime = 0;
803}
804EOM
805      $has_stat_st_uxtime++;
806      DEFINE('TIME_HIRES_STAT_ST_UXTIME');  # 5
807    }
808
809    if ($has_stat_st_uxtime) {
810        print "found.\n";
811    } else {
812        print "NOT found.\n";
813    }
814
815    # See HiRes.xs hrstatns()
816    if ($has_stat_st_xtimespec) {
817        DEFINE('TIME_HIRES_STAT', 1);
818    } elsif ($has_stat_st_xtimensec) {
819        DEFINE('TIME_HIRES_STAT', 2);
820    } elsif ($has_stat_st_xtime_n) {
821        DEFINE('TIME_HIRES_STAT', 3);
822    } elsif ($has_stat_st_xtim) {
823        DEFINE('TIME_HIRES_STAT', 4);
824    } elsif ($has_stat_st_uxtime) {
825        DEFINE('TIME_HIRES_STAT', 5);
826    }
827
828    my $has_hires_stat = ($DEFINE =~ /-DTIME_HIRES_STAT=(\d+)/) ? $1 : 0;
829    if ($has_hires_stat) {
830        print "You seem to have subsecond timestamp reading.\n";
831        print "(Your struct stat has them, but the filesystems must help.)\n";
832        unless ($has_hires_utime) {
833            print "However, you do NOT seem to have subsecond timestamp setting.\n";
834        }
835    } else {
836        print "You do NOT seem to have subsecond timestamp reading.\n";
837    }
838
839    my $has_w32api_windows_h;
840
841    if ($^O eq 'cygwin') {
842        print "Looking for <w32api/windows.h>... ";
843        if (has_include('w32api/windows.h')) {
844            $has_w32api_windows_h++;
845            DEFINE('HAS_W32API_WINDOWS_H');
846        }
847        if ($has_w32api_windows_h) {
848            print "found.\n";
849        } else {
850            print "NOT found.\n";
851        }
852    }
853    if ($^O eq "darwin") {
854        # the system perl on darwin doesn't seem to include -DPERL_DARWIN
855        # which breaks setting up emulation
856        DEFINE("PERL_DARWIN");
857    }
858
859    if ($DEFINE) {
860        $DEFINE =~ s/^\s+//;
861        if (open(XDEFINE, '>', 'xdefine')) {
862            print XDEFINE $DEFINE, "\n";
863            close(XDEFINE);
864        }
865    }
866}
867
868sub doMakefile {
869    my @makefileopts = ();
870
871    push (@makefileopts,
872        'NAME'  => 'Time::HiRes',
873        'AUTHOR'    => 'Jarkko Hietaniemi <jhi@iki.fi>',
874        'ABSTRACT_FROM' => 'HiRes.pm',
875        'VERSION_FROM' => 'HiRes.pm', # finds $VERSION
876        'LIBS'  => $LIBS,   # e.g., '-lm'
877        'DEFINE'        => $DEFINE,     # e.g., '-DHAS_SOMETHING'
878        'XSOPT' => $XSOPT,
879          # Do not even think about 'INC' => '-I/usr/ucbinclude',
880          # Solaris will avenge.
881        'INC'   => '',     # e.g., '-I/usr/include/other'
882        'INSTALLDIRS' => ($] >= 5.008 && $] < 5.011 ? 'perl' : 'site'),
883        'PREREQ_PM' => {
884            'Carp' => 0,
885            'Config' => 0,
886            'Exporter' => 0,
887            'ExtUtils::MakeMaker' => 0,
888            'Test::More' => 0.84,
889            'XSLoader' => 0,
890            'strict' => 0,
891            'File::Spec' => 0,
892        },
893        'dist'      => {
894            'CI'       => 'ci -l',
895            'COMPRESS' => 'gzip -9f',
896            'SUFFIX'   => 'gz',
897        },
898        clean => { FILES => "xdefine" },
899        realclean => { FILES=> 'const-c.inc const-xs.inc' },
900    );
901
902    if ($^O eq "MSWin32" && !(grep { /\ALD[A-Z]*=/ } @ARGV)) {
903        my $libperl = $Config{libperl} || "";
904        my $gccversion = $Config{gccversion} || "";
905        if ($gccversion =~ /\A3\.4\.[0-9]+/ and $libperl =~ /\.lib\z/) {
906            # Avoid broken linkage with ActivePerl, by linking directly
907            # against the Perl DLL rather than the import library.
908            (my $llibperl = "-l$libperl") =~ s/\.lib\z//;
909            my $lddlflags = $Config{lddlflags} || "";
910            my $ldflags = $Config{ldflags} || "";
911            s/-L(?:".*?"|\S+)//g foreach $lddlflags, $ldflags;
912            my $libdirs = join ' ',
913                map { s/(?<!\\)((?:\\\\)*")/\\$1/g; qq[-L"$_"] }
914                @Config{qw/bin sitebin/};
915            push @makefileopts, macro => {
916                LDDLFLAGS => "$lddlflags $libdirs $llibperl",
917                LDFLAGS => "$ldflags $libdirs $llibperl",
918                PERL_ARCHIVE => "",
919            };
920        }
921    }
922
923    if ($ENV{PERL_CORE}) {
924        push @makefileopts, MAN3PODS => {};
925    }
926
927    if ($ExtUtils::MakeMaker::VERSION >= 6.48) {
928        push @makefileopts, (MIN_PERL_VERSION => '5.006',);
929    }
930
931    if ($ExtUtils::MakeMaker::VERSION >= 6.31) {
932        push @makefileopts, (LICENSE => 'perl_5');
933    }
934
935    if ($ExtUtils::MakeMaker::VERSION >= 6.46) {
936        push @makefileopts, (
937            META_MERGE => {
938                resources => {
939                    repository => 'https://github.com/Perl/perl5.git',
940                    bugtracker => 'https://github.com/Perl/perl5/issues',
941                    homepage   => "https://github.com/Perl/perl5",
942                },
943            },
944        )
945    }
946
947    WriteMakefile(@makefileopts);
948}
949
950sub doConstants {
951    if (eval {require ExtUtils::Constant; 1}) {
952        # More or less this same list is in HiRes.pm.  Should unify.
953        my @names = qw(
954                       CLOCKS_PER_SEC
955                       CLOCK_BOOTTIME
956                       CLOCK_HIGHRES
957                       CLOCK_MONOTONIC
958                       CLOCK_MONOTONIC_COARSE
959                       CLOCK_MONOTONIC_FAST
960                       CLOCK_MONOTONIC_PRECISE
961                       CLOCK_MONOTONIC_RAW
962                       CLOCK_PROF
963                       CLOCK_PROCESS_CPUTIME_ID
964                       CLOCK_REALTIME
965                       CLOCK_REALTIME_COARSE
966                       CLOCK_REALTIME_FAST
967                       CLOCK_REALTIME_PRECISE
968                       CLOCK_REALTIME_RAW
969                       CLOCK_SECOND
970                       CLOCK_SOFTTIME
971                       CLOCK_THREAD_CPUTIME_ID
972                       CLOCK_TIMEOFDAY
973                       CLOCK_UPTIME
974                       CLOCK_UPTIME_COARSE
975                       CLOCK_UPTIME_FAST
976                       CLOCK_UPTIME_PRECISE
977                       CLOCK_UPTIME_RAW
978                       CLOCK_VIRTUAL
979                       ITIMER_PROF
980                       ITIMER_REAL
981                       ITIMER_REALPROF
982                       ITIMER_VIRTUAL
983                       TIMER_ABSTIME
984                      );
985        foreach (qw (d_usleep d_ualarm d_gettimeofday d_getitimer d_setitimer
986                     d_nanosleep d_clock_gettime d_clock_getres
987                     d_clock d_clock_nanosleep d_hires_stat
988                     d_futimens d_utimensat d_hires_utime)) {
989            my $macro = $_;
990            if ($macro =~ /^(d_nanosleep|d_clock)$/) {
991                $macro =~ s/^d_(.+)/TIME_HIRES_\U$1/;
992            } elsif ($macro =~ /^(d_hires_stat)$/) {
993                my $d_hires_stat = $1 if ($DEFINE =~ /-DTIME_HIRES_STAT=(\d+)/);
994                if (defined $d_hires_stat) {
995                    push @names, {name => $_, macro => "TIME_HIRES_STAT", value => $d_hires_stat,
996                                  default => ["IV", "0"]};
997                    next;
998                }
999            } elsif ($macro =~ /^(d_hires_utime)$/) {
1000                my $d_hires_utime =
1001                    ($DEFINE =~ /-DHAS_FUTIMENS/ ||
1002                     $DEFINE =~ /-DHAS_UTIMENSAT/);
1003                push @names, {name => $_, macro => "TIME_HIRES_UTIME", value => $d_hires_utime,
1004                              default => ["IV", "0"]};
1005                next;
1006            } elsif ($macro =~ /^(d_clock_gettime|d_clock_getres|d_clock_nanosleep)$/) {
1007                $macro =~ s/^d_(.+)/TIME_HIRES_\U$1/;
1008                my $val = ($DEFINE =~ /-D$macro\b/) ? 1 : 0;
1009                push @names, {name => $_, macro => $macro, value => $val,
1010                              default => ["IV", "0"]};
1011                next;
1012            } else {
1013                $macro =~ s/^d_(.+)/HAS_\U$1/;
1014            }
1015            push @names, {name => $_, macro => $macro, value => 1,
1016                          default => ["IV", "0"]};
1017        }
1018        ExtUtils::Constant::WriteConstants(
1019                                           NAME => 'Time::HiRes',
1020                                           NAMES => \@names,
1021                                          );
1022    } else {
1023        my $file;
1024        foreach $file ('const-c.inc', 'const-xs.inc') {
1025            my $fallback = File::Spec->catfile('fallback', $file);
1026            local $/;
1027            open IN, '<', $fallback or die "Can't open $fallback: $!";
1028            open OUT, '>', $file or die "Can't open $file: $!";
1029            print OUT <IN> or die $!;
1030            close OUT or die "Can't close $file: $!";
1031            close IN or die "Can't close $fallback: $!";
1032        }
1033    }
1034}
1035
1036sub main {
1037    if (-f "xdefine" && !(@ARGV  && $ARGV[0] =~ /^--(?:configure|force)$/)) {
1038        print qq[$0: The "xdefine" exists, skipping the configure step.\n];
1039        print qq[Use "$^X $0 --configure"\n];
1040        print qq[or: "$^X $0 --force\n];
1041        print qq[to force the configure step.\n];
1042    } else {
1043        print "Configuring Time::HiRes...\n";
1044        1 while unlink("define");
1045        if ($^O =~ /Win32/i) {
1046            DEFINE('SELECT_IS_BROKEN');
1047            # we provide our own implementations of those functions on win32
1048            DEFINE('TIME_HIRES_CLOCK_GETTIME');
1049            DEFINE('TIME_HIRES_CLOCK_GETRES');
1050            $LIBS = [];
1051            print "System is $^O, skipping full configure...\n";
1052            open(XDEFINE, '>', 'xdefine') or die "$0: Cannot create xdefine: $!\n";
1053            close(XDEFINE);
1054        } else {
1055            init();
1056        }
1057        doMakefile;
1058        doConstants;
1059    }
1060    my $make = $Config{'make'} || "make";
1061    unless (exists $ENV{PERL_CORE} && $ENV{PERL_CORE}) {
1062        print  <<EOM;
1063Now you may issue '$make'.  Do not forget also '$make test'.
1064EOM
1065       if ($] == 5.008 &&
1066           ((exists $ENV{LC_ALL}   && $ENV{LC_ALL}   =~ /utf-?8/i) ||
1067            (exists $ENV{LC_CTYPE} && $ENV{LC_CTYPE} =~ /utf-?8/i) ||
1068            (exists $ENV{LANG}     && $ENV{LANG}     =~ /utf-?8/i))) {
1069            print <<EOM;
1070
1071NOTE: if you get an error like this (the Makefile line number may vary):
1072Makefile:91: *** missing separator
1073then set the environment variable LC_ALL to "C" and retry
1074from scratch (re-run perl "Makefile.PL").
1075(And consider upgrading your Perl to, say, at least Perl 5.8.8.)
1076(You got this message because you seem to have
1077 an UTF-8 locale active in your shell environment, this used
1078 to cause broken Makefiles to be created from Makefile.PLs)
1079EOM
1080        }
1081    }
1082}
1083
1084&main;
1085
1086# EOF
1087