#  Copyright (c) 1997-2006
#  Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Berlin, Germany)
#  http://www.math.tu-berlin.de/polymake,  mailto:polymake@math.tu-berlin.de
#
#  This program is free software; you can redistribute it and/or modify it
#  under the terms of the GNU General Public License as published by the
#  Free Software Foundation; either version 2, or (at your option) any
#  later version: http://www.gnu.org/licenses/gpl.txt.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#-----------------------------------------------------------------------------
# $Project: polymake $$Id: configure.pl,v 1.137.2.4 2006/03/15 07:22:04 gawrilow Exp $

BEGIN {
   if ($] < 5.008) {
      print STDERR <<".";
polymake requires perl version not lower than 5.8;
your perl interpreter says it is $].

Please upgrade your perl installation;
if you already have an up-to-date perl interpreter somewhere else,
you can specify its location on the command line:

make configure PERL=/path/to/my/new/perl
.
      exit(1);
   }
}

use strict 'vars', 'subs';
use Config;
use Cwd;

use vars qw( @export @noexport $Cflags_ $CXXflags_ $LDflags_ $BuildDir $changed $CPUarch
	     $ProjectTop $ProjectTopLink $GCCv_min $GCCv_max
	     $GMPsourceDir $bindist $developer $silent $quick $multi $multi_build $build_arch @apps @modules
	   );
BEGIN {
   @noexport=qw( CC CXX Cflags CXXflags CXXOPT CXXDEBUG GCCversion ICCversion COMOversion ProcessDep
		 LDflags Libs Arch GMPbuildDir GMPconfEnv GMPconfOpt PerlExe );
   @export=qw( PREFIX InstallTop InstallArch InstallDoc InstallLinks );
}
use vars map { "\$$_" } @noexport, @export;

