our
@ISA
=
qw( Exporter )
;
our
@EXPORT
=
qw( isbigendian
PDL_INCLUDE PDL_TYPEMAP
PDL_AUTO_INCLUDE PDL_BOOT
PDL_INST_INCLUDE PDL_INST_TYPEMAP
pdlpp_eumm_update_deep
pdlpp_postamble_int pdlpp_stdargs_int
pdlpp_postamble pdlpp_stdargs write_dummy_make
unsupported trylink get_maths_libs
pdlpp_mkgen
got_complex_version
)
;
sub
PDL_INCLUDE {
'"-I'
.catdir(whereami_any(),
'Core'
).
'"'
}
sub
PDL_TYPEMAP { catfile(whereami_any(),
qw(Core typemap)
) }
*PDL_INST_INCLUDE
= \
&PDL_INCLUDE
;
*PDL_INST_TYPEMAP
= \
&PDL_TYPEMAP
;
sub
PDL_AUTO_INCLUDE {
my
(
$symname
) =
@_
;
$symname
||=
'PDL'
;
return
<<
"EOR"
;
static Core*
$symname
; /* Structure holds core C functions */
EOR
}
sub
PDL_BOOT {
my
(
$symname
,
$module
) =
@_
;
$symname
||=
'PDL'
;
$module
||=
'The code'
;
return
<<
"EOR"
;
perl_require_pv (
"PDL/Core.pm"
); /* make sure PDL::Core is loaded */
if
(SvTRUE (ERRSV)) Perl_croak(aTHX_
"%s"
,SvPV_nolen (ERRSV));
SV* CoreSV = perl_get_sv(
"PDL::SHARE"
,FALSE); /* var
with
core structure */
if
(!CoreSV)
Perl_croak(aTHX_
"We require the PDL::Core module, which was not found"
);
if
(!(
$symname
= INT2PTR(Core*,SvIV( CoreSV )))) /* Core* value */
Perl_croak(aTHX_
"Got NULL pointer for $symname"
);
if
(
$symname
->Version != PDL_CORE_VERSION)
Perl_croak(aTHX_
"[$symname->Version: \%ld PDL_CORE_VERSION: \%ld XS_VERSION: \%s] $module needs to be recompiled against the newly installed PDL"
, (long
int
)
$symname
->Version, (long
int
)PDL_CORE_VERSION, XS_VERSION);
EOR
}
my
$MY_FILE
= abs_path(__FILE__);
my
$MY_DIR2
= dirname(dirname(
$MY_FILE
));
sub
whereami_any {
$MY_DIR2
}
sub
isbigendian {
my
$byteorder
=
$Config
{byteorder} ||
die
"ERROR: Unable to find 'byteorder' in perl's Config\n"
;
return
1
if
$byteorder
eq
"4321"
;
return
1
if
$byteorder
eq
"87654321"
;
return
0
if
$byteorder
eq
"1234"
;
return
0
if
$byteorder
eq
"12345678"
;
die
"ERROR: PDL does not understand your machine's byteorder ($byteorder)\n"
;
}
sub
_oneliner {
my
(
$cmd
,
@flags
) =
@_
;
my
$MM
=
bless
{
NAME
=>
'Fake'
},
'MM'
;
$MM
->oneliner(
$cmd
, \
@flags
);
}
my
%flist_cache
;
sub
_pp_call_arg {
"-MPDL::PP="
.
join
','
,
@_
}
sub
_postamble {
my
(
$w
,
$internal
,
$src
,
$base
,
$mod
,
$callpack
,
$multi_c
,
$deep
) =
@_
;
$callpack
//=
''
;
$w
= dirname(
$w
);
my
$perlrun
=
"\$(PERLRUN) \"-I$w\""
;
my
(
$pmdep
,
$install
,
$cdep
) = (
$src
,
''
,
''
);
my
(
$ppc
,
$ppo
) = (
$multi_c
&&
$flist_cache
{File::Spec::Functions::rel2abs(
$src
)})
?
map
"\$($_)"
, pdlpp_mod_vars(
$mod
)
: pdlpp_mod_values(
$internal
,
$src
,
$base
,
$multi_c
);
if
(
$internal
) {
my
$ppdir
= File::Spec::Functions::abs2rel(catdir(
$w
,
qw(PDL)
));
$pmdep
.=
join
' '
,
''
, catfile(
$ppdir
,
'PP.pm'
),
glob
(catfile(
$ppdir
,
'PP/*'
));
$cdep
.=
join
' '
,
$ppo
,
':'
,
map
catfile(
$ppdir
,
qw(Core)
,
$_
),
qw(pdl.h pdlcore.h pdlbroadcast.h pdlmagic.h)
;
}
else
{
my
$oneliner
= _oneliner(
qq{exit if \$ENV{DESTDIR}
;
use
PDL::Doc;
eval
{ PDL::Doc::add_module(
q{$mod}
); }});
$install
=
qq|\ninstall ::\n\t\@echo "Updating PDL documentation database...";\n\t$oneliner\n|
;
}
my
$pp_call_arg
= _pp_call_arg(
$mod
,
$mod
,
$base
,
$callpack
,
$multi_c
||
''
,
$deep
||
''
);
qq|
$base.pm : $pmdep
$perlrun \"$pp_call_arg\" $src
\$(TOUCH) $base.pm
$ppc : $base.pm
\$(NOECHO) \$(NOOP)
$cdep
$install|
}
sub
pdlpp_postamble_int {
my
$w
= whereami_any();
join
''
,
map
_postamble(
$w
, 1,
@$_
[0..3], 1,
@$_
[5..
$#$_
]),
@_
;
}
sub
pdlpp_postamble {
my
$w
= whereami_any();
join
''
,
map
_postamble(
$w
, 0,
@$_
),
@_
;
}
our
%EXTRAS
;
sub
pdlpp_eumm_update_deep {
my
(
$eumm
) =
@_
;
my
$pm
=
$eumm
->{PM};
delete
@$pm
{
grep
/\Q
$Config
{obj_ext}\E$/,
keys
%$pm
};
my
$macro
=
$eumm
->{macro} ||= {};
my
$xsb
=
$eumm
->{XSBUILD}{xs} ||= {};
$eumm
->{clean}{FILES} ||=
''
;
$eumm
->{OBJECT} ||=
''
;
$eumm
->{INC} ||=
''
;
my
$pdl_inc
= PDL_INCLUDE();
$eumm
->{INC} .=
' '
.
$pdl_inc
if
index
(
$eumm
->{INC},
$pdl_inc
) == -1;
my
$tms
=
$eumm
->{TYPEMAPS} ||= [];
my
$pdl_tm
= PDL_TYPEMAP();
push
@$tms
,
$pdl_tm
if
!
grep
$_
eq
$pdl_tm
,
@$tms
;
$eumm
->{XSMULTI} ||= 1;
$eumm
->{dist}{PREOP} ||=
'$(PERLRUNINST) -MPDL::Core::Dev -e pdlpp_mkgen $(DISTVNAME)'
;
my
$xs
=
$eumm
->{XS} ||= {};
my
$global_version
=
$eumm
->parse_version(
$eumm
->{VERSION_FROM});
my
@pd_srcs
;
for
my
$f
(
grep
/\.pd$/,
keys
%$pm
) {
delete
$pm
->{
$f
};
my
$nolib
= (
my
$base
=
$f
=~ s/\.pd$//r) =~ s
$xs
->{
"$base.xs"
} =
"$base.c"
;
my
$pmfile
=
"$base.pm"
;
$pm
->{
$pmfile
} =
"\$(INST_LIB)/$nolib.pm"
;
my
@macro_vars
= pdlpp_mod_vars(
my
$mod
=
join
'::'
,
split
/\//,
$nolib
);
@$macro
{
@macro_vars
} = pdlpp_mod_values(1,
$f
,
$base
, 1, 1);
$eumm
->{OBJECT} .=
" $base\$(OBJ_EXT)"
;
$xsb
->{
$base
}{OBJECT} =
"\$($macro_vars[1])"
;
$xsb
->{
$base
}{OBJECT} .=
$EXTRAS
{
$f
}{OBJECT}
if
$EXTRAS
{
$f
}{OBJECT};
$eumm
->{DEFINE} .=
$EXTRAS
{
$f
}{DEFINE}
if
$EXTRAS
{
$f
}{DEFINE};
$eumm
->{INC} .=
" $EXTRAS{$f}{INC}"
if
$EXTRAS
{
$f
}{INC};
my
$mtime
= (
stat
$f
)[9] //
die
"$f: $!"
;
open
my
$fh
,
">"
,
$pmfile
or
die
"$pmfile: $!"
;
print
$fh
"package $mod;\nour \$VER"
.
"SION = '$global_version';\n1;\n"
;
close
$fh
;
utime
$mtime
- 120,
$mtime
- 120,
$pmfile
;
push
@pd_srcs
, [
$f
,
$base
,
$mod
,
''
, 1, 1];
my
$clean_extra
=
join
' '
,
''
,
$pmfile
,
map
"\$($_)"
,
@macro_vars
;
$clean_extra
.=
$EXTRAS
{
$f
}{OBJECT}
if
$EXTRAS
{
$f
}{OBJECT};
if
(
ref
$eumm
->{clean}{FILES}) {
push
@{
$eumm
->{clean}{FILES}},
$clean_extra
;
}
else
{
$eumm
->{clean}{FILES} .=
$clean_extra
;
}
}
delete
@$pm
{
grep
/\.c$/,
keys
%$pm
};
@pd_srcs
;
}
sub
pdlpp_list_functions {
my
(
$src
,
$internal
,
$base
) =
@_
;
my
$abs_src
= File::Spec::Functions::rel2abs(
$src
);
if
(!
$flist_cache
{
$abs_src
}) {
my
$w
= whereami_any();
if
(!
$INC
{
'PDL/Types.pm'
}) {
my
$typespm
= catfile(
$w
,
'Types.pm'
);
require
$typespm
;
$INC
{
'PDL/Types.pm'
} = 1;
}
require
''
.catfile(
$w
,
qw(PP.pm)
);
$::PDLBASE =
$base
;
$flist_cache
{
$abs_src
} = [ PDL::PP::list_functions(
$src
) ];
}
@{
$flist_cache
{
$abs_src
} };
}
sub
pdlpp_mod_vars {
my
@parts
=
split
/::/,
$_
[0];
shift
@parts
if
$parts
[0] eq
'PDL'
;
my
$mangled
=
join
'_'
,
@parts
;
map
"PDL_MULTIC_${mangled}_$_"
,
qw(C O)
;
}
sub
pdlpp_mod_values {
my
(
$internal
,
$src
,
$base
,
$multi_c
,
$deep
) =
@_
;
return
(
"$base.xs"
,
"$base\$(OBJ_EXT)"
)
if
!
$multi_c
;
my
$cfileprefix
=
$deep
?
"$base-"
:
''
;
my
@cbase
=
map
$cfileprefix
.
"pp-$_"
, pdlpp_list_functions(
$src
,
$internal
,
$base
);
(
join
(
' '
,
"$base.xs"
,
map
"$_.c"
,
@cbase
),
join
(
' '
,
map
"$_\$(OBJ_EXT)"
,
$base
,
@cbase
));
}
sub
_stdargs {
my
(
$w
,
$internal
,
$src
,
$base
,
$mod
,
$callpack
,
$multi_c
) =
@_
;
my
(
$clean
,
%hash
) =
''
;
if
(
$multi_c
) {
my
(
$mangled_c
,
$mangled_o
) = pdlpp_mod_vars(
$mod
);
my
(
$mangled_c_val
,
$mangled_o_val
) = pdlpp_mod_values(
$internal
,
$src
,
$base
,
$multi_c
);
%hash
= (
%hash
,
macro
=> {
$mangled_c
=>
$mangled_c_val
,
$mangled_o
=>
$mangled_o_val
,
},
OBJECT
=>
"\$($mangled_o)"
,
);
$clean
.=
" \$($mangled_c)"
;
}
else
{
%hash
= (
%hash
,
OBJECT
=>
"$base\$(OBJ_EXT)"
);
$clean
.=
" $base.xs"
;
}
if
(
$internal
) {
$hash
{depend} = {
"$base\$(OBJ_EXT)"
=> File::Spec::Functions::abs2rel(catfile(
$w
,
qw(PDL Core pdlperl.h)
)),
};
}
(
NAME
=>
$mod
,
VERSION_FROM
=> (
$internal
? catfile(
$w
,
qw(PDL Core.pm)
) :
$src
),
TYPEMAPS
=> [PDL_TYPEMAP()],
PM
=> {
"$base.pm"
=>
"\$(INST_LIBDIR)/$base.pm"
},
MAN3PODS
=> {
"$base.pm"
=>
"\$(INST_MAN3DIR)/$mod.\$(MAN3EXT)"
},
INC
=> PDL_INCLUDE(),
LIBS
=> [
''
],
clean
=> {
FILES
=>
"$base.pm $base.c$clean"
},
%hash
,
(
$internal
? (
NO_MYMETA
=> 1)
: (
dist
=> {
PREOP
=>
'$(PERLRUNINST) -MPDL::Core::Dev -e pdlpp_mkgen $(DISTVNAME)'
})
),
);
}
sub
pdlpp_stdargs_int {
_stdargs(dirname(
$MY_DIR2
), 1, @{
$_
[0]}[0..3], 1);
}
sub
pdlpp_stdargs {
_stdargs(
undef
, 0, @{
$_
[0]});
}
sub
pdlpp_mkgen {
my
$dir
=
@_
> 0 ?
$_
[0] :
$ARGV
[0];
die
"pdlpp_mkgen: unspecified directory"
unless
defined
$dir
&& -d
$dir
;
my
$file
=
"$dir/MANIFEST"
;
die
"pdlpp_mkgen: non-existing '$file\'"
unless
-f
$file
;
my
@pairs
= ();
my
$manifest
= ExtUtils::Manifest::maniread(
$file
);
for
(
grep
!/^(t|xt)\// && /\.pd$/ && -f,
sort
keys
%$manifest
) {
my
$content
=
do
{
local
$/;
open
my
$in
,
'<'
,
$_
; <
$in
> };
warn
(
"pdlpp_mkgen: unknown module name for '$_' (use proper '=head1 NAME' section)\n"
),
next
if
!(
my
(
$name
) =
$content
=~ /=head1\s+NAME\s+(\S+)\s+/sg);
push
@pairs
, [
$_
,
$name
];
}
my
%added
= ();
my
@in
=
map
"-I"
.File::Spec::Functions::rel2abs(
$_
),
@INC
;
for
(
@pairs
) {
my
(
$pd
,
$mod
) =
@$_
;
(
my
$prefix
=
$mod
) =~ s|::|/|g;
my
$outfile
= File::Spec::Functions::rel2abs(
"$dir/GENERATED/$prefix.pm"
);
File::Path::mkpath(dirname(
$outfile
));
my
$old_cwd
= Cwd::cwd();
my
$maybe_lib_base
=
"lib/$prefix"
;
my
$maybe_lib_path
=
"$maybe_lib_base.pd"
;
my
$is_lib_path
=
substr
(
$pd
, -
length
$maybe_lib_path
) eq
$maybe_lib_path
;
my
$todir
=
$is_lib_path
?
substr
(
$pd
, 0, -
length
(
$maybe_lib_path
)-1) : dirname(
$pd
);
chdir
$todir
if
$todir
;
my
$basename
=
$is_lib_path
?
$maybe_lib_base
: (
split
'/'
,
$prefix
)[-1];
my
$pp_call_arg
= _pp_call_arg(
$mod
,
$mod
,
$basename
,
''
, 0);
my
$rv
=
system
$^X,
@in
,
$pp_call_arg
,
$is_lib_path
?
"$basename.pd"
: basename(
$pd
);
my
$basefile
=
"$basename.pm"
;
die
"pdlpp_mkgen: cannot convert '$pd'\n"
unless
$rv
== 0 && -f
$basefile
;
File::Copy::copy(
$basefile
,
$outfile
) or
die
"$outfile: $!"
;
unlink
$basefile
;
unlink
"$basename.xs"
;
chdir
$old_cwd
or
die
"chdir $old_cwd: $!"
;
$added
{
"GENERATED/$prefix.pm"
} =
"mod=$mod pd=$pd (added by pdlpp_mkgen)"
;
}
if
(
scalar
(
keys
%added
) > 0) {
local
$ExtUtils::Manifest::MANIFEST
=
$file
;
ExtUtils::Manifest::maniadd(\
%added
);
}
}
sub
unsupported {
my
(
$package
,
$os
) =
@_
;
"No support for $package on $os platform yet. Will skip build process"
;
}
sub
write_dummy_make {
my
(
$msg
) =
@_
;
$msg
=~ s
$msg
=~ s
print
$msg
;
ExtUtils::MakeMaker::WriteEmptyMakefile(
NAME
=>
'Dummy'
,
DIR
=> []);
}
sub
getcyglib {
my
(
$lib
) =
@_
;
my
$lp
= `gcc -
print
-file-name=lib
$lib
.a`;
$lp
=~ s|/[^/]+$||;
$lp
=~ s|^([a-z,A-Z]):|//$1|g;
return
"-L$lp -l$lib"
;
}
sub
trylink {
my
$opt
=
ref
$_
[
$#_
] eq
'HASH'
?
pop
: {};
my
(
$txt
,
$inc
,
$body
,
$libs
,
$cflags
) =
@_
;
$cflags
||=
''
;
for
my
$key
(
keys
%$opt
) {
$opt
->{
lc
$key
} =
$opt
->{
$key
}}
my
$mmprocess
=
exists
$opt
->{makemaker} &&
$opt
->{makemaker};
my
$hide
=
$opt
->{hide} //
$ENV
{HIDE_TRYLINK} // 1;
my
$clean
=
exists
$opt
->{clean} ?
$opt
->{clean} : 1;
if
(
$mmprocess
) {
my
$self
= ExtUtils::MakeMaker->new({
DIR
=> [],
'NAME'
=>
'NONE'
});
my
@libs
=
$self
->ext(
$libs
, 0);
print
"processed LIBS: $libs[0]\n"
unless
$hide
;
$libs
=
$libs
[0];
}
print
" Trying $txt...\n "
if
$txt
=~ /\S/;
my
$HIDE
= !
$hide
?
''
:
'>/dev/null 2>&1'
;
if
($^O =~ /mswin32/i) {
$HIDE
=
'>NUL 2>&1'
}
my
$tempd
= File::Temp::tempdir(
CLEANUP
=>1) ||
die
"trylink: could not make temp dir"
;
my
(
$tc
,
$te
) =
map
catfile(
$tempd
,
"testfile$_"
), (
'.c'
,
''
);
open
FILE,
">$tc"
or
die
"trylink: couldn't open testfile `$tc' for writing, $!"
;
my
$prog
=
<<"EOF";
$inc
int main(void) {
$body
return 0;
}
EOF
print
FILE
$prog
;
close
FILE;
open
(T,
">$te"
) or
die
(
"unable to write to test executable `$te'"
);
close
T;
my
$cmd
=
"$Config{cc} $cflags -o $te $tc $libs $HIDE"
;
print
"$cmd ...\n"
unless
$hide
;
my
$success
= (
system
(
$cmd
) == 0) && -e
$te
? 1 : 0;
unlink
$te
,
$tc
if
$clean
;
print
$success
?
"\t\tYES\n"
:
"\t\tNO\n"
unless
$txt
=~ /^\s*$/;
print
$success
?
"\t\tSUCCESS\n"
:
"\t\tFAILED\n"
if
$txt
=~ /^\s*$/ && !
$hide
;
return
$success
;
}
sub
get_maths_libs {
return
''
if
$^O =~ /MSWin/;
return
getcyglib(
'm'
)
if
$^O =~ /cygwin/;
return
'-lm'
if
!($^O eq
'solaris'
or $^O eq
'sunos'
);
my
$libs
=
'-lm'
;
my
@d
=
split
/:+/,
$ENV
{LD_LIBRARY_PATH};
my
$ok
= 0;
for
my
$d
(
@d
) {
if
(-e
"$d/libsunmath.so"
or -e
"$d/libsunmath.a"
) {
$libs
=
"-lsunmath $libs"
;
$ok
= 1;
last
;
}
}
return
$libs
if
$ok
;
print
"libsunmath not found in LD_LIBRARY_PATH: looking elsewhere\n"
;
my
@dirs
=
map
dirname(
$_
).
'/lib'
,
grep
defined
,
scalar
File::Which::which(
$Config
{cc});
push
@dirs
,
'/opt/SUNWspro/lib'
;
for
my
$d
(
@dirs
) {
if
(-e
"$d/libsunmath.so"
) {
$libs
=
"-R$d -L$d -lsunmath $libs"
;
$ok
= 1;
last
;
}
if
(-e
"$d/libsunmath.a"
) {
$libs
=
"-L$d -lsunmath $libs"
;
$ok
= 1;
last
;
}
}
print
<<'EOF' if !$ok;
Couldn't find sunmath library in standard places
If you can find libsunmath.a or libsunmath.so
please let us know at pdl-devel@lists.sourceforge.net
EOF
$libs
;
}
my
%flags
= (
hdrcpy
=> {
set
=> 1 },
fflows
=> {
FLAG
=>
"DATAFLOW_F"
},
is_readonly
=> {
FLAG
=>
"READONLY"
},
is_inplace
=> {
FLAG
=>
"INPLACE"
,
postset
=> 1 },
set_inplace
=> {
FLAG
=>
"INPLACE"
,
noret
=> 1 },
donttouch
=> {
FLAG
=>
"DONTTOUCHDATA"
},
allocated
=> { },
vaffine
=> {
FLAG
=>
"OPT_VAFFTRANSOK"
},
anychgd
=> {
FLAG
=>
"ANYCHANGED"
},
datachgd
=> {
FLAG
=>
"PARENTDATACHANGED"
},
dimschgd
=> {
FLAG
=>
"PARENTDIMSCHANGED"
},
);
sub
generate_core_flags {
foreach
my
$name
(
sort
keys
%flags
) {
my
$flag
=
"PDL_"
. (
$flags
{
$name
}{FLAG} ||
uc
(
$name
));
my
$ref
=
$flags
{
$name
};
my
$with_mode
=
grep
$ref
->{
$_
},
qw(set postset noret)
;
my
$mode_dflt
= (
grep
$ref
->{
$_
},
qw(set postset)
) ?
"=0"
:
""
;
my
@mode
=
$with_mode
? (
",mode$mode_dflt"
,
"\n int mode"
) : (
''
,
''
);
printf
<<'EOF', $ref->{noret} ? 'void' : 'int', $name, @mode;
%s
%s(x%s)
pdl *x%s
CODE:
EOF
my
$cond
=
$ref
->{noret} ?
""
:
"if (items>1) "
;
my
$set
=
" ${cond}setflag(x->state,$flag,mode);\n"
;
my
$ret
=
" RETVAL = ((x->state & $flag) > 0);\n"
;
print
$set
if
$ref
->{set} ||
$ref
->{noret};
print
$ret
if
!
$ref
->{noret};
print
$set
if
$ref
->{postset};
print
" OUTPUT:\n RETVAL\n"
if
!
$ref
->{noret};
print
"\n"
;
}
}
my
%got_complex_cache
;
sub
got_complex_version {
my
(
$name
,
$params
) =
@_
;
return
$got_complex_cache
{
$name
}
if
defined
$got_complex_cache
{
$name
};
my
$args
=
join
','
, (
'(double complex)1'
) x
$params
;
$got_complex_cache
{
$name
} = Devel::CheckLib::check_lib(
(
$Config
{gccversion} ? (
ccflags
=>
'-O0'
) : ()),
lib
=>
'm'
,
header
=>
'complex.h'
,
function
=>
sprintf
(
'double num; num = creal(c%sl(%s)); return 0;'
,
$name
,
$args
),
);
}
1;