# Makefile.PL for XML::Hash::XS.
#
# This program is free software; you can redistribute it and/or modify it
# under the same terms as Perl itself.
# Copyright 2012-2015 Yuriy Ustushenko, all rights reserved.
#
# Derived from the module XML::LibXML
# Copyright 2001-2003 AxKit.com Ltd., 2002-2006 Christian Glahn, 2006-2009 Petr Pajas
use 5.008008;
use warnings;
use strict;
use lib qw(inc);
use Devel::CheckLib;
use ExtUtils::MakeMaker;
use Config;
use File::Spec;
$| = 0;
our %PARAMS = parse_params();
my %WriteMakefileArgs = (
NAME => 'XML::Hash::XS',
VERSION_FROM => 'lib/XML/Hash/XS.pm',
ABSTRACT_FROM => 'lib/XML/Hash/XS.pm',
AUTHOR => 'Yuriy Ustushenko <yoreek@yahoo.com>',
test => {
TESTS => 't/*.t'. ($ENV{AUTHOR_TESTING} ? ' xt/*.t' : '')
},
META_MERGE => {
'meta-spec' => { version => 2 },
resources => {
license => 'http://dev.perl.org/licenses/',
homepage => 'https://github.com/yoreek/XML-Hash-XS',
repository => {
type => 'git',
url => 'https://github.com/yoreek/XML-Hash-XS.git',
web => 'https://github.com/yoreek/XML-Hash-XS',
},
bugtracker => {
web => 'https://github.com/yoreek/XML-Hash-XS/issues',
},
},
},
META_ADD => {
prereqs => {
configure => {
requires => {
'ExtUtils::MakeMaker' => 0,
'Config' => 0,
'File::Spec' => 0,
},
},
build => {
requires => {
'ExtUtils::MakeMaker' => 0,
'Config' => 0,
'File::Spec' => 0,
},
},
runtime => {
requires => {
'Exporter' => 5.57,
'base' => 0,
'XSLoader' => 0,
},
},
test => {
requires => {
'Test::More' => 0,
'Data::Dumper' => 0,
},
},
},
},
MIN_PERL_VERSION => 5.008008,
LICENSE => 'perl_5',
CCFLAGS => $Config{ccflags} . ' -o $@',
OBJECT => join(' ', '$(BASEEXT)$(OBJ_EXT)', map { s/\.c$/\$(OBJ_EXT)/; $_ } glob('src/*.c')),
C => [ 'XS.c', glob('src/*.c') ],
H => [ glob('src/*.h') ],
clean => { FILES => 'src/*.o' },
extra_config(),
);
my $eumm_version = eval $ExtUtils::MakeMaker::VERSION;
for (qw(configure build test runtime)) {
my $key = $_ eq 'runtime' ? 'PREREQ_PM' : uc $_.'_REQUIRES';
next unless exists $WriteMakefileArgs{META_ADD}{prereqs}{$_}
or exists $WriteMakefileArgs{$key};
my $r = $WriteMakefileArgs{$key} = {
%{$WriteMakefileArgs{META_ADD}{prereqs}{$_}{requires} || {}},
%{delete $WriteMakefileArgs{$key} || {}},
};
defined $r->{$_} or delete $r->{$_} for keys %$r;
}
$WriteMakefileArgs{BUILD_REQUIRES} = {
%{$WriteMakefileArgs{BUILD_REQUIRES} || {}},
%{delete $WriteMakefileArgs{TEST_REQUIRES}}
} if $eumm_version < 6.63_03;
$WriteMakefileArgs{PREREQ_PM} = {
%{$WriteMakefileArgs{PREREQ_PM}},
%{delete $WriteMakefileArgs{BUILD_REQUIRES}}
} if $eumm_version < 6.55_01;
delete $WriteMakefileArgs{CONFIGURE_REQUIRES}
if $eumm_version < 6.51_03;
delete @WriteMakefileArgs{qw(META_ADD META_MERGE)}
if $eumm_version < 6.46;
delete $WriteMakefileArgs{MIN_PERL_VERSION}
if $eumm_version < 6.48;
delete $WriteMakefileArgs{LICENSE}
if $eumm_version < 6.31;
WriteMakefile(%WriteMakefileArgs);
sub extra_config {
my $available_libs = get_available_libs();
return unless scalar %$available_libs;
my (%config, %summary_config);
my @options = qw(lib libpath incpath);
# remove unneded libxml2
delete $available_libs->{xml2} unless exists $available_libs->{'XML::LibXML'};
foreach my $lib_config (values %$available_libs) {
foreach my $option (@options) {
my $value = $lib_config->{$option} or next;
$value = [ split(/\s+/, $value) ] unless ref $value;
$config{$option}{$_} = 1 for @$value;
}
}
if ( $PARAMS{LIBS} ) {
$summary_config{LIBS} = [ $PARAMS{LIBS} ];
}
else {
my @libs = (
# order is important!
( map { "-L$_" } keys %{ $config{libpath} || {} } ),
( map {
$Config{cc} eq 'cl' && $_ !~ /\.lib$/ ? "-l$_.lib" : "-l$_"
} keys %{ $config{lib} || {} }
),
);
$summary_config{LIBS} = \@libs if scalar @libs;
}
if ( $PARAMS{INC} ) {
$summary_config{INC} = [ $PARAMS{INC} ];
}
else {
my @inc = map { "-I$_" } keys %{ $config{incpath} || {} };
$summary_config{INC} = \@inc if scalar @inc;
}
my @define = map { s/:/_/g; "-DXH_HAVE_" . uc($_) } keys %$available_libs;
$summary_config{DEFINE} = \@define if scalar @define;
# convert array to string
$summary_config{$_} = join(' ', @{ $summary_config{$_} }) for keys %summary_config;
# CCFLAGS
$summary_config{CCFLAGS} = ( $Config{ccflags} || '' ) . ' -o $@';
$summary_config{CCFLAGS} .= ' -g -Wall -Werror -Wextra -pedantic -std=c99 -DPERL_GCC_PEDANTIC -DWITH_DEBUG -O0'
if $PARAMS{DEBUG};
$summary_config{CCFLAGS} .= ' -DWITH_TRACE'
if $PARAMS{DEBUG} && $PARAMS{TRACE};
return %summary_config;
}
sub get_available_libs {
my @COMMON_LIB_PATH = (
'/usr/lib',
'/usr/local/lib',
'/usr/pkg/lib',
'/opt/local/lib',
);
my @COMMON_INC_PATH = (
'/usr/include',
'/usr/local/include',
'/usr/pkg/include',
'/opt/local/include',
);
my @REQUIRED_LIBS = (
{
perl => 1,
name => 'XML::LibXML',
version => 1.62,
mandatory => 0,
},
{
name => 'xml2',
mandatory => 0,
configs => [
{
lib => sub {
my $results = $PARAMS{WIN32} ? undef : backtick(
join('/bin/', grep { $_ } ($ENV{XMLPREFIX} || $PARAMS{XMLPREFIX}, 'xml2-config')),
'--libs',
);
$results ? [ map { substr($_, 2) } grep { $_ =~ /^-l/ } split(/\s+/, $results) ] : undef;
},
libpath => sub {
my $results = $PARAMS{WIN32} ? undef : backtick(
join('/bin/', grep { $_ } ($ENV{XMLPREFIX} || $PARAMS{XMLPREFIX}, 'xml2-config')),
'--libs',
);
$results ? [ map { substr($_, 2) } grep { $_ =~ /^-L/ } split(/\s+/, $results) ] : undef;
},
incpath => sub {
my $results = $PARAMS{WIN32} ? undef : backtick(
join('/bin/', grep { $_ } ($ENV{XMLPREFIX} || $PARAMS{XMLPREFIX}, 'xml2-config')),
'--cflags',
);
$results ? [ map { substr($_, 2) } grep { $_ =~ /^-I/ } split(/\s+/, $results) ] : undef;
},
header => 'libxml/parser.h',
},
{
lib => 'xml2 m z',
libpath => \@COMMON_LIB_PATH,
incpath => [
@COMMON_INC_PATH,
'/usr/include/libxml2',
'/usr/local/include/libxml2',
'/usr/pkg/include/libxml2',
'/opt/local/include/libxml2',
],
header => 'libxml/parser.h',
},
],
},
{
name => 'iconv',
configs => [
{
lib => 'c',
header => 'iconv.h',
function => 'iconv_t iconv = iconv_open("UTF-8", "UTF-8");(void) iconv_close(iconv);return 0;',
},
{
lib => 'iconv',
header => 'iconv.h',
function => 'iconv_t iconv = iconv_open("UTF-8", "UTF-8");(void) iconv_close(iconv);return 0;',
},
],
},
{
name => 'icu',
configs => [
{
lib => sub {
my $results = $PARAMS{WIN32} ? undef : backtick('icu-config', '--ldflags-libsonly');
$results ? [ map { substr($_, 2) } grep { $_ =~ /^-l/ } split(/\s+/, $results) ] : undef;
},
libpath => sub {
my $results = $PARAMS{WIN32} ? undef : backtick('icu-config', '--ldflags-searchpath');
$results ? [ map { substr($_, 2) } grep { $_ =~ /^-L/ } split(/\s+/, $results) ] : undef;
},
incpath => sub {
my $results = $PARAMS{WIN32} ? undef : backtick('icu-config', '--cppflags-searchpath');
$results ? [ map { substr($_, 2) } grep { $_ =~ /^-I/ } split(/\s+/, $results) ] : undef;
},
header => [
'unicode/utypes.h',
'unicode/ucnv.h',
],
function => 'UErrorCode status = U_ZERO_ERROR;UConverter *uconv = ucnv_open("UTF-8", &status);ucnv_close(uconv);return 0;',
},
{
lib => 'icui18n icuuc icudata',
libpath => \@COMMON_LIB_PATH,
incpath => \@COMMON_INC_PATH,
header => [
'unicode/utypes.h',
'unicode/ucnv.h',
],
function => 'UErrorCode status = U_ZERO_ERROR;UConverter *uconv = ucnv_open("UTF-8", &status);ucnv_close(uconv);return 0;',
},
],
},
);
my %libs;
my @options = qw(lib libpath incpath header function);
foreach my $info (@REQUIRED_LIBS) {
my $lib = $info->{name};
if ( $info->{perl} ) {
my $ver = $info->{version} || '';
print "Checking for '$lib'... ";
eval "use $lib $ver";
if (my $err = $@) {
print "no\n";
print $err if $PARAMS{DEBUG}
}
else {
print "yes\n";
$libs{$lib} = {};
}
}
else {
foreach my $lib_config (@{ $info->{configs} }) {
my %config;
@config{@options} = map {
my $results = $lib_config->{$_};
$results = ($results and ref($results) eq 'CODE') ? &$results() : $results;
($results and $_ ne 'function' and !ref($results))
? [ split(/\s+/, $results) ]
: $results
;
} @options;
next unless $config{lib} || $config{perl_lib};
print "Checking for '$lib'... ";
delete $config{$_} for grep { !$config{$_} } keys %config;
if ( $PARAMS{LIBS} ) {
delete $config{lib};
delete $config{libpath};
$config{LIBS} = $PARAMS{LIBS};
}
if ( $PARAMS{INC} ) {
delete $config{incpath};
$config{INC} = $PARAMS{INC};
}
if ( check_lib(debug => $PARAMS{DEBUG}, %config) ) {
print "yes\n";
$libs{$lib} = \%config;
last;
}
print "no\n";
}
}
if ($info->{mandatory} && !$libs{$lib}) {
print STDERR <<"DEATH";
'$lib' library not found
Try setting LIBS and INC values on the command line
Also, you may try to run perl Makefile.PL with the DEBUG=1 parameter
to see the exact reason why the detection of '$lib' installation
failed or why Makefile.PL was not able to compile a test program.
DEATH
exit 1;
}
}
return \%libs;
}
sub parse_params {
my %params;
@params{qw(DEBUG TRACE INC LIBS XMLPREFIX)} = ();
@ARGV = grep {
my ($key, $val) = split(/=/, $_, 2);
if (exists $params{$key}) {
$params{$key} = $val; 0
} else { 1 }
} @ARGV;
$params{WIN32} = ($^O =~ /Win32/);
if ( $params{WIN32} ) {
$params{DEVNULL} = 'DEVNULL';
}
else {
$params{DEVNULL} = eval { File::Spec->devnull };
if ($@) { $params{DEVNULL} = '/dev/null' }
}
return %params;
}
sub backtick {
my $command = join(' ', @_);
if ($PARAMS{DEBUG}) {
print "Cmd: $command \n";
my $results = `$command`;
if ($? != 0) {
warn "Backticks call to '$command' failed";
return;
}
chomp $results;
return $results;
}
local *OLDOUT;
local *OLDERR;
open(OLDOUT, ">&STDOUT");
open(OLDERR, ">&STDERR");
open(STDOUT, ">$PARAMS{DEVNULL}");
open(STDERR, ">$PARAMS{DEVNULL}");
my $results = `$command`;
my $retval = $?;
open(STDOUT, ">&OLDOUT");
open(STDERR, ">&OLDERR");
if ($retval != 0) {
if ($PARAMS{DEBUG}) {
warn "backticks call to '$command' failed";
}
return;
}
chomp $results;
return $results;
}