# This is a perl script, invoked from a shell

# use warnings;  # this doesn't work on older versions of perl



%MakeFlag = (

'WIZARD'  => 'on',
'SHARED'  => 'off',
'NATIVE'  => 'on'

);

%MakeVal = (

'CXX'	      => 'g++',
'CXXFLAGS'    => '-g -O2',
'CXXAUTOFLAGS'=> '',
'AR'	      => 'ar',
'ARFLAGS'     => 'ruv',
'RANLIB'      => 'ranlib',
'LIBTOOL'     => 'libtool',

'LDFLAGS'     => '',
'LDLIBS'      => '-lm',
'CPPFLAGS'    => '',

'DEF_PREFIX'  => '/usr/local',

'PREFIX'      => '$(DEF_PREFIX)',
'LIBDIR'      => '$(PREFIX)/lib',
'INCLUDEDIR'  => '$(PREFIX)/include',
'DOCDIR'      => '$(PREFIX)/share/doc',

'GMP_PREFIX'  => '$(DEF_PREFIX)',
'GMP_INCDIR'  => '$(GMP_PREFIX)/include',
'GMP_LIBDIR'  => '$(GMP_PREFIX)/lib',

'GF2X_PREFIX'  => '$(DEF_PREFIX)',
'GF2X_INCDIR'  => '$(GF2X_PREFIX)/include',
'GF2X_LIBDIR'  => '$(GF2X_PREFIX)/lib',

);




%ConfigFlag = (

'NTL_LEGACY_NO_NAMESPACE' => 'off',
'NTL_LEGACY_INPUT_ERROR'  => 'off',
'NTL_DISABLE_LONGDOUBLE'  => 'off',
'NTL_DISABLE_LONGLONG'    => 'off',
'NTL_DISABLE_LL_ASM'      => 'off',
'NTL_MAXIMIZE_SP_NBITS'   => 'off',
'NTL_LEGACY_SP_MULMOD'    => 'off',
'NTL_THREADS'             => 'off',
'NTL_DISABLE_TLS_HACK'    => 'off',
'NTL_ENABLE_TLS_HACK'     => 'off',
'NTL_EXCEPTIONS'          => 'off',
'NTL_THREAD_BOOST'        => 'off',
'NTL_GMP_LIP'             => 'on',
'NTL_GF2X_LIB'            => 'off',
'NTL_X86_FIX'             => 'off',
'NTL_NO_X86_FIX'          => 'off',
'NTL_AVOID_FLOAT'         => 'off',
'NTL_LONG_LONG'           => 'off',
'NTL_SPMM_ULL'            => 'off',
'NTL_SPMM_ASM'            => 'off',
'NTL_AVOID_BRANCHING'     => 'off',
'NTL_TBL_REM'             => 'off',
'NTL_TBL_REM_LL'          => 'off',
'NTL_CRT_ALTCODE'         => 'off',
'NTL_CRT_ALTCODE_SMALL'   => 'off',
'NTL_GF2X_NOINLINE'       => 'off',
'NTL_GF2X_ALTCODE'        => 'off',
'NTL_GF2X_ALTCODE1'       => 'off',
'NTL_PCLMUL'              => 'off',
'NTL_NO_INIT_TRANS'       => 'off',
'NTL_CLEAN_INT'           => 'off',
'NTL_CLEAN_PTR'           => 'off',
'NTL_RANGE_CHECK'         => 'off',
'NTL_FFT_BIGTAB'          => 'off',
'NTL_FFT_LAZYMUL'         => 'off',

);


%ConfigVal = (

'NTL_LONG_LONG_TYPE' => undef,
'NTL_UNSIGNED_LONG_LONG_TYPE' => undef,

);


%Variable = ();

$nowrite = 0;

foreach $arg (@ARGV) {

   if ($arg =~ '^(-h|help|-help|--help)$') {
      system("more ../doc/config.txt");
      exit 0;
   }

   if ($arg =~ '^--nowrite$') {
      $nowrite = 1;
      next;
   }


   if (($name, $val) = ($arg =~ /(.*?)=(.*)/)) {

      $Variable{$name} = 0;
      
      if (exists($MakeFlag{$name}) && ($val =~ 'on|off')) {
         $MakeFlag{$name} = $val;
         next;
      }
      elsif (exists($MakeVal{$name})) {
         $MakeVal{$name} = $val;
         next;
      }
      elsif (exists($ConfigFlag{$name}) && ($val =~ 'on|off')) {
         $ConfigFlag{$name} = $val;
         next;
      }
      elsif (exists($ConfigVal{$name})) {
         $ConfigVal{$name} = $val;
         next;
      }
   }

   die "Error: unrecognized option: $arg\ntype \"./configure -h\" for help\n";

}

# special processing: NTL_THREAD_BOOST => NTL_THREADS

