1#  Copyright (c) 1997-2021
2#  Ewgenij Gawrilow, Michael Joswig, and the polymake team
3#  Technische Universität Berlin, Germany
4#  https://polymake.org
5#
6#  This program is free software; you can redistribute it and/or modify it
7#  under the terms of the GNU General Public License as published by the
8#  Free Software Foundation; either version 2, or (at your option) any
9#  later version: http://www.gnu.org/licenses/gpl.txt.
10#
11#  This program is distributed in the hope that it will be useful,
12#  but WITHOUT ANY WARRANTY; without even the implied warranty of
13#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14#  GNU General Public License for more details.
15#-------------------------------------------------------------------------------
16
17@conf_vars=qw( UseBundled CFLAGS LDFLAGS LIBS );
18
19sub allowed_options {
20   my ($allowed_options, $allowed_with)=@_;
21   @$allowed_with{ qw( cdd cdd-include cdd-lib) }=();
22}
23
24
25sub usage {
26   print STDERR "  --with-cdd=PATH  Installation path of cddlib, if non-standard.\n",
27                "                   By default, polymake will try to use a system-wide\n",
28                "                   installation or fall back to the bundled cddlib\n",
29                "                   (bundled/cdd/external/cdd) if it exists.\n",
30                "                   To force the bundled version, specify 'bundled' as PATH.\n",
31                "  --with-cdd-include=PATH  Path to the folder containing cdd.h\n",
32                "  --with-cdd-lib=PATH      Path to the folder containing libcddgmp.{a,so,dylib} \n";
33}
34
35sub check_bundled {
36   -e "bundled/cdd/external/cdd/lib-src-gmp/cdd.h"
37}
38
39sub proceed {
40   my ($options)=@_;
41   my $cdd_path;
42   my $cddversion;
43   $UseBundled = 1;
44
45   if (defined ($cdd_path=$options->{cdd}) and $cdd_path ne "bundled") {
46      my $cdd_inc="$cdd_path/include";
47      if (-f "$cdd_inc/cdd.h") {
48         $CFLAGS = "-I$cdd_inc";
49      } elsif (-f "$cdd_inc/cdd/cdd.h") {
50         # This is for debian where the includes are moved to a subdirectory
51         $CFLAGS = "-I$cdd_inc/cdd";
52      } elsif (-f "$cdd_inc/cddlib/cdd.h") {
53         # This is for fedora where the includes are moved to a subdirectory
54         $CFLAGS = "-I$cdd_inc/cddlib";
55      }
56      my $cdd_lib=Polymake::Configure::get_libdir($cdd_path, "cddgmp");
57      if (-f "$cdd_lib/libcddgmp.$Config::Config{so}" ) {
58         $LDFLAGS = "-L$cdd_lib";
59         $LDFLAGS .= " -Wl,-rpath,$cdd_lib" if $cdd_path ne "/usr";
60      }
61      if (!$CFLAGS or !$LDFLAGS) {
62         die "Invalid installation location of cddlib: header file cdd.h and/or library libcddgmp.$Config::Config{so} not found.\n",
63             "You might try to use --with-cdd-include and --with-cdd-lib.\n";
64      }
65   }
66
67   if (defined (my $cdd_inc=$options->{'cdd-include'})) {
68      $CFLAGS = "-I$cdd_inc";
69      $cdd_path .= "include: $cdd_inc ";
70   }
71   if (defined ($cdd_lib=$options->{'cdd-lib'})) {
72      $LDFLAGS = "-L$cdd_lib -Wl,-rpath,$cdd_lib";
73      $cdd_path .= "lib: $cdd_lib";
74   }
75
76
77   if ($cdd_path ne "bundled") {
78      my $testcode = <<"---";
79#include <cstddef>
80#include <iostream>
81#include <gmp.h>
82
83#define GMPRATIONAL
84extern "C" {
85   #include <setoper.h>
86   #include <cdd.h>
87}
88
89int main() {
90   std::cout << "dd " << dd_DDVERSION << std::endl;
91   std::cout << "ddf " << ddf_DDVERSION << std::endl;
92   dd_set_global_constants();
93   dd_free_global_constants();
94   ddf_set_global_constants();
95   ddf_free_global_constants();
96   return 0;
97}
98---
99      my $error=Polymake::Configure::build_test_program($testcode, LIBS => "-lcddgmp -lgmp", CXXFLAGS => "$CFLAGS", LDFLAGS => "$LDFLAGS");
100      if ($? != 0) {
101         # if this failed then we try to determine whether the includes from cdd are in a subfolder
102         # (like on debian or fedora)
103         my $newcode;
104         foreach my $subdir (qw(cdd cddlib)) {
105            ($newcode = $testcode) =~ s{setoper\.h|cdd\.h}{$subdir/$&}g;
106            $error = Polymake::Configure::build_test_program($newcode, CXXFLAGS => "$CFLAGS", LIBS => "-lcddgmp -lgmp", LDFLAGS => "$LDFLAGS");
107            last if $? == 0;
108         }
109         if ($? == 0) {
110            # run just the preprocessor and parse the output to find the path of cdd.h
111            open my $source, "echo '$newcode' | $Polymake::Configure::CXX $CFLAGS -xc++ -E - 2>/dev/null |"
112               or die "This looks like debian or fedora with cdd.h in a subfolder but we could not\n",
113                      "run the preprocessor to find the cdd include path '$Polymake::Configure::CXX $CFLAGS -xc++ -E -': $!\n",
114                      "You can try specifying --with-cdd-include and --with-cdd-lib";
115            while (<$source>) {
116               if (m{\# \d+ "(\S+)/cdd\.h"}) {
117                  $CFLAGS .= " -I$1";
118                  last;
119               }
120            }
121            close $source;
122         }
123      }
124      $error=Polymake::Configure::build_test_program($testcode, LIBS => "-lcddgmp -lgmp", CXXFLAGS => "$CFLAGS", LDFLAGS => "$LDFLAGS");
125      if ($?==0) {
126         my $message=Polymake::Configure::run_test_program();
127         if ($?) {
128            check_bundled() and !defined($cdd_path) or
129               die "Could not run a test program checking for cdd library.\n",
130                   "The complete error log follows:\n\n$message\n",
131                   "Please investigate the reasons and fix the installation.\n";
132         } else {
133            my ($ddver,$ddfver) = $message =~ /dd Version ([0-9a-z.]+).*\nddf Version ([0-9a-z.]+)/;
134            if ($ddver ne $ddfver) {
135               check_bundled() and !defined($cdd_path) or
136                  die "Your cddlib installation does not seem to contain the floating-point arithmetic version.\n",
137                      "Reported versions: dd_DDVERSION=$ddver and ddf_DDVERSION=$ddfver\n";
138            } elsif (($ddver cmp "0.94f") >= 0) {
139               $UseBundled = 0;
140               $cddversion = $ddver;
141            } else {
142               check_bundled() and !defined($cdd_path) or
143                  die "Your cddlib version $ddver is too old, at least version 0.94f is required.\n";
144            }
145         }
146      } else {
147         check_bundled() and !defined($cdd_path) or
148            die "Could not compile a test program checking for cdd library.\n",
149                "The most probable reasons are that the library is installed at a non-standard location,\n",
150                "is not configured to build a shared module, or missing at all.\n",
151                "The complete error log follows:\n\n$error\n",
152                "Please install the library and specify its location using --with-cdd option, if needed.\n",
153                "Please remember to enable shared modules when configuring the cdd library!\n";
154      }
155   }
156
157   if ($UseBundled) {
158      die "bundled cdd requested but it cannot be found"
159         unless (-e "bundled/cdd/external/cdd/lib-src-gmp/cdd.h");
160      undef $LIBS;
161      $CFLAGS='-I${root}/bundled/cdd/external/cdd/lib-src-gmp';
162   } else {
163      $LIBS="-lcddgmp";
164   }
165
166   return $UseBundled ? "bundled" : ("$cddversion @ ".($cdd_path//"system"));
167}
168
169