The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package Module::Build::My;

use 5.006;

use strict;
use warnings;

use base 'Module::Build';

use Config;

sub new {
    my ($class, @args) = @_;
    my $self = $class->SUPER::new(@args);
    $self->config(cc   => $ENV{CC}) if defined $ENV{CC};
    $self->config(ld   => $ENV{LD}) if defined $ENV{LD};
    $self->config(lddl => $ENV{LD}) if defined $ENV{LD};
    $self->extra_compiler_flags(grep { $_ ne '' } split /\s/, $ENV{CFLAGS})  if defined $ENV{CFLAGS};
    $self->extra_linker_flags(  grep { $_ ne '' } split /\s/, $ENV{LDFLAGS}) if defined $ENV{LDFLAGS};
    return $self;
};

sub ACTION_xs_config {
    my $self = shift;
    return if $self->args('pp');

    my $config_h = 'xs/xs_config.h';
    $self->add_to_cleanup($config_h);

    return if $self->up_to_date('Build', $config_h);

    require ExtUtils::CChecker;
    my $chk = ExtUtils::CChecker->new(
        defines_to => $config_h,
    );

    $chk->define('HAVE_MKTIME 1')    if $Config{d_mktime};
    $chk->define('HAVE_TM_GMTOFF 1') if $Config{d_tm_tm_gmtoff};
    $chk->define('HAVE_TM_ZONE 1')   if $Config{d_tm_tm_zone};
    $chk->define('HAVE_TZNAME 1')    if $Config{d_tzname};

    foreach my $kw (qw( __restrict __restrict__ _Restrict restrict )) {
        last if $chk->try_compile_run(
            define => "restrict $kw",
            source => << "EOF" );
typedef int * int_ptr;
int foo (int_ptr $kw ip) {
    return ip[0];
}
int
main ()
{
    int s[1];
    int * $kw t = s;
    t[0] = 0;
    return foo(t);
    return 0;
}
EOF
    }

    $chk->try_compile_run(
        define => 'HAVE_DECL_TZNAME 1',
        source => << "EOF" );
#include <time.h>
int main () {
#ifndef tzname
    (void) tzname;
#endif
    return 0;
}
EOF

    foreach my $m (qw( E O 1 )) {
        $chk->try_compile_run(
            define => "HAVE_STRFTIME_${m}_MODIFIER 1",
            source => << "EOF" );
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int
main()
{
    char outstr[200];
    time_t t;
    struct tm *tmp;

    t = time(NULL);
    tmp = localtime(&t);
    if (tmp == NULL)
        exit(1);
    if (strftime(outstr, sizeof(outstr), "%${m}y", tmp) == 0)
        exit(1);
    if (strncmp(outstr, "%${m}y", 4) == 0 || strncmp(outstr, "y", 4) == 0)
        exit(1);
    return 0;
}
EOF
    };

    $chk->try_compile_run(
        define => 'HAVE_STDBOOL_H 1',
        source => << "EOF" );
#include <stdbool.h>
int main () {
    return false;
}
EOF

    $chk->try_compile_run(
        define => 'HAVE__BOOL 1',
        source => << "EOF" );
int main () {
    _Bool b = 0;
    return b;
}
EOF

    return 1;
};

sub ACTION_gnulib {
    my $self = shift;
    return if $self->args('pp');

    $self->depends_on('xs_config');

    if (my $o = $self->cbuilder->object_file(my $c = 'xs/time_r.c')) {
        $self->add_to_cleanup($o);
        $self->cbuilder->compile(source => $c, object_file => $o, include_dirs => ['xs'], extra_compiler_flags => $self->extra_compiler_flags)
            unless $self->up_to_date($c, $o);
        push @{$self->{properties}{objects}}, $o;
    }

    if (my $o = $self->cbuilder->object_file(my $c = 'xs/gnu_strftime.c')) {
        $self->add_to_cleanup($o);
        $self->cbuilder->compile(source => $c, object_file => $o, include_dirs => ['xs'], extra_compiler_flags => $self->extra_compiler_flags)
            unless $self->up_to_date($c, $o);
        push @{$self->{properties}{objects}}, $o;
    }

    return 1;
};

sub ACTION_code {
    my $self = shift;
    $self->depends_on('gnulib');
    return $self->SUPER::ACTION_code(@_);
};

sub ACTION_test_core {
    my $self = shift;
    $self->log_info("Testing CORE (ignoring results)\n");
    $ENV{PERL_POSIX_STRFTIME_GNU_XS} = 0;
    $ENV{PERL_POSIX_STRFTIME_GNU_PP} = 0;
    return eval { $self->SUPER::ACTION_test(@_) };
};

sub ACTION_test_pp {
    my $self = shift;
    $self->log_info("Testing PP\n");
    $ENV{PERL_POSIX_STRFTIME_GNU_XS} = 0;
    $ENV{PERL_POSIX_STRFTIME_GNU_PP} = 1;
    return $self->SUPER::ACTION_test(@_);
};

sub ACTION_test_xs {
    my $self = shift;
    $self->log_info("Testing XS\n");
    $ENV{PERL_POSIX_STRFTIME_GNU_XS} = 1;
    $ENV{PERL_POSIX_STRFTIME_GNU_PP} = 0;
    return $self->SUPER::ACTION_test(@_);
};

sub ACTION_test {
    my $self = shift;
    $self->depends_on('test_core') if $ENV{TEST_CORE};
    $self->depends_on('test_xs') unless $self->args('pp');
    $self->depends_on('test_pp');
};

1;