if ($ConfigFlag{'NTL_THREAD_BOOST'} eq 'on') {
   $ConfigFlag{'NTL_THREADS'} = 'on';
}

if ($ConfigFlag{'NTL_THREADS'} eq 'on' && $ConfigFlag{'NTL_GMP_LIP'} eq 'off') {
   die "Error: NTL_THREADS currently only available with NTL_GMP_LIP...sorry\n";
}



# some special MakeVal values that are determined by SHARED

if ($MakeFlag{'SHARED'} eq 'off') {

   $MakeVal{'LSTAT'} = '';
   $MakeVal{'LSHAR'} = '# ';

} else {

   # sanity check for libtool

   print("***** checking for libtool *****\n");
   if (system("$MakeVal{'LIBTOOL'} --version")) {
      die "Error: bad libtool ($MakeVal{'LIBTOOL'}) -- try glibtool?";
   }
   print("***** libtool OK *****\n\n");

   $MakeVal{'LSTAT'} = '# ';
   $MakeVal{'LSHAR'} = '';

}

# special GMP variables

$MakeVal{'GMPI'} = '# ';
$MakeVal{'GMPL'} = '# ';
$MakeVal{'GMP'} =  '# ';

if ($ConfigFlag{'NTL_GMP_LIP'} eq 'on') {
   $MakeVal{'GMP'} = '';
   if (exists($Variable{'DEF_PREFIX'}) ||
       exists($Variable{'GMP_PREFIX'}) ||
       exists($Variable{'GMP_INCDIR'})) {
      $MakeVal{'GMPI'} = '';
   }
   if (exists($Variable{'DEF_PREFIX'}) ||
       exists($Variable{'GMP_PREFIX'}) ||
       exists($Variable{'GMP_LIBDIR'})) {
      $MakeVal{'GMPL'} = '';
   }
}

# special GF2X variables


$MakeVal{'GF2XI'} = '# ';
$MakeVal{'GF2XL'} = '# ';
$MakeVal{'GF2X'} =  '# ';


if ($ConfigFlag{'NTL_GF2X_LIB'} eq 'on') {
   $MakeVal{'GF2X'} = '';
   if (exists($Variable{'DEF_PREFIX'}) ||
       exists($Variable{'GF2X_PREFIX'}) ||
       exists($Variable{'GF2X_INCDIR'})) {
      $MakeVal{'GF2XI'} = '';
   }
   if (exists($Variable{'DEF_PREFIX'}) ||
       exists($Variable{'GF2X_PREFIX'}) ||
       exists($Variable{'GF2X_LIBDIR'})) {
      $MakeVal{'GF2XL'} = '';
   }
}


# copy %MakeVal and %MakeFlag as is into %MakeSub

%MakeSub = (%MakeVal, %MakeFlag);


# copy %ConfigFlag into %ConfigSub, substituting 0 for off and 1 of on


%ConfigSub = ( );

foreach $name (keys %ConfigFlag) {

   if ($ConfigFlag{$name} eq 'on') {
      $ConfigSub{$name} = 1;
   }
   else {
      $ConfigSub{$name} = 0;
   }

}

# special logic for NTL_LONG_LONG_TYPE

if (defined($ConfigVal{'NTL_LONG_LONG_TYPE'})) {

   $ConfigSub{'NTL_LONG_LONG_TYPE'} = $ConfigVal{'NTL_LONG_LONG_TYPE'};
   $ConfigSub{'FLAG_LONG_LONG_TYPE'} = 1;

}
else {
   
   $ConfigSub{'NTL_LONG_LONG_TYPE'} = 'long long';
   $ConfigSub{'FLAG_LONG_LONG_TYPE'} = 0;

}


# special logic for NTL_UNSIGNED_LONG_LONG_TYPE

if (defined($ConfigVal{'NTL_UNSIGNED_LONG_LONG_TYPE'})) {

   $ConfigSub{'NTL_UNSIGNED_LONG_LONG_TYPE'} = $ConfigVal{'NTL_UNSIGNED_LONG_LONG_TYPE'};
   $ConfigSub{'FLAG_UNSIGNED_LONG_LONG_TYPE'} = 1;

}
else {
   
   $ConfigSub{'NTL_UNSIGNED_LONG_LONG_TYPE'} = 'unsigned long long';
   $ConfigSub{'FLAG_UNSIGNED_LONG_LONG_TYPE'} = 0;

}

# special logic for WIZARD_HACK

$ConfigSub{'WIZARD_HACK'} = '';


# some extra logic consistency checks

if ($ConfigSub{'NTL_X86_FIX'} + $ConfigSub{'NTL_NO_X86_FIX'} > 1) {

   die "Error: at most one of NTL_X86_FIX and NTL_NO_X86_FIX may be on\n";

}


