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