$VERSION
=
'2.01080604'
;
@ISA
=
'Exporter'
;
@EXPORT
=
qw(get_pari_version
pari_formatted_version
find_pari_dir
download_pari
patch_pari
download_and_patch_pari
make_pod
build_tests
find_paricfg
find_or_Configure_paricfg
write_paricfg
build_paricfg
find_machine_architecture
known_asmarch
inline_headers
inline_headers2
not_gnu_as
choose_and_report_assembler
kernel_files
kernel_fill_data
assembler_flags
assembler_flags_via
extra_includes
ep_codes_from_file
ep_hash_report
ep_in_version
code_C_translator
build_funclists
)
;
sub
get_pari_version {
my
$dir
=
shift
;
my
$v
=
""
;
open
(IN,
"$dir/config/version"
) or
return
;
/(?:version|VersionMajor|VersionMinor|patch)=
'?(\d+(\.\d+)?)'
?/
and
$v
.=
"$1."
while
<IN>;
close
(IN) or
die
"error closing '$dir/config/version'"
;
$v
=~ s/\.$// or
return
;
return
$v
;
}
sub
pari_formatted_version {
my
$dir
=
shift
;
my
$v
;
$v
= get_pari_version
$dir
;
if
(
defined
$v
) {
$dir
=
$v
;
}
else
{
warn
(
<<EOW);
Could not extract version from '$dir/config/version';
Do you remember that paridir should be location of PARI/GP source tree,
not the location of compiled+installed files?
Trying extract from the directory name...
EOW
}
return
sprintf
'%d%03d%03d'
,$1, $2, $3
if
$dir
=~ /(\d+)\.(\d+).(\d+)(\.(alpha|beta))?$/;
warn
(
<<EOW);
Directory `$dir' has unknown syntax...
EOW
return
$dir
;
}
my
$latmus
=
'src/test/in/nfields'
;
sub
filter_versions_too_new {
my
$force
=
shift
;
my
@dirs
=
grep
!m((?:^|[\\/])pari-(?:
$common::skip_versions
)),
@_
;
print
"Filtered out versions too new...\n"
if
@dirs
!=
@_
;
return
@dirs
if
$force
or
@dirs
;
return
@_
;
}
sub
find_pari_dir {
my
(
$dir
,
@dirs
,
@gooddirs
);
for
$dir
(
'.'
,
'..'
,
'../..'
,
'../../..'
) {
@dirs
= filter_versions_too_new 0, <
$dir
/pari-[234].*>;
@dirs
=
"$dir/pari"
if
not
@dirs
and -d
"$dir/pari"
;
@dirs
=
grep
-e
"$_/$latmus"
,
@dirs
;
last
if
@dirs
;
}
@gooddirs
=
grep
!/alpha|beta/,
@dirs
;
@gooddirs
=
grep
!/alpha/,
@dirs
unless
@gooddirs
;
@gooddirs
=
@dirs
unless
@gooddirs
;
@gooddirs
=
sort
{pari_formatted_version(
$a
) cmp pari_formatted_version(
$b
)}
@gooddirs
;
return
$gooddirs
[-1];
}
sub
manual_download_instructions {
<<EOP;
One can rerun Makefile.PL after fetching GP/PARI archive (e.g., pari-2.1.7.tgz,
or pari-2.3.4.tar.gz) manually to the current directory, or a (grand)parent
directory of the current directory.
[Keep in mind that the numbers "inside version" of Math::Pari module
correspond to the last versions of GP/PARI it was tested with (additionally,
2.0108* works best with the last 2.1.* version, 2.1.7).
As an alternative to having archive in CWD or its (grand)parent, specify
pari_tgz=PATH_TO_TAR_GZ
option to Makefile.PL.
There is no need to extract the archive, or build GP/PARI; but if you
have it extracted [and patched, if needed], you may specify
paridir=PATH_TO_DIST_DIR
option to Makefile.PL instead of `pari_tgz'. However, in this case
the files WON'T be auto-patched.
As a last-resort solution, there is also a possibility to use an already
compiled PARI library. See the documentation in README and INSTALL files.]
EOP
}
sub
debug_no_response ($) {
return
''
unless
$ENV
{AUTOMATED_TESTING};
my
$r
=
shift
;
my
$c
=
$r
->content;
my
$t
=
$r
->content_type;
$c
=
'<<undef>>'
unless
defined
$c
;
$c
=~ s/\s+\Z/\n/;
my
$b
=
'====================='
;
return
"\n$b Response content (type=$t)\n$c\n$b\n\n"
;
}
sub
ll_ftp () {
open
OF,
'> ftp-cmd'
or
die
"Can't open `ftp-cmd' for write: $!"
;
print
OF
<<'EOF'; # XXXX Hardwired version!
user anonymous auto-download-Math-Pari@cpan.org
cd /pub/pari/unix/
dir
cd OLD
dir
binary
get pari-2.1.7.tgz
quit
EOF
close
OF or
die
"Can't close `ftp-cmd' for write: $!"
;
print
<<EOP;
==============================================
ftp -pinegv megrez.math.u-bordeaux.fr < ftp-cmd
EOP
my
$rc
=
system
"ftp -pinegv megrez.math.u-bordeaux.fr < ftp-cmd"
;
print
<<EOP;
==============================================
EOP
return
if
$rc
;
warn
<<EOW;
==========================================================================
===
=== If the output from FTP session above successfully lists
=== directories, your installs of Net::FTP and, possibly, LWP
=== is completely broken. How comes???
===
==========================================================================
EOW
warn
(
<<'EOW'), return unless $ENV{MATHPARI_USEFTP};
FTP session is for debugging only; I'm ignoring the downloaded file.
(Set $ENV{MATHPARI_USEFTP} to TRUE to actually use the downloaded file.)
EOW
return
'pari-2.1.7.tgz'
;
}
sub
download_pari {
my
(
$srcfile
,
$force
) = (
shift
,
shift
);
my
$host
=
'megrez.math.u-bordeaux.fr'
;
my
$dir
=
'/pub/pari/unix/'
;
my
(
$ftp
,
$ua
,
$base_url
);
print
"Did not find GP/PARI build directory around.\n"
unless
defined
$srcfile
;
my
@match
= (
'((?:.*\/)?pari\W*'
,
'(\d+\.\d+\.\d+).*\.t(?:ar\.)?gz)$'
);
my
$match1
=
"$match[0]$match[1]"
;
my
$match
=
"$match[0](?!$common::skip_versions)$match[1]"
;
my
%archive
;
my
$match_pari_archive
=
sub
{
my
(
$file
,
$ok23
) = (
shift
,
shift
);
return
unless
$ok23
?
$file
=~ /
$match1
/o :
$file
=~ /
$match
/o;
$file
= $1;
my
$version
= $2;
if
(
$file
=~ /alpha/) {
$archive
{alpha}{
$version
} =
$file
;
}
elsif
(
$file
=~ /beta/) {
$archive
{beta}{
$version
} =
$file
;
}
else
{
$archive
{golden}{
$version
} =
$file
;
}
};
if
(
$srcfile
and -s
$srcfile
) {
die
"The FILE supplied via the pari_tgz=$srcfile option did not match /$match/"
unless
$match_pari_archive
->(
$srcfile
,
'ok2.3'
);
}
else
{
if
(
$force
) {
print
"Forced autofetching...\n\n"
}
elsif
(not
$ENV
{AUTOMATED_TESTING} and not
$ENV
{PERL_MM_USE_DEFAULT}
and -t STDIN and (-t STDOUT or -p STDOUT)) {
$| = 1;
my
$mess
=
<<EOP;
Do you want to me to fetch GP/PARI automatically?
(If you do not, you will need to fetch it manually, and/or direct me to
the directory with GP/PARI source via the command-line option paridir=/dir)
Make sure you have a large scrollback buffer to see the messages, or `tee'
the STDOUT/STDERR to a file.
Fetch? (y/n, press Enter)
EOP
chomp
$mess
;
print
"$mess "
;
my
$ans
= <STDIN>;
if
(
$ans
!~ /y/i) {
my
(
$eA
,
$eM
,
$tI
,
$tO
,
$tE
,
$pO
,
$pE
)
= (
@ENV
{
qw(AUTOMATED_TESTING PERL_MM_USE_DEFAULT)
},
-t STDIN, -t STDOUT, -t STDERR, -p STDERR, -p STDOUT);
defined
() ?
$_
=
"'$_'"
:
$_
=
'<undef>'
for
$eA
,
$eM
;
print
<<EOP; # Is AUTOMATED_TESTING ALWAYS defined on smoke???
Well, as you wish...
[ to debug Smoke Tests: AUTOMATED_TESTING=$eA PERL_MM_USE_DEFAULT=$eM
-t STDIN/STDOUT/ERR = $tI/$tO/$tE -p STDOUT/ERR = $pO/$pE ]
EOP
print
manual_download_instructions();
return
;
}
}
else
{
print
"Non-interactive session, autofetching...\n\n"
}
$base_url
=
"ftp://$host$dir"
;
my
@extra_chdir
=
qw(OLD)
;
print
"Getting GP/PARI from $base_url\n"
;
eval
{
$ftp
= Net::FTP->new(
$host
) or
die
"Cannot create FTP object: $!"
;
$ftp
->login(
"anonymous"
,
"Math::Pari@"
)
or
die
"Cannot login anonymously ("
,
$ftp
->message(),
"): $!"
;
my
$c
= 0;
my
@Extra
=
@extra_chdir
;
while
(not
$c
) {
$ftp
->cwd(
$dir
) or
die
"Cannot cwd ("
,
$ftp
->message(),
"): $!"
;
$ftp
->binary() or
die
"Cannot switch to binary ("
,
$ftp
->message(),
"): $!"
;
my
@lst
=
$ftp
->ls();
@lst
or (
$ftp
->pasv() and
@lst
=
$ftp
->ls()) or
die
"Cannot list ("
,
$ftp
->message(),
"): $!"
;
%archive
= ();
for
my
$file
(
@lst
) {
$c
++
if
$match_pari_archive
->(
$file
);
}
unless
(
$c
) {
die
"Did not find any file matching /$match/ via FTP\n\n"
. manual_download_instructions()
unless
@Extra
;
$dir
=
shift
@Extra
;
print
"Not in this directory, now chdir('$dir')...\n"
;
}
}
};
if
($@) {
undef
$ftp
;
warn
"$@\nCan't fetch file with Net::FTP, now trying with LWP::UserAgent...\n"
;
or
die
"You do not have LWP::UserAgent and/or HTML::LinkExtor installed, cannot download, exiting...\n\n"
. manual_download_instructions();
my
$c
= 0;
my
@Extra
=
@extra_chdir
;
while
(not
$c
) {
$ua
= LWP::UserAgent->new;
$ua
->env_proxy;
my
$req
= HTTP::Request->new(
GET
=>
$base_url
);
my
$resp
=
$ua
->request(
$req
);
$resp
->is_success
or
die
"Can't fetch directory listing from $base_url: "
.
$resp
->as_string;
%archive
= ();
if
(
$resp
->content_type eq
'text/html'
) {
my
$p
= HTML::LinkExtor->new;
$p
->parse(
$resp
->content);
for
my
$link
(
$p
->links) {
my
(
$tag
,
%attr
) =
@$link
;
next
if
$tag
ne
'a'
;
$c
++
if
$match_pari_archive
->(
$attr
{href});
}
}
else
{
foreach
my
$file
(
split
/\n/,
$resp
->content) {
$c
++
if
$match_pari_archive
->(
$file
);
}
}
unless
(
$c
) {
unless
(
@Extra
) {
warn
debug_no_response(
$resp
)
.
"Did not find any file matching /$match/ via FTP.\n\n"
;
my
$f
= ll_ftp or
die
manual_download_instructions();
return
download_pari(
$f
);
}
my
$dir
=
shift
@Extra
;
$base_url
.=
"$dir/"
;
print
"Not in this directory, trying `$base_url'...\n"
;
}
}
}
}
sub
fmt_version {
sprintf
"%03d%03d%03d"
,
split
/\./,
shift
}
my
(
$type
,
%have
,
%types
,
$best
,
%latest_version
,
%latest_file
);
for
$type
(
qw(alpha beta golden)
) {
if
(
$archive
{
$type
}) {
$have
{
$type
}++;
$best
=
$type
;
my
@files
=
keys
%{
$archive
{
$type
}};
print
"Available $type versions: `@files'\n"
;
$latest_version
{
$type
} = (
sort
{fmt_version(
$a
) cmp fmt_version(
$b
)}
keys
%{
$archive
{
$type
}})[-1];
$latest_file
{
$type
} =
$archive
{
$type
}{
$latest_version
{
$type
}};
print
qq(Latest supported $type is `$latest_file{$type}'\n)
;
}
}
if
(!
$archive
{golden} and
$latest_version
{beta} eq
'2.0.11'
and
$latest_version
{alpha} eq
'2.0.14'
) {
$best
=
'alpha'
;
}
undef
$dir
;
my
$version
;
if
(
$best
) {
my
$file
=
$latest_file
{
$best
};
$version
=
$latest_version
{
$best
};
print
qq(Picking $best version $version, file $file\n)
;
if
(-f
$file
) {
print
qq(Well, I already have it, using the disk copy...\n)
;
}
else
{
print
qq(Downloading `$base_url$file'...\n)
;
if
(
$ftp
) {
$ftp
->get(
$file
) or
die
"Cannot get via FTP ("
,
$ftp
->message(),
"): $!"
;
$ftp
->quit or
warn
"Warning: cannot quit FTP: "
,
$ftp
->message();
}
else
{
my
$req
= HTTP::Request->new(
GET
=>
"$base_url$file"
);
my
$resp
=
$ua
->request(
$req
);
$resp
->is_success
or
die
"Can't fetch $base_url/$file: "
.
$resp
->as_string;
my
$base
= basename(
$file
);
open
(F,
">$base"
) or
die
"Can't write to $base: $!"
;
binmode
F or
die
"Can't binmode(): $!"
;
print
F
$resp
->content;
close
F;
}
print
qq(Downloaded...\n)
;
}
print
qq(Extracting...\n)
;
my
$zcat
=
"gzip -dc"
;
print
"$zcat $file | tar -xvf -\n"
;
system
"$zcat $file | tar -xvf -"
and
do
{
print
"Can't un-targz PARI: \$!=$!, exitcode=$?.\n"
;
my
@cmd
= ($^X,
qw(-MArchive::Tar -wle)
,
'Archive::Tar->new(shift)->extract()'
,
$file
);
print
' Now retry with "'
,
join
(
'" "'
,
@cmd
), "\
"\n"
;
system
@cmd
and
die
"Can't un-targz PARI: \$!=$!, exitcode=$?.\n"
};
(
$dir
=
$file
) =~ s,(?:.*[\\/])?(.*)\.t(ar\.)?gz$,$1,
or
die
"malformed name `$file'"
;
-d
$dir
or
die
"Did not find directory $dir!"
;
}
return
(
$dir
,
$version
);
}
sub
patches_for ($) {
my
(
$v
) = (
shift
);
my
%patches
= (
'2.0.11'
=> [
qw(
patch11/diff_pari_gnuplot_aa
patch11/patch_pari_round0
patch11/patches_round1_short
patch11/diff_pari_fixed_interfaces_011
patch11/diff_pari_highlevel_hash_011a
patch11/diff_pari_ret_proto_2011)
],
'2.0.12'
=> [
'patch12/diff_for_perl_2012'
],
'2.0.13'
=> [
'patch13/diff_for_perl_2013'
,
'patch13/diff_for_gnuplot_2013'
],
'2.0.14'
=> [
'patch14/diff_for_perl_2014'
,
'patch14/diff_extra_2014'
,
'patch14/diff_last_2014'
,
'patch14/diff_plot_2014'
],
'2.0.15'
=> [
'patch15/diff_cast_2015'
,
'patch15/diff_errout_2015'
,
'patch15/diff_gnuplot_2015'
,
'patch15/diff_proto_2015'
,
'patch15/diff_errpari_2015'
,
'patch15/diff_pari_gnuplot_2015'
],
'2.0.16'
=> [
'patch16/diff_gnuplot_2016'
],
'2.1.2'
=> [
'patches/diff_2.1.2_gccism'
],
'2.1.3'
=> [
'patches/diff_2.1.3_interface'
],
'2.1.4'
=> [
'patches/diff_2.1.4_interface'
],
'2.1.5'
=> [
'patches/diff_2.1.4_interface'
],
'2.2.2'
=> [
'patches/diff_2.2.2_interface'
],
'2.1.6'
=> [
'patches/diff_2.1.6_ploth64'
,
'patches/diff_2.1.6_align_power_of_2'
,
'patches/diff_2.1.6_no-common'
],
'2.1.7'
=> [
($^O =~ /darwin/i ?
'patches/diff_2.1.6_no-common'
: ()),
($^O eq
'MSWin32'
?
'patches/diff_2.1.7_mingw-w64'
: ()),
'patches/patch-pari-unnormalized-float'
,
'patches/diff_2.1.7_-O'
,
'patches/diff_2.1.7_div'
,
'patches/diff_2.1.6_align_power_of_2'
,
'patches/diff_2.1.7_restart'
],
'2.3.5'
=> [
($^O eq
'MSWin32'
?
'patches/diff_2.3.5_mingw-w64'
: ())],
);
print
"Looking for patches for $v...\n"
;
my
@p
=
$patches
{
$v
} ? @{
$patches
{
$v
}} : ();
push
@p
,
'patches/diff_pari-2.1.3-ix86-divl'
if
$v
le
'2.1.3'
or
$v
ge
'2.2'
and
$v
le
'2.2.2'
;
@p
;
}
sub
patch_args ($) {
return
'/'
unless
$^O =~ /win32/i;
my
(
$patch
,
$p
) = (
shift
,
'utils/inc_h.diff'
);
$p
=~ s,/,\\,g;
system
"$patch -p1 --binary < $p"
or
warn
(
"... Apparently, your patch takes flag --binary...\n"
),
return
(
'\\'
,
'--binary'
);
return
'\\'
;
}
sub
patch_pari {
my
(
$dir
,
$version
) = (
shift
,
shift
);
$version
= get_pari_version(
$dir
)
unless
defined
$version
;
my
@patches
= patches_for(
$version
) or
return
;
print
"Patching...\n"
;
my
$patch
=
$Config
{gnupatch} ||
'patch'
;
my
(
$dir_sep
,
@args
) = patch_args
$patch
;
my
(
$rc
,
$p
) =
join
'; '
,
$dir_sep
,
@args
,
''
;
foreach
$p
(
@patches
) {
(
my
$pp
=
"../$p"
) =~ s,/,
$dir_sep
,g;
my
$cmd
=
"cd $dir && $patch -p1 @args < $pp"
;
print
"$cmd\n"
;
system
"$cmd"
and
warn
"...Could not patch: \$?=$?, $!; continuing anyway...\n"
;
$rc
.=
"'$pp' => $?, "
}
print
"Finished patching...\n"
;
$rc
=~ s/,?\s+$//;
$rc
}
sub
download_and_patch_pari {
my
(
$file
,
$force
,
@rc
) = (
shift
,
shift
);
my
(
$dir
,
$version
) = download_pari(
$file
,
$force
);
@rc
= patch_pari(
$dir
,
$version
)
if
defined
$dir
;
return
$dir
unless
wantarray
;
(
$dir
,
@rc
);
}
sub
make_pod {
my
(
$targ
,
$how
,
$paridir
) =
@_
;
if
(not -e
$targ
or -M
$targ
> -M
"$paridir/doc/usersch3.tex"
or -M
$targ
> -M
"libPARI/gphelp"
) {
if
(-f
$targ
) {
chmod
0666,
$targ
;
unlink
$targ
;
}
(
system
"$^X libPARI/gphelp $how $paridir/doc/usersch3.tex > tmp_pod "
and (
warn
(
"Errors when converting documentation: $?"
), 0))
or
rename
'tmp_pod'
,
$targ
;
}
}
sub
scan_headers {
my
$opts
=
shift
;
warn
"Scanning header files...\n"
;
my
$cmd
=
"$Config{cpprun} $Config{cppflags} utils/inc.h 2>&1"
;
open
INC,
"$cmd |"
or
warn
(
"Error $! from: $cmd\n"
),
return
;
$opts
->{clk_tck_def} = 1;
while
(<INC>) {
$opts
->{have_ulong} = 1,
warn
"...ulong\n"
if
/\btypedef\b.*\bulong\s*;/;
$opts
->{clk_tck_def} = 0,
warn
"...CLK_TCK not defined\n"
if
/y\s*=\s
*CLK_TCK
\b/;
$opts
->{have_getrusage} = 1,
warn
"...getrusage\n"
if
/\bgetrusage\s*\(/;
$opts
->{have_ladd} = 1,
warn
"...ladd\n"
if
/\bladd\b/;
}
close
INC or
warn
"Note (probably harmless): Errors reading from pipe: '$!', exit=$?: $cmd\n"
}
sub
build_tests {
my
$dir
=
shift
;
my
$paritests
=
"$dir/src/test/in"
;
opendir
TESTS,
$paritests
or
die
"Cannot find tests in $paritests: $!"
;
my
@tests
=
readdir
TESTS;
closedir
TESTS or
die
"Cannot find tests (close): $!"
;
my
$sou
=
'test_eng/ex.t'
;
my
$targ
=
"$sou-"
;
unless
(-e
$targ
and -M
$targ
<= -M
$sou
) {
$dir
=~ s/\\/\\\\\\\\/g;
my
$quote
= ($^O =~ /win32/i) ?
'"'
: "'";
system
"$^X -pe $quote s,CHANGE_ME,$dir, $quote $sou > $targ"
and
die
"Could not run test converter: $! $?"
;
}
$sou
=
$targ
;
my
$test
;
for
$test
(
@tests
) {
next
if
$test
=~ /^\.\.?$/;
next
if
$test
=~ /compat/;
next
if
-d
"$paritests/$test"
and
$test
eq
'CVS'
;
next
if
$test
=~ /(~|\.(bak|orig|rej))$/;
$targ
=
"t/55_$test.t"
;
if
(-f
$targ
) {
chmod
0666,
$targ
;
unlink
$targ
;
}
copy
$sou
,
$targ
or
die
"Cannot create test $test.t: $1"
;
}
}
sub
find_paricfg {
my
$paridir
=
shift
;
my
@paricfg
= <
$paridir
/o.*/paricfg.h>;
push
@paricfg
, <
$paridir
/O*/paricfg.h>;
@paricfg
=
grep
!/Odos/,
@paricfg
unless
$^O =~ /dos|djgcc|MSWin32/i;
unshift
@paricfg
,
"$paridir/win32/paricfg.h"
if
$^O eq
'MSWin32'
and -f
"$paridir/win32/paricfg.h"
;
@paricfg
;
}
sub
find_or_Configure_paricfg {
my
(
$paridir
,
$do_configure
) = (
shift
,
shift
);
my
@paricfg
= find_paricfg
$paridir
;
return
0
unless
$do_configure
;
if
(
@paricfg
== 0) {
print
"No existing paricfg.h found, running Configure...\n"
;
print
"cd $paridir ; sh ./Configure\n"
;
system
"cd $paridir ; sh ./Configure"
and
die
"Cannot configure: $!, exitcode=$?.\n"
;
print
"Configuration of GP/PARI successful.\n"
;
@paricfg
= find_paricfg
$paridir
;
}
if
(
@paricfg
== 0) {
warn
<<EOW;
Did not find paricfg.h. You may need to manually copy it to libPARI
directory from the GP/PARI build directory.
...Now switching to creation of paricfg.h by Perl code.
EOW
return
0;
}
my
$found
=
$paricfg
[0];
if
(
@paricfg
> 1) {
warn
"Found multiple paricfg.h: @paricfg.\n"
;
@paricfg
=
sort
{ -M
$a
<=> -M
$b
}
@paricfg
;
$found
=
$paricfg
[0];
warn
"Choosing newest paricfg.h: $found.\n"
;
}
if
(-e
'libPARI/paricfg.h'
and -M
$found
>= -M
'libPARI/paricfg.h'
) {
print
<<EOP; # Duplication with build_paricfg()...
Existing libPARI/paricfg.h not older than $found.
...Will not overwrite libPARI/paricfg.h... (remove it manually if needed);
You may also want to remove libPARI/paricfg.h if you configuration changed
from the time of the first build in this directory...
EOP
}
else
{
print
"Found $found, copying it to libPARI...\n"
;
copy
$found
,
'libPARI/paricfg.h'
or
die
"Could not copy $found to paricfg.h: $!"
if
not -e
'libPARI/paricfg.h'
or -M
$found
< -M
'libPARI/paricfg.h'
;
}
return
1;
}
sub
write_paricfg {
my
$version
=
shift
;
my
%opts
;
scan_headers(\
%opts
) or
$opts
{clk_tck_def} = 0;
warn
"Creating libPARI/paricfg.h...\n"
;
open
F,
'> libPARI/paricfg.h'
or
die
"open 'libPARI/paricfg.h' for write: $!"
;
print
F
<<EOP unless $^O =~ /win32/i; # Should not we check for CygWin?
#define UNIX
EOP
my
$shellq
= ($^O eq
'os2'
or $^O =~ /win32/i or $^O eq
'dos'
) ?
q(")
:
q(')
;
my
$datadir
=
'/usr/local/lib/pari/'
;
{
local
%ENV
;
delete
$ENV
{GP_DATA_DIR};
(
my
$o
= `$^X -wle
"print shift"
"print(default(datadir))"
| gp -
q` || '')
=~ s,/?\n*$,,;
$datadir = "$o/" if length $o and -d $o;
}
# with 2.1.7, it is either in one of $miscdir/galdata $share_prefix/pari/galdata
my $miscdir = $datadir; # Not needed with 2.3.4
$datadir .= "galdata/" if $version < 2003000;
print F <<EOP;
#define SHELL_Q '\\$shellq'
EOP
print F <<EOP;
#define GPDATADIR "$datadir"
#define GPMISCDIR "$miscdir"
#define PARI_BYTE_ORDER $Config{byteorder}
#define NOEXP2 /* Otherwise elliptic.t:11 rounds differetly, and fails */
EOP
if ($opts{have_getrusage}) {
print F <<EOP if $Config{d_times};
#define USE_GETRUSAGE 1
EOP
} else {
print F <<EOP if $Config{d_times} and $^O !~ /win32/i; # times() missing there...
#define USE_TIMES 1
EOP
print F <<EOP if $Config{d_times} and $Config{i_time} and !$opts{clk_tck_def};
/* Reported to be needed on some Linuxes: */
#include <time.h>
EOP
print F <<EOP if not $Config{d_times} and $Config{d_ftime};
#define USE_FTIME 1
EOP
}
print F <<EOP if $Config{dlsrc} eq 'dl_dlopen.xs';
#define HAS_DLOPEN
EOP
print F <<EOP unless $opts{have_ulong};
#define ULONG_NOT_DEFINED
EOP
my $arch = find_machine_architecture();
my $bits64 = ($arch =~ /alpha|64/ # ppc is 32bit
or defined($Config{longsize}) and $Config{longsize} == 8);
print F <<EOP if $bits64;
#define LONG_IS_64BIT 1
EOP
if (!$bits64) {
# Order of words in a double
my @w = unpack 'LL', pack 'd', 2;
my $f = $w[1] ? 1 : 0;
die "Unknown double format" unless $w[$f] == (1<<30) and $w[1-$f] == 0;
print F <<EOP;
#define PARI_DOUBLE_FORMAT $f
EOP
}
print F <<EOP;
#define DL_DFLT_NAME NULL
EOP
print F <<EOP if $arch eq 'port';
#define __HAS_NO_ASM__
EOP
my @v = ($version =~ /^(\d+)(\d{3})(\d{3})$/)
or die "write_paricfg() needs a formatted version argument, got `
$version
'";
my
$vvv
= (((
$v
[0]) << 16) + ((
$v
[1]) << 8) + (
$v
[2]));
print
F
<<EOP; # <=2.3.0 it was used only in gp.c, which we don't compile
#define PARI_VERSION_CODE $vvv
#define PARI_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
#define PARI_VERSION_SHIFT 8
EOP
close
F or
die
"close 'libPARI/paricfg.h' for write: $!"
;
%opts
;
}
sub
build_paricfg {
my
(
$paridir
,
$do_configure
,
$version
) = (
shift
,
shift
,
shift
);
my
%opts
;
unless
(find_or_Configure_paricfg(
$paridir
,
$do_configure
)) {
if
(-r
'libPARI/paricfg.h'
) {
print
<<EOP unless $do_configure; # Duplication with find_or_Configure_paricfg()
...Will not overwrite libPARI/paricfg.h... (remove it manually if needed)
You may also want to remove libPARI/paricfg.h if your configuration changed
from the time of the first build in this directory...
EOP
}
else
{
print
"...Generating libPARI/paricfg.h ...\n"
;
%opts
= write_paricfg(
$version
);
}
}
%opts
;
}
sub
process_sparc {
my
$info
=
shift
;
return
'sparcv8_super'
if
$info
=~ /SuperSparc|TMS390Z5[05]|CY605|MB86934|RT625/;
return
'sparcv8_micro'
if
$info
=~ /TMS390S1[05]|MB8690[47]/;
return
shift
;
}
sub
find_machine_architecture () {
my
$os
= (
split
' '
,
$Config
{myuname})[0];
my
$machine
=
$os
;
if
(
$os
=~ /^irix/) {
$machine
=
'irix'
;
}
elsif
(
$os
=~ /^hp/) {
$machine
= `uname -m` ||
'hppa'
;
if
(
$machine
=~ m(^9000/[34])) {
$machine
=
'm68k'
;
}
elsif
(
$machine
ne
'ia64'
) {
$machine
=
'hppa'
;
}
}
elsif
(
$os
eq
'os2'
or
$os
eq
'netbsd'
or
$os
eq
'freebsd'
or
$os
=~ /^cygwin/) {
chomp
(
$machine
= `uname -m`);
$machine
||=
'ix86'
;
}
elsif
((
$Config
{archname} eq
'MSWin32-x86-multi-thread'
) && (
$Config
{cc} =~ /gcc/)) {
$machine
=
'ix86'
;
}
elsif
(0 and
$os
=~ /win32/i and not
$Config
{gccversion}) {
$machine
=
'port'
;
}
elsif
(
$os
eq
'ultrix'
) {
$machine
=
'mips'
;
}
elsif
(
$os
eq
'nextstep'
or -d
'/NextApps'
) {
chomp
(
$machine
= `file /bin/sh | sed
's/.*(for architecture \(.*\))/\1/'
`);
}
elsif
(
$os
eq
'darwin'
) {
chomp
(
$machine
= `uname -p`);
$machine
=
'ppc'
if
$machine
eq
'powerpc'
;
}
elsif
(
$os
eq
'osf1'
) {
$machine
=
'alpha'
if
(
split
' '
,
$Config
{myuname})[4] eq
'alpha'
;
}
elsif
(
$os
=~ /^cygwin/) {
$machine
=
$ENV
{HOSTTYPE};
}
elsif
(
$os
eq
'linux'
) {
chomp
(
$machine
= `uname -m`);
$machine
=
'sparcv9'
if
$machine
eq
'sparc64'
;
$machine
=
'hppa'
if
$machine
=~ /^parisc/;
if
(
$machine
eq
'sparc'
and -e
'/proc/cpuinfo'
&& -R
'/proc/cpuinfo'
) {
open
IN,
'/proc/cpuinfo'
or
die
"open /proc/cpuinfo: $!"
;
local
$/ =
undef
;
my
$info
= <IN>;
close
IN or
die
"close /proc/cpuinfo: $!"
;
$machine
= process_sparc
$info
,
$machine
;
}
}
elsif
(
$os
eq
'sunos'
) {
my
$type
= (
split
' '
,
$Config
{myuname})[4];
$type
= (
split
' '
,
$Config
{myuname})[3]
if
$type
eq
'sparc'
;
my
$redo
;
find_machine: {
if
(
$type
=~ /^sun3/) {
$machine
=
'm68k'
;
}
elsif
(
$type
=~ /^sun4[dm]/) {
local
$ENV
{PATH} =
"$ENV{PATH}:/dev/sbin"
;
my
$info
= `(prtconf||devinfo)2>&-`;
$info
=
join
' '
,
grep
/(TI|FMI|Cypress|Ross),/,
split
"\n"
,
$info
;
$machine
= process_sparc
$info
,
'sparcv8'
;
}
elsif
(
$type
eq
'sun4u'
) {
$machine
=
'sparcv9'
;
}
elsif
(
$type
=~ /^sun4[ce]?$/) {
$machine
=
'none'
;
}
elsif
(
$type
=~ /^i.
*pc
$/) {
$machine
=
'ix86'
;
}
elsif
((
split
' '
,
$Config
{myuname})[3] eq
'sun'
) {
$machine
=
'm86k'
;
}
elsif
(
$redo
++ == 0) {
$type
= `uname -m`;
redo
find_machine;
}
}
}
elsif
(
$os
eq
'gnu'
) {
chomp
(
$machine
= `uname -m`);
$machine
=
'ix86'
if
$machine
=~ /^i\d86-/;
}
$machine
=
'port'
if
$machine
!~ m(alpha|64) and (
$Config
{longsize} || 0) == 8;
print
(
"I detect multi-arch build; assembler not supported on such builds.\n\n"
),
$machine
=
'port'
if
$Config
{ccflags} =~ /(^|\s)-arch\s.*\S\s+-arch\s/;
if
(not
defined
$machine
and
$Config
{myuname}
=~ /\b(sun3|sparcv7|sparcv8_micro|sparcv8_super|alpha|hppa|[ix]\d86)\b/) {
$machine
= $1;
}
elsif
(not
defined
$machine
) {
chomp
(
$machine
= `uname -m`);
}
$machine
=~ s/[ix]\d86(-\w+)?/ix86/
if
defined
$machine
;
print
"...Processor of family `$machine' detected\n"
;
return
$machine
;
}
sub
not_gnu_as {
local
$/;
my
$ass
=
$ENV
{AS} ||
'as'
;
my
$devnul
= -e
'/dev/null'
?
'< /dev/null'
:
''
;
open
ASS,
"$ass --version 2>&1 $devnul |"
;
my
$assout
;
eval
{
local
$SIG
{ALRM} =
sub
{
die
};
eval
{
alarm
10};
$assout
= <ASS>;
close
ASS;
unless
(
$assout
) {
eval
{
alarm
10};
open
ASS,
"$ass -v 2>&1 $devnul |"
;
$assout
= <ASS>;
close
ASS;
}
eval
{
alarm
0};
};
(
$assout
and
$assout
=~ /GNU/) and
return
;
$assout
or 1;
}
sub
sparcv8_inl {
my
(
$asmarch
,
$pari_version
) = (
shift
,
shift
);
return
[
'none/asm0.h'
,
'none/level1.h'
]
if
$Config
{osname} =~ /^(linux|nextstep)$/;
return
[
'sparcv8/level0.h'
,
'none/level1.h'
]
if
$pari_version
< 2002006;
return
[
'sparcv8_micro/level0_common.h'
,
'sparcv8_micro/level0.h'
,
'none/level1.h'
]
if
$asmarch
eq
'sparcv8_micro'
;
return
[
'sparcv8_micro/level0_common.h'
,
'none/divll.h'
,
'none/level1.h'
]
if
$asmarch
eq
'sparcv8_super'
;
}
sub
inline_headers_arr {
my
(
$asmarch
,
$pari_version
) = (
shift
,
shift
);
return
sparcv8_inl(
$asmarch
,
$pari_version
)
if
$asmarch
=~ /^sparcv8/;
my
%h
= (
alpha
=> [
'none/asm0.h'
,
'none/level1.h'
],
hppa
=> [
'none/asm0.h'
,
'none/level1.h'
],
ix86
=> [
'ix86/level0.h'
,
'none/level1.h'
],
m86k
=> [
'none/level0.h'
,
'none/level1.h'
],
none
=> [
'none/level0.h'
,
'none/level1.h'
],
(
$pari_version
> 2002007
? (
ppc
=> [
'ppc/asm0.h'
,
'none/divll.h'
],
x86_64
=> [
'x86_64/asm0.h'
,
'none/level1.h'
],
ia64
=> [
'ia64/asm0.h'
,
'ia64/asm1.h'
])
: ()),
sparcv7
=> [
'none/asm0.h'
,
'none/level1.h'
],
);
$h
{
$asmarch
};
}
sub
inline_headers {
my
(
$asmarch
,
$pari_version
) = (
shift
,
shift
);
my
$inlines
= inline_headers_arr(
$asmarch
,
$pari_version
)
or
die
"Unknown inlines for '$asmarch'"
;
my
@inlines
=
@$inlines
;
if
(
$pari_version
< 2003000) {
unshift
@inlines
,
'none/int.h'
if
$pari_version
>= 2002005;
unshift
@inlines
,
'none/tune.h'
if
$pari_version
>= 2002008;
}
map
"\$(PARI_DIR)/src/kernel/$_"
,
@inlines
;
}
sub
generic_build_method {
my
(
$asmarch
,
$pari_version
,
$paridir
) = (
shift
,
shift
,
shift
);
$pari_version
>= 2003000
and (not -f
"$paridir/src/kernel/$asmarch/MakeLVL1.SH"
or
$asmarch
eq
'none'
);
}
sub
inline_headers_by_file {
my
(
$dir
,
$f
) = (
shift
,
shift
);
die
"I expect to have $f present"
unless
-f
$f
;
open
F,
"< $f"
or
die
"Error opening `$f' for read: $!"
;
my
@I
= ([], [
$f
]);
while
(<F>) {
next
unless
/^(NO)?ASM\s+(\S.*?)\s*$/;
my
$arr
=
$I
[ $1 ? 1 : 0 ];
push
@$arr
,
map
"$dir/none/$_.h"
,
split
' '
, $2;
}
close
F or
die
"Error closing `$f' for read: $!"
;
return
@I
;
}
sub
inline_headers_by_dir {
my
(
$asmarch
,
$pari_version
,
$paridir
) = (
shift
,
shift
,
shift
);
my
$dir
=
"$paridir/src/kernel"
;
unless
(generic_build_method(
$asmarch
,
$pari_version
,
$paridir
)) {
}
my
@I
= ([],[]);
@I
= inline_headers_by_file
$dir
,
"$dir/sparcv8_micro/asm0-common.h"
if
$asmarch
=~ /^sparcv8_/;
my
@I1
= inline_headers_by_file
$dir
,
"$dir/$asmarch/asm0.h"
;
for
(0,1) {
push
@{
$I
[
$_
]}, @{
$I1
[
$_
]};
}
push
@{
$I
[1]},
map
"$dir/none/$_.h"
,
qw(tune int level1)
;
return
@I
;
}
sub
inline_headers_pre {
my
(
$asmarch
,
$pari_version
,
$paridir
) = (
shift
,
shift
,
shift
);
return
if
$pari_version
< 2003000;
my
$script
=
"$paridir/src/kernel/$asmarch/"
;
return
;
}
sub
inline_headers2 {
my
(
$asmarch
,
$pari_version
,
$paridir
) = (
@_
);
return
([inline_headers_pre(
@_
)], [inline_headers(
@_
)])
if
$pari_version
< 2003000;
return
inline_headers_by_dir(
@_
);
}
sub
known_asmarch {
defined
inline_headers_arr(
@_
);
}
sub
choose_and_report_assembler {
my
(
$machine
,
$pari_version
) = (
shift
,
shift
);
my
%asmarch
= (
sun3
=>
'm86k'
,
sparc
=>
'sparcv8_micro'
,
sparcv9
=>
'sparcv8_micro'
,
port
=>
'none'
,
mips
=>
'none'
,
fx2800
=>
'none'
,
ia64
=> ((
$Config
{longsize}||4) == 8 ?
'ia64'
:
'none'
),
hppa
=> (
$Config
{osvers} =~ /^.\.10\./
?
'hppa'
:
'none'
),
);
my
$asmarch
=
$asmarch
{
$machine
} ||
$machine
;
my
%skip64
= (
alpha
=> 1,
none
=> 1);
if
(not (
$skip64
{
$asmarch
} or
$asmarch
=~ /\D64$/ )
and (
$Config
{longsize} || 0) == 8) {
$asmarch
.=
'_64'
;
$asmarch
=
'hppa64'
if
$asmarch
eq
'hppa_64'
;
$asmarch
=
'x86_64'
if
$asmarch
eq
'ix86_64'
;
}
unless
(known_asmarch
$asmarch
,
$pari_version
) {
warn
<<EOW;
#### Do not know how to build for assembler `$asmarch'. ####
#### Reversing to assembler-less type `port'. ####
#### ####
#### If you think your processor's assembler is supported ####
#### by PARI, edit libPARI/Makefile.PL and report. ####
#### ####
#### Alternatively, specify machine=YOURTYPE or machine=none ####
#### on the ####
#### perl Makefile.PL ####
#### command line. ####
#### Recognized types: ####
#### alpha hppa m86k none sparcv7 sparcv8 sparcv8_micro ####
#### sparcv8_super ix86 (ppc ia64 after 2.2.7) ####
EOW
$machine
=
'port'
;
$asmarch
=
'none'
;
}
if
(
$asmarch
eq
'none'
) {
print
"...I will use portable assembler-less build\n"
;
}
else
{
print
"...I will use assembler build of type '$asmarch'.\n"
;
}
print
<<EOP if $asmarch =~ /^hppa/;
###
### Some time ago HPPA assembler files were not relocatable,
### if this is still true, they are probably unsuitable for dynamic linking.
### It is advisable to restart Makefile.PL with an extra argument
### machine=port
### if you are planning for dynamic linking of Math::Pari.
###
### NOTE: machine=port results in a significant drop in performance.
### For a static build (which makes a new perl executable with the library
### compiled in [and arranges for it to be compiled in when
### other extensions are statically built later]):
### perl Makefile.PL LINKTYPE=static
### make static
### make perl
### make test
### make install
###
EOP
return
$asmarch
;
}
sub
sparcv8_kernel_files_old {
my
(
$asmarch
,
$pari_version
,
$Using_gnu_as
) = (
shift
,
shift
,
shift
);
my
$_ext
= ((
$pari_version
< 2000015) ?
's'
:
'S'
);
my
$cvt
=
$Using_gnu_as
||
$Config
{osname} =~ /^(linux|nextstep)$/;
my
$sparcv8_kernel
= (
$cvt
? [
"sparcv8/level0.$_ext"
, 1,
"sparcv8/level0_$asmarch.$_ext"
, 1]
: [
"sparcv8/level0.$_ext"
, 0,
"sparcv8/level0_$asmarch.$_ext"
, 0]);
my
$sparcv8_need_kernel2
=
!
$Config
{gccversion} ||
$Config
{osname} =~ /^(linux|nextstep)$/;
$sparcv8_kernel
= [
$sparcv8_kernel
->[2],
$sparcv8_kernel
->[3]]
unless
$sparcv8_need_kernel2
;
return
$sparcv8_kernel
;
}
sub
sparcv7_kernel_files {
my
(
$asmarch
,
$pari_version
,
$Using_gnu_as
) = (
shift
,
shift
,
shift
);
my
$_ext
= ((
$pari_version
< 2000015) ?
's'
:
'S'
);
my
$cvt
=
$Using_gnu_as
||
$Config
{osname} =~ /^(linux|nextstep|netbsd)$/;
return
[
"sparcv7/level0.$_ext"
,
$cvt
];
}
sub
kernel_files {
my
(
$asmarch
,
$pari_version
,
$Using_gnu_as
,
$paridir
) = (
@_
);
return
[]
if
$pari_version
>= 2003000;
return
sparcv8_kernel_files_old(
$asmarch
,
$pari_version
,
$Using_gnu_as
)
if
$asmarch
=~ /^sparcv8/ and
$pari_version
< 2002006;
return
sparcv7_kernel_files(
$asmarch
,
$pari_version
,
$Using_gnu_as
)
if
$asmarch
eq
'sparcv7'
;
my
$sparcv8_kernel
= [
"sparcv8_micro/level0_common.S"
, 1,
"$asmarch/level0.S"
, 1];
my
%level0
= (
alpha
=>
''
,
hppa
=>
''
,
(
$pari_version
> 2002007
? (
ppc
=> [
"none/level0.c"
, 0],
ia64
=> [
"ia64/level0.s"
, 0])
: ()),
ix86
=> [
'ix86/l0asm.c'
, 1],
m86k
=> [
"none/level0.c"
, 0],
none
=> [
"none/level0.c"
, 0],
sun3
=>
''
,
sparcv8_micro
=>
$sparcv8_kernel
,
sparcv8_super
=>
$sparcv8_kernel
,
);
return
$level0
{
$asmarch
} || [
"$asmarch/level0.s"
, 0];
}
sub
kernel_fill_data {
my
(
$kernels
,
$hash
) = (
shift
,
shift
);
return
unless
@$kernels
;
$hash
->{file1} =
"\$(PARI_DIR)/src/kernel/$kernels->[0]"
;
$hash
->{convert1} =
$kernels
->[1];
$hash
->{converted1} =
$hash
->{convert1} ?
'kernel1.s'
:
$hash
->{file1};
(
$hash
->{header1} =
$hash
->{file1}) =~ s/\.c$/.h/;
$hash
->{header1} =
''
unless
-r
$hash
->{header1};
(
$hash
->{dir1} =
$hash
->{file1}) =~ s/[^\/]*\.[csS]$//;
$hash
->{file2} =
$hash
->{converted2} =
"\$(PARI_DIR)/src/kernel/$kernels->[2]"
if
$kernels
->[2];
$hash
->{file2} =
$hash
->{converted2} =
''
unless
$kernels
->[2];
$hash
->{converted2} =
'kernel2.s'
if
$kernels
->[3];
$hash
->{convert} = (
$hash
->{converted2} eq
'kernel2.s'
or
$hash
->{converted1} eq
'kernel1.s'
);
if
( $^O =~ /win32/i
and
$Config
{cc} =~ /\bcl/
and
$hash
->{converted1} eq
'kernel1.s'
) {
$hash
->{converted1} =
'kernel1.c'
;
}
}
sub
assembler_flags_via {
my
(
$machine
,
$not_gnu_as
) = (
shift
,
shift
);
my
%assf
= (
sparc
=> (
$Config
{osname} eq
'solaris'
?
"-P -T -I."
:
"-P -I."
),
hppa
=>
"+DA1.1"
,
);
my
$assflags
=
$assf
{
$machine
=~ /sun3|sparc/ ?
'sparc'
:
$machine
} ||
''
;
$assflags
.=
' -D__GNUC__'
if
$not_gnu_as
and
$Config
{gccversion};
$assflags
.=
' -K PIC'
if
0 and
$not_gnu_as
and
$Config
{cccdlflags} =~ /(^|\s)-K\s*(pic|PIC)\b/
and
$not_gnu_as
=~ /(^|\W)-K\s+\{?(\w+,)PIC\b/;
return
$assflags
;
}
sub
assembler_flags {
my
(
$machine
,
$is_gnu_as
) = (
shift
,
shift
);
assembler_flags_via(
$machine
, not
$is_gnu_as
);
}
sub
extra_includes {
my
$pari_dir
=
shift
;
return
join
' -I '
,
''
,
grep
-d,
"$pari_dir/src/systems/$^O"
,
"$pari_dir/src"
;
}
sub
build_funclists_ourselves ($) {
my
$pari_dir
=
shift
;
chdir
"$pari_dir/src/desc"
or
die
"Can't chdir to `$pari_dir/src/desc'"
;
unless
(-f
'pari.desc'
) {
my
$t
=
'tmp-pari.desc'
;
system
"$^X merge_822 ../functions/*/* > $t"
and
die
"Can't run `$^X merge_822 ../functions/*/* > $t'"
;
rename
$t
,
'pari.desc'
or
die
"rename failed: $t => 'pari.desc'"
;
}
my
%recipies
;
if
(-f
'gen_help'
) {
%recipies
= (
'language/members.h'
=> [[
qw(gen_member)
]],
'language/init.h'
=> [[
qw(gen_proto basic)
],
[
qw(gen_help basic)
]],
'gp/highlvl.h'
=> [[
qw(gen_proto highlevel)
],
[
qw(gen_help highlevel)
]],
'gp/gp_init.h'
=> [[
qw(gen_proto gp)
],
[
qw(gen_help gp)
]],
);
}
else
{
%recipies
= (
'language/members.h'
=> [[
qw(gen_member)
]],
'language/init.h'
=> [[
qw(gen_proto basic)
]],
'gp/highlvl.h'
=> [[
qw(gen_proto highlevel)
]],
'gp/gp_init.h'
=> [[
qw(gen_proto gp)
]],
);
}
for
my
$outfile
(
keys
%recipies
) {
next
if
-r
"../$outfile"
;
my
$append
=
'>'
;
for
my
$step
(@{
$recipies
{
$outfile
}}) {
system
"$^X @$step pari.desc $append ../$outfile-tmp"
and
die
"Can't run `$^X @$step pari.desc $append ../$outfile-tmp'"
;
$append
=
'>>'
;
}
rename
"../$outfile-tmp"
,
"../$outfile"
or
die
"rename failed: ../$outfile-tmp => ../$outfile"
;
}
1;
}
sub
build_funclists {
my
$pari_dir
=
shift
;
return
unless
-d
"$pari_dir/src/desc"
;
return
if
-f
"$pari_dir/src/language/init.h"
and -f
"$pari_dir/src/desc/pari.desc"
;
if
(-f
"$pari_dir/src/desc/Makefile"
) {
open
FL,
"> $pari_dir/src/funclist"
and
close
FL
unless
-f
"$pari_dir/src/funclist"
;
(
system
(
"cd $pari_dir/src/desc && make"
)
and
system
(
"cd $pari_dir/src/desc && make SHELL=cmd"
)
or not -s
"$pari_dir/src/desc/pari.desc"
) and
(
unlink
(
"$pari_dir/src/desc/pari.desc"
),
die
<<EOW);
###
### Apparently, we failed to build function descriptions of GP/PARI.
### Try editing $pari_dir/src/desc/Makefile - a typical reason
### is a wrong value of SHELL for your system. You can run make in
### $pari_dir/src/desc manually too...
EOW
}
else
{
my
$cwd
= Cwd::cwd();
my
$res
=
eval
{ build_funclists_ourselves
$pari_dir
};
chdir
$cwd
;
die
<<EOD unless $res;
$@
###
### We do not know how to build function descriptions of GP/PARI.
### Please build them manually (e.g., by building GP/PARI).
###
EOD
}
}
sub
ep_codes_from_file ($\%\%) {
my
(
$file
,
$descrh
,
$names
) = (
shift
,
shift
,
shift
);
local
$_
;
open
IN,
"< $file"
or
warn
"Cannot open `$file': $!"
and
return
;
while
(<IN>) {
next
unless
/^\s*{\s*\"/;
chomp
;
warn
(
"Unrecognized line: `$_'\n"
),
next
unless
/^\s*\{\s*
"(\w+)"
\s*,\s*(\d+)\s*,[^,]*,\s*\d+\s*,(?:\s*\d+\s*,)?\s*(
"((?:\\.|[^"
])*)"|NULL)\s*(,|\})/;
next
unless
defined
$4;
my
(
$name
,
$code
,
$descr
) = ($1, $2, $4);
$descrh
->{
$code
} = []
unless
exists
$descrh
->{
$code
};
push
@{
$descrh
->{
$code
}},
$descr
unless
grep
$descr
eq
$_
, @{
$descrh
->{
$code
}};
warn
"! Duplicate code $code for function '$name' (was $names->{$name})\n"
if
defined
$names
->{
$name
};
$names
->{
$name
} = [
$code
,
$descr
];
}
close
IN or
warn
"Cannot close `$file': $!"
;
}
my
$expected_codes_as_in
=
'2.1.3'
;
my
(
$dummy1
,
%old_expected_codes
) =
split
/\s+/,
qq(
13 GD0,L,D0,G,
34 vLLL
)
;
my
(
$dummy2
,
%expected_codes
) =
split
/\s+/,
qq(
1 Gp
2 GG
3 GGG
4 GGGG
10 lG
11 L
12 GnP
14 GDn
16 ls
18 G
19 vLL
20 lGG
21 GL
22 GVI
23 GL
24 LG
25 GGD0,L,
26 GnG
27 V=GIp
28 GDVDI
29 GGp
30 lGGG
31 GDGDGD&
32 GGL
33 GGGD0,L,p
35 vLGG
37 V=GGIp
45 LGD0,L,
47 V=GGIDG
48 V=GGIDG
49 GGDVDVDI
57 vLs
59 vLGGGG
62 GD0,G,D0,G,D0,L,p
73 LV=GGIpD0,L,D0,L,
83 vV=GGI
84 vGVI
85 vS
86 vV=GGGI
87 vV=GID0,L,
91 GD0,L,DGp
96 GD0,L,DGp
)
;
my
$t
;
my
%variations
=
map
{(
$t
=
$expected_codes
{
$_
}) =~ s/I/E/ ? (
$_
,
$t
) : ()}
keys
%expected_codes
;
my
%known_unimplemented
= (
57
=> 1,
62
=> 1);
sub
ep_hash_report (\%;\%$) {
my
(
$h
,
$names
,
$fh
) = (
shift
,
shift
,
shift
);
my
(
$c
,
@list
);
$names
= {}
unless
defined
$names
;
my
@keys
=
grep
{
$_
ne 0 and
$_
ne 99}
keys
%$h
;
if
(
@list
=
grep
{not
exists
$h
->{
$_
}}
keys
%expected_codes
) {
return
unless
$fh
;
print
$fh
<<EOP;
Cosmetic only: the following numeric interfaces are not used any more:
EOP
for
$c
(
sort
@list
) {
print
$fh
<<EOP;
$c (was meaning "$expected_codes{$c}" in $expected_codes_as_in)
EOP
}
}
if
(
@list
=
grep
{not
exists
$expected_codes
{
$_
}}
@keys
) {
return
unless
$fh
;
print
$fh
<<EOP;
Harmless: the following numeric interfaces are new:
EOP
for
$c
(
sort
@list
) {
print
$fh
<<EOP;
$c meaning "@{$h->{$c}}"
EOP
my
$list
=
join
", "
,
grep
$names
->{
$_
}[0] ==
$c
,
sort
keys
%$names
;
print
$fh
<<EOP;
(appears for $list)
EOP
}
}
if
(
@list
=
grep
@{
$h
->{
$_
}} != 1,
@keys
) {
return
unless
$fh
;
print
$fh
<<EOP;
May be harmless: non-unique string interfaces for numeric interfaces:
EOP
for
$c
(
sort
@list
) {
print
$fh
<<EOP;
$c meaning "@{$h->{$c}}"
EOP
my
$list
=
join
", "
,
grep
$names
->{
$_
}[0] ==
$c
,
sort
keys
%$names
;
print
$fh
<<EOP;
(appears for $list)
EOP
}
}
if
(
@list
=
grep
{
exists
$expected_codes
{
$_
}
and
"@{$h->{$_}}"
ne
$expected_codes
{
$_
}
and
"@{$h->{$_}}"
ne
$variations
{
$_
}
and not
$known_unimplemented
{
$_
}}
@keys
) {
return
unless
$fh
;
print
$fh
<<EOP;
Possible problems with Math::Pari interface to GP/PARI:
unexpected value of string interfaces for numeric interfaces:
EOP
for
$c
(
sort
@list
) {
print
$fh
<<EOP;
$c meaning "@{$h->{$c}}" (was meaning "$expected_codes{$c}" in $expected_codes_as_in)
EOP
my
$list
=
join
", "
,
grep
{
$names
->{
$_
}[0] ==
$c
and
$names
->{
$_
}[1] ne
$expected_codes
{
$c
}}
sort
keys
%$names
;
print
$fh
<<EOP;
(may affect functions $list)
EOP
}
}
return
1;
}
sub
ep_in_version ($) {
my
$v
=
shift
;
if
(
$v
>= 2002002) {
my
$c
;
for
$c
(
qw(26 62)
) {
delete
$expected_codes
{
$c
};
}
}
}
sub
code_C_translator {
my
%c
= (
%old_expected_codes
,
%expected_codes
);
my
%codes
;
@codes
{
values
%c
} =
keys
%c
;
my
$k
;
for
$k
(
keys
%codes
) {
(
my
$kk
=
$k
) =~ s/I/E/g;
$codes
{
$kk
} =
$codes
{
$k
}
unless
exists
$codes
{
$kk
};
(
$kk
=
$k
) =~ s/D0,G,/DG/g;
$codes
{
$kk
} =
$codes
{
$k
}
unless
exists
$codes
{
$kk
};
}
$codes
{
'p'
} = 0;
my
@t
= ExtUtils::Constant::constant_types();
my
@tt
=
ExtUtils::Constant::C_constant(
'Math::Pari::func_type'
,
'func_ord_by_type'
,
undef
,
undef
,
undef
,
undef
,
map
{{
name
=>
$_
,
value
=>
$codes
{
$_
},
macro
=> 1}}
keys
%codes
);
join
''
,
@t
,
@tt
;
}
1;