if ($ConfigSub{'NTL_AVOID_FLOAT'} + $ConfigSub{'NTL_LONG_LONG'} > 1) {

   die "Error: at most one of NTL_AVOID_FLOAT and NTL_LONG_LONG may be on\n";

}


if ($ConfigSub{'NTL_SPMM_ULL'} + $ConfigSub{'NTL_SPMM_ASM'} > 1) {

   die "Error: at most one of NTL_SPMM_ULL and NTL_SPMM_ASM may be on\n";

}


if ($ConfigSub{'NTL_GF2X_ALTCODE'} + $ConfigSub{'NTL_GF2X_ALTCODE1'} > 1) {

   die "Error: at most one of NTL_GF2X_ALTCODE and NTL_GF2X_ALTCODE1 may be on\n";

}




#
#
#code to set CXXAUTOFLAGS

sub RemoveProg {
# This should work on unix and cygwin on windows

   my ($name) = @_;
   unlink($name);  unlink("$name.exe");
   return 1;
}

sub GenFiles {

   open(MFILE, "< mfile");
   open(MFILEOUT, "> mfileout");
   
   while ($line = <MFILE>) {
   
      $line =~ s/@\{(.*?)\}/$MakeSub{$1}/ge;
   
      print MFILEOUT $line;
   
   }
   
   close(MFILE);
   close(MFILEOUT);
   
   
   # generate config.h
   
   
   open(CFILE, "< cfile");
   open(CFILEOUT, "> cfileout");
   
   while ($line = <CFILE>) {
   
      $line =~ s/@\{(.*?)\}/$ConfigSub{$1}/ge;
   
      print CFILEOUT $line;
   
   }

   close(CFILE);
   close(CFILEOUT);

   open(HFILEOUT, "> hfileout");
   $argstr = join(' ', @ARGV);
   print HFILEOUT "// generated by ./configure $argstr\n"; 
   print HFILEOUT "// CXXAUTOFLAGS=\"$MakeSub{'CXXAUTOFLAGS'}\" \n";
   close(HFILEOUT);
   
   
   return 1;
}

sub CopyFiles {

   system("cp mfileout makefile");
   system("cp cfileout ../include/NTL/config.h");
   system("cp hfileout ../include/NTL/config_log.h");

   return 1;
}

sub CheckCompile {
   GenFiles();
   CopyFiles();
   RemoveProg("CheckCompile");
   system("make CheckCompile >> CheckFlag.log 2>&1") and return 0;
   system("./CheckCompile") and RemoveProg("CheckCompile") and return 0;
   RemoveProg("CheckCompile");
   return 1;
}

sub CheckFlag {
   my ($flag) = @_;
   my $try_flags = $MakeSub{'CXXAUTOFLAGS'};
   print "*** checking $flag flag\n";
   $MakeSub{'CXXAUTOFLAGS'} = $MakeSub{'CXXAUTOFLAGS'} . ' ' . $flag;
   print("CXXAUTOFLAGS=\"$MakeSub{'CXXAUTOFLAGS'}\"\n");
   if (CheckCompile()) {
      print "*** $flag works\n";
   }
   else {
      $MakeSub{'CXXAUTOFLAGS'} = $try_flags;
      print "*** $flag does not work\n";
   }
   return 1;
}



if ($nowrite) {
   GenFiles();
   exit 0;
}


if (exists($Variable{'CXXAUTOFLAGS'})) {
   print("CXXAUTOFLAGS=\"$MakeSub{'CXXAUTOFLAGS'}\"\n");
   GenFiles();
   CopyFiles();
   exit 0;
}

$std_flag = 0;
$pthread_flag = 0;
$native_flag = 0;

# special processing for NTL_THREADS

if ($ConfigFlag{'NTL_THREADS'} eq 'on') {
   $std_flag = 1; # ' -std=c++11';
   $pthread_flag = 1; # ' -pthread';
}

# special processing for NTL_EXCEPTIONS

if ($ConfigFlag{'NTL_EXCEPTIONS'} eq 'on') {
   $std_flag = 1; # ' -std=c++11';
}

# special processing for NATIVE

if ($MakeFlag{'NATIVE'} eq 'on') {
    $native_flag = 1; # ' -march=native';
}


system("echo '*** CheckFlag log ***' > CheckFlag.log");

if ($std_flag) {
   CheckFlag('-std=c++11');
}

if ($pthread_flag) {
   CheckFlag('-pthread');
}
   
if ($native_flag) {
   CheckFlag('-march=native');
}

print("CXXAUTOFLAGS=\"$MakeSub{'CXXAUTOFLAGS'}\"\n");
print("generating makefile\n");
print("generating ../include/NTL/config.h\n");
print("generating ../include/NTL/config_log.h\n");

GenFiles();
CopyFiles();
exit 0;



