use strict;
use warnings;
use ExtUtils::MakeMaker::CPANfile;
my $pkgconfig_name = 'libunbound';
my ($cflags, $ldflags, $libdir);
use Config;
use File::Temp;
use File::Spec;
use JSON::PP;
my $ccpath = $ENV{'CC'} || $Config::Config{'cc'};
print "Your C compiler appears to be: $ccpath\n";
if ( eval { require ExtUtils::PkgConfig } ) {
print "Oh good! You have ExtUtils::PkgConfig. :)\n";
# These can fail because older libunbound versions (e.g., 1.4.22)
# didn’t include a pkg-config file.
$cflags = ExtUtils::PkgConfig->cflags($pkgconfig_name);
$ldflags = ExtUtils::PkgConfig->libs($pkgconfig_name);
$libdir = ExtUtils::PkgConfig->libs_only_L($pkgconfig_name);
}
else {
print "Hmm. You don’t seem to have ExtUtils::PkgConfig.\n";
print "I’ll try running `pkg-config` directly …\n";
my $cmd = "pkg-config --cflags $pkgconfig_name";
$cflags = `$cmd`;
if ($?) {
warn "`$cmd` failed (CHILD_ERROR=$?)\n";
}
else {
print "Cool. It looks like pkg-config works.\n";
$ldflags = `pkg-config --libs $pkgconfig_name`;
$libdir = `pkg-config --libs-only-L $pkgconfig_name`;
}
$_ && chomp for $cflags, $ldflags, $libdir;
}
$libdir =~ s<\A-L><>;
# In case pkg-config didn’t give us anything.
if (!$ldflags) {
warn "I didn’t find libunbound via pkg-config. :(\n";
warn "Now I’ll look for libunbound via ExtUtils::Liblist …\n";
my ($xtralibs, $bsloadlibs, $ldloadlibs, $ld_run_path, $where_ar) = ExtUtils::Liblist->ext('-lunbound', 0, 1);
if (@$where_ar) {
print "Libunbound found at: @$where_ar\n";
my @pieces = File::Spec->splitdir($where_ar->[0]);
pop @pieces;
$libdir = File::Spec->catdir(@pieces);
$ldflags = "-L$libdir -lunbound";
if (!$cflags) {
print "Looking for unbound.h …$/";
require Config;
my @incdirs = (
$Config::Config{'usrinc'},
map { split m<\s+> } (
$Config::Config{'incpth'},
$Config::Config{'locincpth'},
),
);
while (@pieces > 1) {
pop @pieces;
push @incdirs, File::Spec->catdir(@pieces, "include"),
}
my %checked;
for my $dir (@incdirs) {
next if !$dir;
next if $checked{$dir};
$checked{$dir}++;
print "Checking $dir …$/";
if (-s File::Spec->catdir($dir, 'unbound.h')) {
print "Found it!$/";
$cflags = "-I$dir";
last;
}
else {
print "… nope. :($/";
}
}
if (!$cflags) {
print "I didn’t find unbound.h, but maybe your compiler can?$/";
}
}
}
else {
# Useful for Travis CI. Not sure if it’s relevant in production …
warn "That didn’t work, either. This doesn’t look good. :-/\n";
warn "As a last resort, let’s just try compiling with libunbound …\n";
my ($tfh, $tpath) = File::Temp::tempfile( CLEANUP => 1 );
print {$tfh} "#include <unbound.h>\nint main() { return 0; }\n";
close $tfh;
my $cmd = "$ccpath $cflags -xc -lunbound $tpath";
print "Trying: `$cmd`\n";
my $out = `$cmd`;
if ($?) {
die "$ccpath failed to use libunbound (CHILD_ERROR=$?): $out";
}
else {
print "Huh, weird … the compiler can use and link libunbound.\n";
print "Maybe there’s a bug in ExtUtils::Liblist?\n";
print "Anyway, let’s get on with our business …\n";
}
}
$ldflags ||= '-lunbound';
}
print "CFLAGS: [$cflags]\n";
print "LDFLAGS: [$ldflags]\n";
# There has to be something better …
my (
$HAS_UB_VERSION,
$HAS_UB_CANCEL,
$HAS_UB_CTX_ADD_TA_AUTR,
$HAS_WHY_BOGUS,
$HAS_TTL,
$HAS_UB_CONSTANTS,
);
my @checks = (
{
label => 'sanity',
c => join(
$/,
'#include <unbound.h>',
'int main() {',
' struct ub_result myresult;',
' (void)(myresult);',
' return 0;',
'}',
),
perl => sub {
if (!shift) {
die "libunbound didn’t compile! (CHILD_ERROR=$?)";
}
},
},
{
label => 'ub_version()',
c => join(
$/,
'#include <stdio.h>',
'#include <unbound.h>',
'int main() {',
' fprintf(stdout, "%s", ub_version());',
' return 0;',
'}',
),
perl => sub {
$HAS_UB_VERSION = shift;
},
},
{
label => 'ub_result.ttl',
c => join(
$/,
'#include <unbound.h>',
'int main() {',
' struct ub_result myresult;',
' myresult.ttl = 0;',
' return myresult.ttl;',
'}',
),
perl => sub {
$HAS_TTL = shift;
},
},
{
label => 'UB_* constants',
c => join(
$/,
'#include <unbound.h>',
'int main() {',
' int foo = UB_NOERROR;',
' (void)(foo);',
' return 0;',
'}',
),
perl => sub {
$HAS_UB_CONSTANTS = shift;
},
},
{
label => 'ub_result.why_bogus',
c => join(
$/,
'#include <unbound.h>',
'#include <stdio.h>',
'int main() {',
' struct ub_result myresult;',
' myresult.why_bogus = "123";',
' fprintf(stdout, "%s", myresult.why_bogus);',
' return 0;',
'}',
),
perl => sub {
$HAS_WHY_BOGUS = shift;
},
},
{
label => 'ub_cancel()',
c => join(
$/,
'#include <unbound.h>',
'int main() {',
' struct ub_ctx* myctx = ub_ctx_create();',
' ub_cancel(myctx, 0);',
' return 0;',
'}',
),
perl => sub {
$HAS_UB_CANCEL = shift;
},
},
{
label => 'ub_ctx_add_ta_autr()',
c => join(
$/,
'#include <unbound.h>',
'int main() {',
' struct ub_ctx* myctx = ub_ctx_create();',
' ub_ctx_add_ta_autr(myctx, "/faux");',
' return 0;',
'}',
),
perl => sub {
$HAS_UB_CTX_ADD_TA_AUTR = shift;
},
},
);
for my $check (@checks) {
print "Checking: $check->{label} … $/";
my $tdir = File::Temp::tempdir( CLEANUP => 1 );
my $cpath = File::Spec->catdir( $tdir, 'check.c' );
my $progpath = File::Spec->catdir( $tdir, 'check' );
open my $wfh, '>', $cpath;
print {$wfh} $check->{c};
close $wfh;
# Some compilers care about order here:
# compile flags, compile source, linker flags, then linker source.
my $cmd = "$ccpath $Config{'ccflags'} $cflags $cpath -o $progpath $Config{ccdlflags} $ldflags";
print "Compiling test program: `$cmd`\n";
system($cmd);
my $success = -s $progpath ? 1 : 0;
printf " $check->{label}: %s$/", ($success ? 'yes' : 'no');
$check->{'perl'}->($success);
}
_generate_includes();
my @extra_makefile_args;
if ($libdir) {
push @extra_makefile_args, LDDLFLAGS => "-Wl,-rpath,$libdir $Config{lddlflags}",
}
WriteMakefile(
NAME => 'DNS::Unbound',
VERSION_FROM => 'lib/DNS/Unbound.pm',
ABSTRACT_FROM => 'lib/DNS/Unbound.pm',
AUTHOR => 'Felipe Gasper (FELIPE)',
CCFLAGS => join(
q< >,
$Config{'ccflags'},
$cflags,
'-Wall',
'-std=c99',
"-DHAS_UB_VERSION=$HAS_UB_VERSION",
"-DHAS_UB_CANCEL=$HAS_UB_CANCEL",
"-DHAS_UB_CTX_ADD_TA_AUTR=$HAS_UB_CTX_ADD_TA_AUTR",
"-DHAS_WHY_BOGUS=$HAS_WHY_BOGUS",
"-DHAS_TTL=$HAS_TTL",
"-DHAS_UB_CONSTANTS=$HAS_UB_CONSTANTS",
),
@extra_makefile_args,
LIBS => [ $ldflags ],
LICENSE => 'perl',
META_MERGE => {
'meta-spec' => { version => 2 },
resources => {
bugtracker => {
web => 'https://github.com/FGasper/p5-DNS-Unbound/issues',
},
repository => {
type => 'git',
url => 'https://github.com/FGasper/p5-DNS-Unbound.git',
web => 'https://github.com/FGasper/p5-DNS-Unbound',
},
},
},
);
#----------------------------------------------------------------------
sub _generate_includes {
open my $fh, '<', 'errcodes.jsonc' or die "open: $!";
my $jsonc = do { local $/; <$fh> };
my $err_value_ar = JSON::PP->new()->relaxed()->decode($jsonc);
{
open my $define_fh, '>', 'errcodes_define.inc';
print {$define_fh} "#if !HAS_UB_CONSTANTS\n";
print {$define_fh} "# define @$_\n" for @$err_value_ar;
print {$define_fh} "#endif\n";
}
{
my @names = map { $_->[0] } @$err_value_ar;
my $pkg_gv = qq<gv_stashpv("\$Package", FALSE)>;
open my $boot_fh, '>', 'errcodes_boot.inc';
print {$boot_fh} "BOOT:\n";
print {$boot_fh} qq< newCONSTSUB( $pkg_gv, "_ERROR_NAMES_STR", newSVpvs("@names") );\n>;
print {$boot_fh} qq/ newCONSTSUB( $pkg_gv, "$_", newSViv($_) );\n/ for @names;
}
}