sub compile {
   open C, ">polymake_configure.cc" or die "$0: can't create a temporary file: $!\n";
   print C @_;
   close C;
   my $errors=`$CXX $CXXflags -c polymake_configure.cc 2>&1`;
   if ($COMOversion) {
      1 while $errors =~ s/\A[^"].*\n//xm;
      $errors="" unless $errors =~ /\S/;
   }
   $errors;
}

sub build {
   open C, ">polymake_configure.cc" or die "$0: can't create a temporary file: $!\n";
   print C @_;
   close C;
   my $errors=`$CXX $CXXflags -o polymake_configure polymake_configure.cc 2>&1`;
   if ($COMOversion) {
      1 while $errors =~ s/\A[^"].*\n//xm;
      $errors="" unless $errors =~ /\S/;
   }
   $errors;
}

sub build_c {
   open C, ">polymake_configure.c" or die "$0: can't create a temporary file: $!\n";
   print C @_;
   close C;
   my $errors=`$CC $Cflags -o polymake_configure polymake_configure.c $LDflags $Libs 2>&1`;
   if ($COMOversion) {
      1 while $errors =~ s/\A[^"].*\n//xm;
      $errors="" unless $errors =~ /\S/;
   }
   $errors;
}

sub answer {
   my $def= length($_[0]) ? $_[0] : "none";
   print "[$def] ";
   $_=<STDIN>;
   if (/\S/) {
      chomp;
      $_[0]= $_ eq "none" ? undef : $_;
      $changed=1;
   } else {
      $changed=0;
   }
}

sub answer_path {
   my $def= length($_[0]) ? $_[0] : "none";
   print "[$def] ";
   $_=<STDIN>;
   if (/\S/) {
      chomp;
      s/\$(\w+)/$ENV{$1}/g;
      s/~(\w+)/(getpwnam($1))[7]/eg;
      s/~/$ENV{HOME}/g;
      $_[0]=$_;
      $changed=1;
   } else {
      $changed=0;
   }
}

sub yes_not {
   my ($def)=@_;
   print $def ? "[y] " : "[n] ";
   while (1) {
      my $answer=<STDIN>; chomp $answer;
      return 1 if $answer =~ /^\s*y(es?)?$/i;
      return 0 if $answer =~ /^\s*no?$/i;
      return $def if $answer eq "" and defined $def;
      print "please answer `yes' or `no' ";
      undef $def;
   }
}

sub read_vars($) {
   my ($file)=@_;
   open M, $file
   or die "$0: can't read configuration file $file: $!\n";
   while (<M>) {
      last if /end of configure/;
      if (/^(\w+)\s*=\s*(.*)$/ and exists $main::{$1}) {
	 $$1=$2;
      }
   }
   close M;
}

# path( default=$_ ), allow_readonly =>
sub make_dir(;$$) {
   my $dir=@_ ? $_[0] : $_;
   if (-d $dir) {
      -x _ && ($_[1] || -w _) or die "$0: directory $dir inaccessible\n";
   } else {
      mkdir $dir, 0755 or die "$0: can't create directory '$dir': $!\n";
   }
}

sub make_dir_path(@) {
   foreach (@_) {
      while (m{ (?<!^) / | $ }xg) {
	 make_dir substr($_, 0, $-[0]), $+[0]<length($_);
      }
   }
}

sub make_build_dir(@) {
   foreach my $dir (@_) {
      make_dir "$BuildDir/$dir";
      open M, ">$BuildDir/$dir/Makefile";
      my $rel_dir=$dir;
      $rel_dir =~ s:[^/]+:..:g;
      my $make= $bindist ? "bin" : "build";
      print M <<".";
BuildDir := $rel_dir
ProjectTop := \$(BuildDir)/..$ProjectTopLink
include \$(BuildDir)/conf.make
include \$(ProjectTop)/support/$make.make
.
      close M;
   }
}

sub default_archname() {
   $_= $^O =~ /aix|rs6000|ibm/i ? $Config::Config{archname} : `uname -m`;
   chomp;
   s/Power Macintosh/darwin/;
   $_
}

sub v_cmp($$) {
  eval "v$_[0] cmp v$_[1]";
}

my $TOP=$ENV{TOP};
$bindist=-f "build/.bindist";
if (-d "CVS") {
   open C, "CVS/Root";
   $ProjectTop=<C>;
   close C;
   $ProjectTop =~ s'/[^/]+$'';
   $developer= $ProjectTop =~ s/^:.*?:// ? "remote" : "local";
}
@apps=grep { !m%/CVS$% } glob "apps/*";
@modules=grep { !m%/CVS$% } glob "modules/*";

select STDERR; $|=1;

#######################################################################################
#
# Read the configuration known so far
#
if (@ARGV and $ARGV[0] eq "-quick") {
   $quick=1;
   $multi=$multi_build=0;
   shift;
}
if (@ARGV) {
   read_vars($ARGV[0]);
   $multi=$Arch ne "";
   $multi_build= $ARGV[0] =~ m|\bbuild\.([^/]+)|;
   $build_arch=$1;

} elsif ($bindist) {
   read_vars("build/.bindist");
   $multi=$multi_build=0;

} elsif (!-t STDIN) {
   $silent=$quick=1;
   read_vars("<&STDIN");
   $multi=$multi_build= $Arch ne "";

} else {
   $Arch= $ENV{Arch} || default_archname;
   if (-f "build.$Arch/conf.make") {
      read_vars("build.$Arch/conf.make");
      $multi= $InstallTop ne $InstallArch;
      $multi_build=1;

   } elsif (-f "build/conf.make") {
      read_vars("build/conf.make");
      $multi=$multi_build=0;

   } elsif (!defined($multi) and my @other=glob "build.*/conf.make") {
      $multi_build=1;
      {
	 local $Arch;
	 read_vars($other[0]);
      }
      undef $Cflags; undef $CXXflags; undef $LDflags; undef $Libs;
      if ($InstallArch ne $InstallTop) {
	 $multi=1;
	 if ($InstallArch =~ m:^$InstallTop/[^/]+$:) {
	    $InstallArch="$InstallTop/$Arch";
	    undef $InstallLinks;
	 }
      }
   }
}
$build_arch ||= $Arch;

#######################################################################################
#
# Determine the kind of installation (single-architecture or multi-architecture)
#
if (!defined $multi) {
   print "\nAre you going to install polymake on multiple hardware architectures,\n",
         "with shared architecture-independent files? ";
   $_=$Config::Config{installsitelib};
   $multi=yes_not($Config::Config{installsitearch} !~ /^$_/);
}
undef $Arch unless $multi;
   
#######################################################################################
#
# Agree upon installation location
#
$InstallTop ||= $multi ? "/usr/local/share/polymake" : "/usr/local/polymake";
if (!$silent) {
   print "\nWhere should ", ($multi ? "the architecture-independent part of " : ""), "polymake be installed? ";
   answer_path($InstallTop);
}
if (!$multi) {
   if ($silent) {
      $InstallArch ||= $InstallTop;
   } else {
      $InstallArch=$InstallTop;
   }
} else {
   $_=$InstallTop;
   $InstallArch ||= s:/local/share/:/local/lib/: ? $_ : "$InstallTop/$Arch";
   if (!$silent) {
      print "\nWhere should the components for this architecture be installed? ";
      answer_path($InstallArch);
   }
}

$InstallLinks ||= "$InstallArch/bin";
if (!$quick) {
   print "\nThe client programs and perl scripts will be scattered over several directories after the installation.\n",
         "For your convenience, an additional directory will contain symbolic links to all the executables.\n",
	 "Where should it be created? ";
   answer_path($InstallLinks);
}

$InstallDoc ||= "$InstallTop/doc";
if (!$quick) {
   print "\nWhere should the documentation be installed? ";
   answer_path($InstallDoc);
}
#######################################################################################
#
# Agree upon compiler and options
#
sub check_cxx {
   my $silent=shift;
   undef $GCCversion;  undef $ICCversion;  undef $COMOversion;
   if ($CXX =~ m/\b[ei]cp?c$/) {
      local $CXXflags="-V";
      $CXX =~ s/cc$/cpc/;
      $_=compile 'int main() { return 0; }';
      if (/Version\s+([\d.]+)/) {
	 $ICCversion=$1;
      }
   } elsif ($CXX =~ m/\bcomo$/) {
      local $CXXflags="--version";
      $_=compile 'int main() { return 0; }';
      if (/C\+\+\s+([\d.]+)/) {
	 $COMOversion=$1;
      }
   } elsif ($CXX =~ m/\b[gc]\+\+/) {
      $GCCversion=`$CXX --version`; chomp $GCCversion;
   }

   my $warn;
   if ($GCCversion) {
      if ($GCCversion =~ /\((.*)\)$ | prerelease | snapshot /mx) {
	 $warn=<<".";
*************************************************************
*********               WARNING:                    *********

Your C++ compiler $CXX is apparently NOT an official release
of the GCC project team.
You may try to compile polymake with it, but if this fails,
please resort to one of versions recommended in the
Installation Guide before sending us a bug report.

*************************************************************
*************************************************************
.
      }
      if ($GCCversion =~ /\s* (\d+\.\d[\d.]*) \s+/xs) {
	 $GCCversion=$1;
      }
      if (v_cmp($GCCversion,"3.3")<0) {
	 return "$CXX says its version is $GCCversion, which is rather out-of-date.\nPlease refer to the installation instructions";
      }
      if (v_cmp($GCCversion,"4.0")>=0) {
	 $warn=<<".";
**********************************************
********        WARNING:              ********

gcc 4 optimization is not very reliable yet.
Use it at your own risk.
Please refer to the installation instructions
for our recomendations.

**********************************************
**********************************************
.
      }
      $ProcessDep="gcc";
      unless ($CC) {
	 ($CC=$CXX) =~ s/\+\+/cc/;
      }

   } elsif ($ICCversion) {
      if (v_cmp($ICCversion,"8.1")<0) {
	 return "$CXX says its version is $ICCversion, while the minimal required version is 8.1";
      }
      $ProcessDep= "gcc";
      unless ($CC) {
	 ($CC=$CXX) =~ s/cpc$/cc/;
      };

   } elsif ($COMOversion) {
      if (v_cmp($COMOversion,"4.3.3")<0) {
	 return "$CXX says its version is $COMOversion, while the minimal required version is 4.3.3";
      }
      $ProcessDep="old";
      $CC ||= $CXX;
   } else {
      return "$CXX seems not to be any of the supported C++ compilers (GNU, Intel, Comeau)";
   }
   if (!$silent && defined($warn)) {
      warn $warn;
   }
   undef;
}

sub compiler_choice($) {
   my ($may_omit)=@_;
   print "\nWhich C++ compiler should be used? ";
   while (1) {
      answer($CXX);
      last if $may_omit and !defined $CXX;
      if ($changed) {
	 undef $CC; undef $CXXflags; undef $Cflags;
      }
      my $error=check_cxx;
      last if !defined $error;
      print "\n$error.\nPlease specify a path to g++", ($may_omit ? " or \"none\": " : " : ");
   }

   print "\nWhich C compiler should be used? ";
   answer($CC);

   print "\nWhich compiler optimization level do you trust? ";
   answer($CXXOPT);
}

sub compiler_options {
   print "\nWhich additional C++ compiler flags should be used (e.g. choosing specific CPU model)? ";
   answer($CXXflags);
   undef $Cflags if $changed;

   $Cflags ||= $CXXflags;
   print "\nWhich additional C compiler flags should be used? ";
   answer($Cflags);

   print "\nWhich additional linker flags should be used? ";
   answer($LDflags);
}

sub icc_check {
   my ($check_only)=@_;

   my $error=build <<'.';
#include <iostream>
int main() {
#ifdef __GNUC__
   std::cout << "Version: " << __GNUC__ << "." << __GNUC_MINOR__;
#endif
   return 0;
}
.
   if (my ($gcc_version)=`./polymake_configure` =~ /Version: ([\d.]+)/) {
      if (v_cmp($gcc_version, "3.3")<0) {
	 return 0 if $check_only;
	 print <<".", "\n Do you want to disable the compatibility mode? ";

*********************************************************
*********             WARNING:                  *********

Your Intel C++ Compiler $CXX apparently runs in
compatibility mode with gcc version $gcc_version,
which is older than the required minimal version 3.3

*********************************************************
.
         if (!yes_not(1)) {
	    print <<".";
Now you must arrange $CXX to use a more up-to-date gcc installation
or choose an entirely different compiler.

.
            return 0;
	 }
      } else {
	 return 1 if $check_only;
	 print <<".", "\nDo you want to disable this mode for polymake? ";

Your $CXX installation per default runs in gcc compatibility mode,
using the GCC standard C++ library.
.
         return 1 if !yes_not(0);
      }
      $CXXflags_ .= " -no-gcc -cxxlib-icc -strict-ansi";
      $LDflags_ .= " -cxxlib-icc";
   }
   1
}

$CXX ||= "g++";
$CXXOPT ||= "-O3";

my $cxx_error=check_cxx(1);
my $options_asked_for;
if (!$quick || defined($cxx_error)) {
COMPILER_CHOICE: {
   undef $CXX if $cxx_error;
   if (!$bindist or
       do {
	  print "\nAre you going to develop new client programs? ";
	  yes_not(0)
       }) {
      compiler_choice($bindist);
      $CPUarch=`uname -m`; chomp $CPUarch;
      if (!defined $CXXflags) {
	 if ($CPUarch eq "sun4u") {
	    $CXXflags="-mcpu=ultrasparc";
	 } elsif ($CPUarch eq "i686") {
	    $_=`cat /proc/cpuinfo`;
	    if (/Athlon/s) {
	       if ($ICCversion) {
		  $CXXflags="";
	       } else {
		  $CXXflags="-march=athlon";
	       }
	    } elsif (/Pentium III/s) {
	       if ($ICCversion) {
		  $CXXflags="-march=pentiumiii -mcpu=pentiumpro";
	       } else {
		  $CXXflags="-march=pentium3";
	       }
	    } elsif (/(?:Pentium IV|Pentium\(R\) 4)/s) {
	       if ($ICCversion) {
		  $CXXflags="-march=pentium4 -mcpu=pentium4";
	       } else {
		  $CXXflags="-march=pentium4";
	       }
	    } elsif (/Pentium/) {
	       if ($ICCversion) {
		  $CXXflags="-mcpu=pentium";
	       } else {
		  $CXXflags="-march=pentium";
	       }
	    }
	 } elsif ($CPUarch eq "x86_64") {
	    $_=`cat /proc/cpuinfo`;
	    if (/Athlon/s) {
	       if ($ICCversion) {
		  $CXXflags="";
	       } else {
		  $CXXflags="-march=athlon64";
	       }
	    } elsif (/Opteron/s) {
	       if ($ICCversion) {
		  $CXXflags="";
	       } else {
		  $CXXflags="-march=opteron";
	       }
	    }
	 } elsif ($CPUarch eq "i86pc") {
	    $CXXflags="-march=pentiumpro";
	 }
      }

      if ($ICCversion && !icc_check) {
	 compiler_options;
	 if (icc_check(1)) {
	    $options_asked_for=1;
	 } else {
	    $cxx_error=1;
	    redo COMPILER_CHOICE;
	 }
      }

      compiler_options if !$quick && !$options_asked_for;
      if ($COMOversion) {
	 foreach ($Cflags, $CXXflags) { ~s/(\S+)/-copt $1/g }
      }
   }

   if ($bindist and
       defined($GCCv_min) && v_cmp($GCCversion,$GCCv_min)<0 ||
       defined($GCCv_max) && v_cmp($GCCversion,$GCCv_max)>0) {
      foreach ("lib", @apps, @modules) {
	 if (!-f "build/$_/.dependences") {
	    open TOUCH, ">build/$_/.rebuild_lib";
	    close TOUCH;
	 }
      }
      open TOUCH, ">build/lib/.install_cxxlib";
      close TOUCH;
   }
} }

$CXXDEBUG ||= $ICCversion ? "-g -Ob0" : "-g";

if (defined $CXX) {

   if ($GCCversion) {
      $CXXflags_ .= " -Wall -ftemplate-depth-200";
      $Cflags_ .= " -Wall";
      $Libs = "";
      if (v_cmp($GCCversion, "4.0")>=0) {
	 $CXXflags_ .= " -Wno-strict-aliasing";
      }
   } elsif ($ICCversion) {
      $CXXflags_ .= " -Wall -wd193,383,304,981,1419,279,810,171,1418,488,1572,561";
      $Cflags_ .= " -Wall -wd193,1572,561";
      $Libs = "";
   } elsif ($COMOversion) {
      $CXXflags_ .= " --diag_suppress 815 -no_A --no_display_mode -D_GNU_SOURCE -D_STL_NO_CONCEPT_CHECKS";
      $Cflags_ .= " -no_A --c --no_display_mode -D_GNU_SOURCE";
      $Libs = "-lm";
   }

   #######################################################################################
   #
   # Check the declaration of socket functions in the system header files
   #
   {
      local $/;
      open C, "$Config::Config{installarchlib}/CORE/config.h"
         or die "can't locate perl's config.h: suspicious perl installation problem?\n";
      $_=<C>; close C;
      if (/define \s+ Sock_size_t \s+ (\w+)/mx) {
	 if ($1 ne "socklen_t") {
	    $CXXflags_ .= " -Dsocklen_t=$1";
	 }
      }
   }

   #######################################################################################
   #
   # Detect whether socket functions reside in a separate library
   #
   if ($Config::Config{libs} =~ "-lsocket") {
      $Libs= $Libs ? "-lsocket $Libs" : "-lsocket";
   }
}

#######################################################################################
#
# Locate the GMP
#
my $needGMPxx=$ENV{WITH_GMP_XX};
sub locateGMP {
   my ($GMPversion)= ($GMPsourceDir =~ /([\d.]+)$/)[0];
   my $GMPrequired=v3.1.1;
   my $GMPerror=1;

   local $Libs="-lgmp $Libs";
   my $build_error=build_c <<".";
#include <gmp.h>
#include <stdio.h>
int main() {
   mpz_t a;
   mpz_init(a);
   printf("%d.%d.%d", __GNU_MP_VERSION, __GNU_MP_VERSION_MINOR, __GNU_MP_VERSION_PATCHLEVEL);
   return 0;
}
.
   if (!$build_error and $?==0) {
      my $is_version=`./polymake_configure`;
      if ($?==0) {
	 if (v_cmp($is_version,$GMPversion)>=0) {
	    if ($needGMPxx) {
	       my $compile_error=compile <<".";
#include <gmpxx.h>
mpz_class x;
.
	       if ($compile_error eq "") {
		  $CXXflags_ .= " -DPOLYMAKE_WITH_GMP_XX";
		  undef $GMPsourceDir;
		  return 1;
	       }
            } else {
	       undef $GMPsourceDir;
	       return 1;
	    }
	 }
	 if (!$silent) {
	    print "\nThe GNU Multiprecision Library (GMP) installed at your site";
	 }
	 if ($needGMPxx && v_cmp($is_version,$GMPversion)>=0) {
	    print " is configured\nWITHOUT c++ wrapper classes needed for the Parma Polyhedra Library.\n";
	 } elsif (v_cmp($is_version,$GMPrequired)>=0) {
	    if (!$silent) {
	       $GMPerror=0;
	       print " is not of the latest version.\n";
	    } else {
	       undef $GMPsourceDir;
	       return 1;
	    }
	 } elsif (!$silent) {
	    print " is of version $is_version\n",
	          "while $GMPversion is the minimal required version.\n";
	 }
      } elsif (!$silent) {
	 print "\nA program checking for the GNU Multiprecision Library (GMP) failed.\n",
               "Probably it couldn't find the shared library.\n";
      }
   } elsif (!$silent) {
      print "\nA program checking for the GNU Multiprecision Library (GMP) couldn't be compiled:\n",
            $build_error;
   }

   if (!$silent) {
      if ($GMPerror) {
	 print "\nIf you know that the required version of GMP is installed somewhere at your site,\n",
               "would you like to adjust compiler and linker options,\n",
	       "so that it can be found by the next try? ";
	 if (yes_not(0)) {
	    print "\nPlease supply the path to gmp.h in the -I compiler option\n",
                  "and the path to libgmp.a or libgmp.so in the -L linker option\n";
	    compiler_options;
	    return 0;
	 }
      }
      print "\nThe polymake distribution contains the source code for this library in the version $GMPversion\n",
	    "Should it be installed LOCALLY together with polymake? ";
      if (yes_not(1)) {
	 $GMPconfEnv ||= "CC=$CC";
	 print "\nEnvironment variables for GMP configuration: ";
	 answer($GMPconfEnv);

	 if ($CPUarch eq "sun4u" || $CPUarch eq "i86pc") {
	    if ($CXXflags !~ /-m64/) {
	       $GMPconfOpt ||= "ABI=32";
	    }
	 }
	 print "\nOptions for GMP configuration: ";
	 answer($GMPconfOpt);
      } else {
	 if ($GMPerror) {
	    die "OK, you are going to install it yourself.\n",
	        "You might want to visit http://www.swox.com/gmp/\n",
                "and check for a newer releases or actual patches before.\n",
	        "When ready, run `make configure' again.\n";
	 } else {
	    undef $GMPsourceDir;
	 }
      }
   }
   1;
}

($GMPsourceDir)=(glob "external/gmp-*");
until (locateGMP) { }

######################################################################################
#
# Other stuff borrowed from perl config
#
sub checkPerlExe {
   my $verbose=shift;
   if (-x $PerlExe  and
       `$PerlExe -v` =~ /^This is perl/m) {
      if (`$PerlExe -e 'print $]'` >= 5.008) {
	 1
      } else {
	 $verbose and print "\nThe perl installation at $PerlExe is too old; perl version must be at least 5.8\n";
	 0
      }
   } else {
      $verbose and print "\nThe path you have specified doesn't seem to point to a perl interpreter!\n";
      0
   }
}

if (!defined $PerlExe  or  !checkPerlExe(0)) {
   $PerlExe = ($Config::Config{startperl} =~ m'#!(.*)')[0];
   if ($multi) {
      while (1) {
	 print "\nWhat is the architecture-invariant path to the perl interpreter\n",
               "(ask your sysadmin for assistance if in doubt?) ";
	 answer_path($PerlExe);
	 last if checkPerlExe(1);
      }
   }
}
######################################################################################
#
# Create the build directories and write the Makefile's
#
my $relBuildDir= $multi_build ? "build.$build_arch" : "build";
$BuildDir=$relBuildDir;
if (!$bindist) {
   if (!-e $BuildDir
       and $ENV{BuildTop} ||
           do {
	      foreach my $build (glob "build.*") {
		 if (-l $build) {
		    $build=readlink $build;
		    if (-d $build && $build =~ s|/build(?:\.[^/]+)?$||) {
		       $ENV{BuildTop}=$build;
		       last;
		    }
	         }
	      }
	      $ENV{BuildTop}
           }
       and $ENV{BuildTop} ne '.') {
      $BuildDir="$ENV{BuildTop}/$relBuildDir";
      symlink $BuildDir, $relBuildDir;
      symlink $TOP, "$ENV{BuildTop}/ProjectTop";
      $ProjectTopLink="/ProjectTop";
   }
   make_dir for $BuildDir, "$BuildDir/apps", "$BuildDir/modules";
   $ProjectTopLink ||= -l $BuildDir && "/ProjectTop";
}

### build perl extensions
my $perlxdir="$BuildDir/perlx-$Config::Config{version}-$Config::Config{archname}";
my $absBuildDir=Cwd::abs_path($BuildDir);
make_dir $perlxdir;
if (! -f "$perlxdir/Makefile") {
   system "cd $perlxdir; $^X $TOP/perl/ext/Makefile.PL";
}
system "$ENV{MAKE} -C $perlxdir all pure_install InstallDir=$absBuildDir";

### GMP build directory
if ($GMPsourceDir) {
   $GMPbuildDir="$relBuildDir/external/gmp";
   make_dir for "$BuildDir/external", $GMPbuildDir;
   my $configure="../../..$ProjectTopLink/$GMPsourceDir/configure";
   my $enable_cxx= $needGMPxx && ($CXXflags_ .= " -DPOLYMAKE_WITH_GMP_XX", "--enable-cxx");
   system "cd $GMPbuildDir; $GMPconfEnv $configure --prefix=$InstallTop --exec-prefix=$InstallArch $enable_cxx $GMPconfOpt >&2";
   $GMPbuildDir="\$(BuildDir)/external/gmp";
} else {
   ($GMPbuildDir, $GMPconfOpt, $GMPconfEnv)=();
}

### start writing the conf file
open CONF, ">$BuildDir/conf.make";

foreach my $var (@noexport, @export) {
   print CONF "$var=$$var\n" if defined($$var);
   if (defined ${$var."_"}) {
      print CONF "$var+=".${$var."_"}."\n";
   }
}

print CONF "export ", join(" ", grep { defined($$_) } @export), "\n";

### configure the java components
if (!$quick) {
   do "support/configure_java.pl";
   print STDERR "ERROR in configure_java:\n$@" if $@;
}

### complete the conf file
my $DirMask= $developer eq "local" ? "775" : "755";

print CONF <<".";
# permissions for installation directories
export DirMask=$DirMask
# umask active during the compilation
# UMASK=umask 002;
# end of configure
RANLIB=$Config::Config{ranlib}
export INSTALL_PL=$TOP/support/install.pl
DESTDIR=
export FinalInstallTop := \$(InstallTop)
export FinalInstallArch := \$(InstallArch)
InstallTop := \$(DESTDIR)\$(InstallTop)
InstallArch := \$(DESTDIR)\$(InstallArch)
InstallDoc := \$(DESTDIR)\$(InstallDoc)
InstallLinks := \$(DESTDIR)\$(InstallLinks)
.
close CONF;

if (!$bindist  and  @apps) {
   if (! -e "external") {
      if ($developer eq "local") {
	 symlink "$ProjectTop/external", "external";
      } elsif ($developer eq "remote") {
	 print "Trying to copy external libraries from $ProjectTop ...\n";
	 system("scp -rp $ProjectTop/external .");
	 if (! -d "external") {
	    print "scp failed - exiting\n";
	    exit(1);
	 }
      }
   }
   ### cdd and lrs build directories
   make_dir "$BuildDir/external";
   foreach my $pkg (qw(cdd lrs)) {
      make_build_dir "external/$pkg";
      unlink "$BuildDir/external/$pkg/src";
      symlink "../../..$ProjectTopLink/".(glob "external/$pkg*")[0], "$BuildDir/external/$pkg/src";
   }
}

if ($developer && -d "rpm") {
   make_dir_path "$BuildDir/rpm/BUILD";
   symlink "../$relBuildDir/rpm/BUILD", "rpm/BUILD";
}

### core library and applications build directories
make_build_dir "lib", @apps, @modules;

END {
   unlink glob "polymake_configure*";
   unlink glob "core*";
}
