#!/bin/sh
#--------------------------------------------------------------------------#
# Run './configure' to produce a 'makefile' in the 'build' sub-directory or
# in any immediate sub-directory different from the 'src', 'scripts' and
# 'test' directories.
#--------------------------------------------------------------------------#
rm -f configure.log
#--------------------------------------------------------------------------#
# Common default options.
all=no
debug=no
logging=no
check=no
competition=no
coverage=no
profile=no
contracts=yes
tracing=yes
unlocked=yes
pedantic=no
options=""
quiet=no
m32=no
#--------------------------------------------------------------------------#
if [ -f ./scripts/colors.sh ]
then
. ./scripts/colors.sh
elif [ -f ../scripts/colors.sh ]
then
. ../scripts/colors.sh
else
BAD=""
HILITE=""
BOLD=""
NORMAL=""
fi
die () {
if [ -f configure.log ]
then
checklog=" (check also 'configure.log')"
else
checklog=""
fi
cecho "${BOLD}configure:${NORMAL} ${BAD}error:${NORMAL} $*${checklog}"
exit 1
}
msg () {
cecho "${BOLD}configure:${NORMAL} $*"
}
# if we can find the 'color.sh' script source it and overwrite color codes
for dir in . ..
do
[ -f $dir/scripts/colors.sh ] || continue
. $dir/scripts/colors.sh || exit 1
break
done
#--------------------------------------------------------------------------#
# Parse and handle command line options.
usage () {
cat << EOF
usage: configure [ ... ]
where ' ' is one of the following
-h|--help print this command line summary
-g|--debug compile with debugging information
-c|--check compile with assertion checking (default for '-g')
-l|--log[ging] include logging code (but disabled by default)
-a|--all short cut for all above, e.g., '-g -l' (thus also '-c')
-q|--quiet exclude message and profiling code (logging too)
-p|--pedantic add '--pedantic' and '-Werror' compilation flag
-s|--symbols add '-ggdb3' (even for optimized compilation)
--coverage compile with '-ftest-coverage -fprofile-arcs' for 'gcov'
--profile compile with '-pg' to profile with 'gprof'
--no-contracts compile without API contract checking code
--no-tracing compile without API call tracing code
--competition configure for the competition
('--quiet', '--no-contracts', '--no-tracing')
-f... pass '-f [=]' options to the makefile
-m32 pass '-m32' to the compiler (compile for 32 bit)
-ggdb3 pass '-ggdb3' to makefile (like '-s')
-O|-O[123] pass '-O' or '-O[123]' to the makefile
-j|-j... pass this option to the makefile (for parallel build)
The environment variable CXX can be used to set a different C++
compiler than the default 'g++'. Similarly you can add additional
compilation options by setting CXXFLAGS. For example
CXX=clang++ CXXFLAGS=-fPIC ./configure
will enforce to use 'clang++' as C++ compiler and also produce
position independent code. In order to be shell independent we also
allow to have the following form. Thus for instance
./configure CXX="g++-8" CXXFLAGS="-fPIC -fsanitize=address"
will have the same effect as
CXX="g++-8" ./configure -fPIC -fsanitize=address
The following configuration options might be usefull during porting the
code to a new platform and are usually not necessary to change.
--no-unlocked force compilation without unlocked IO
EOF
exit 0
}
#--------------------------------------------------------------------------#
while [ $# -gt 0 ]
do
case $1 in
-h|--help) usage;;
-a|--all) all=yes;;
-g|--debug) debug=yes;;
-c|--check) check=yes;;
-l|--log|--logging) logging=yes;;
-p|--pedantic) pedantic=yes;;
-q|--quiet) quiet=yes;;
--no-contracts | --no-contract) contracts=no;;
--no-tracing | --no-trace) tracing=no;;
--coverage) coverage=yes;;
--profile) profile=yes;;
--competition) competition=yes;;
--no-unlocked) unlocked=no;;
-j*) MAKEFLAGS="$1";;
-m32) options="$options $1";m32=yes;;
-f*|-ggdb3|-O|-O1|-O2|-O3) options="$options $1";;
-s|--symbols) options="$options -ggdb3";;
CXX=*)
CXX="`expr \"$1\" : 'CXX=\(.*\)'`"
;;
CXXFLAGS=*)
CXXFLAGS="`expr \"$1\" : 'CXXFLAGS=\(.*\)'`"
;;
*) die "invalid option '$1' (try '-h')";;
esac
shift
done
#--------------------------------------------------------------------------#
if [ $quiet = yes ]
then
[ $logging = yes ] && die "can not combine '-q' with '-l'"
fi
if [ $all = yes ]
then
[ $check = yes ] && die "'-a' subsumes '-c'"
[ $debug = yes ] && die "'-a' subsumes '-g'"
[ $logging = yes ] && die "'-a' subsumes '-l'"
check=yes
debug=yes
logging=yes
elif [ $debug = yes ]
then
[ $check = yes ] && die "'-g' subsumes '-c'"
check=yes
fi
#--------------------------------------------------------------------------#
# Generate and enter 'build' directory if not already in sub-directory.
build_in_default_build_sub_directory () {
if [ -d build ]
then
msg "reusing default 'build' directory"
else
mkdir build 2>/dev/null || \
die "failed to generate 'build' directory"
msg "making default 'build' directory"
fi
cd build
msg "building in default ${HILITE}'`pwd`'${NORMAL}"
build=build
}
if [ -f configure -a -f makefile.in -a -d src ]
then
root="`pwd`"
build_in_default_build_sub_directory
elif [ -f ../configure -a -f ../makefile.in -a -d ../src ]
then
cwd="`pwd`"
build=`basename "$cwd"`
root=`dirname "$cwd"`
case x"$build" in
xsrc|xtest|xscripts)
cd ..
build_in_default_build_sub_directory
;;
*)
msg "building in ${HILITE}'$build'${NORMAL} sub-directory"
;;
esac
else
die "call 'configure' from root of CaDiCaL source or a sub-directory"
fi
msg "root directory '$root'"
#--------------------------------------------------------------------------#
# Prepare '@CXX@' and '@CXXFLAGS@' parameters for 'makefile.in'
[ x"$CXX" = x ] && CXX=g++
[ x"$CXXFLAGS" = x ] || CXXFLAGS="$CXXFLAGS "
case x"$CXX" in
xg++*|xclang++*) CXXFLAGS="${CXXFLAGS}-Wall -Wextra";;
*) CXXFLAGS="${CXXFLAGS}-W";;
esac
if [ $debug = yes ]
then
CXXFLAGS="$CXXFLAGS -g"
else
case x"$CXX" in
xg++*|xclang++*) CXXFLAGS="$CXXFLAGS -O3";;
*) CXXFLAGS="$CXXFLAGS -O";;
esac
fi
if [ $m32 = yes ]
then
case x"$CXX" in
xg++*)
options="$options -mpc64"
msg "forcing portable 64-bit FPU mode ('-mpc64') for '$CXX'"
;;
esac
fi
if [ $competition = yes ]
then
quiet=yes
contracts=no
tracing=no
fi
[ $check = no ] && CXXFLAGS="$CXXFLAGS -DNDEBUG"
[ $logging = yes ] && CXXFLAGS="$CXXFLAGS -DLOGGING"
[ $quiet = yes ] && CXXFLAGS="$CXXFLAGS -DQUIET"
[ $profile = yes ] && CXXFLAGS="$CXXFLAGS -pg"
[ $coverage = yes ] && CXXFLAGS="$CXXFLAGS -ftest-coverage -fprofile-arcs"
[ $pedantic = yes ] && CXXFLAGS="$CXXFLAGS --pedantic -Werror"
[ $contracts = no ] && CXXFLAGS="$CXXFLAGS -DNCONTRACTS"
[ $tracing = no ] && CXXFLAGS="$CXXFLAGS -DNTRACING"
CXXFLAGS="$CXXFLAGS$options"
#--------------------------------------------------------------------------#
case x"$CXX" in
xg++* | xclang++*) WERROR="-Werror -pedantic";;
*) WERROR="";;
esac
# Check that compilation flags work.
feature=./configure-hello-world
cat < $feature.cpp
#include
int main () { std::cout << "hello world" << std::endl; }
EOF
if $CXX $CXXFLAGS $WERROR -o $feature.exe $feature.cpp 2>>configure.log
then
if [ ! "`$feature.exe 2>>configure.log`" = "hello world" ]
then
die "execution of '$feature.exe' failed"
fi
else
die "test compilation '$feature.cpp'"
fi
#--------------------------------------------------------------------------#
# Since C99/C++0x is becoming the standard newer versions of 'g++' (7.3 for
# instance) discourage certain GCC extensions, particularly the GCC version
# of variadic macros, if the same concept exists in the standard. This
# forced us to replace all GCC style 'ARGS...' macros with '...' and
# '__VA_ARGS__'. Otherwise compiling the library with '--pedantic -Werror'
# would fail (configuration flag '-p'). However, older versions of 'gcc'
# (such as 4.8) would disallow these new forms of macros unless we
# explicitly enforce the new standard with '-std=c++0x'. Here we try to
# figure out whether we need that flag.
feature=./configure-requires-c++0x
cat < $feature.cpp
#include
#include
// old variadic macro usage 'ARGS...' / '#ARGS' discouraged in g++-7...
// new variadic macro usage '...' / '__VA_ARGS__' available in C99/C++0x
//
#define MACRO(FMT, ...) printf (FMT "\n", __VA_ARGS__)
// we use ranged for loops which became available in gcc 4.6 and for
// the gcc 4.6 as well as 4.8 requires '-std=c++0x' too.
//
unsigned f (const std::vector & a) {
unsigned res = 0;
for (auto i : a) res += i;
return res;
}
int main () { MACRO ("%d", 42); return 0; }
EOF
if $CXX $CXXFLAGS $WERROR -o $feature.exe $feature.cpp 2>>configure.log
then
if [ "`$feature.exe 2>>configure.log`" = 42 ]
then
msg "compiler supports all required C99/C++0x extensions"
else
die "checking compilation without '-std=c++0x' failed"
fi
else
CXXFLAGS="$CXXFLAGS -std=c++0x"
if $CXX $CXXFLAGS -o $feature.exe $feature.cpp 2>>configure.log
then
if [ "`$feature.exe 2>>configure.log`" = 42 ]
then
msg "using '-std=c++0x' for all required C99/C++0x extensions"
else
die "checking compilation with '-std=c++0x' failed"
fi
else
die "compiler does not support C99/C++0x even with '-std=c++0x'"
fi
fi
#--------------------------------------------------------------------------#
# Unlocked IO is much faster but not necessarily supported.
if [ $unlocked = yes ]
then
feature=./configure-have-unlocked-io
cat < $feature.cpp
#include
int main () {
const char * path = "$feature.log";
FILE * file = fopen (path, "w");
if (!file) return 1;
if (putc_unlocked (42, file) != 42) return 1;
if (fclose (file)) return 1;
file = fopen (path, "r");
if (!file) return 1;
if (getc_unlocked (file) != 42) return 1;
if (fclose (file)) return 1;
return 0;
}
EOF
if $CXX $CXXFLAGS -o $feature.exe $feature.cpp 2>>configure.log
then
if $feature.exe
then
msg "unlocked IO with '{putc,getc}_unlocked' seems to work"
else
msg "not using unlocked IO (running '$feature.exe' failed)"
unlocked=no
fi
else
msg "not using unlocked IO (failed to compile '$feature.cpp')"
unlocked=no
fi
else
msg "not using unlocked IO (since '--no-unlocked' specified)"
fi
[ $unlocked = no ] && CXXFLAGS="$CXXFLAGS -DNUNLOCKED"
#--------------------------------------------------------------------------#
# Instantiate '../makefile.in' template to produce 'makefile' in 'build'.
msg "compiling with ${HILITE}'$CXX $CXXFLAGS'${NORMAL}"
rm -f makefile
sed \
-e "2c\\
# This 'makefile' is generated from '../makefile.in'." \
-e "s,@CXX@,$CXX," \
-e "s#@CXXFLAGS@#$CXXFLAGS#" \
-e "s,@MAKEFLAGS@,$MAKEFLAGS," \
../makefile.in > makefile
msg "generated '$build/makefile' from '../makefile.in'"
#--------------------------------------------------------------------------#
build="`pwd`"
makefile="`dirname "$build"`/makefile"
cat < "$makefile"
CADICALBUILD=$build
all:
\$(MAKE) -C "\$(CADICALBUILD)"
clean:
@if [ -d "\$(CADICALBUILD)" ]; \\
then \\
if [ -f "\$(CADICALBUILD)"/makefile ]; \\
then \\
touch "\$(CADICALBUILD)"/build.hpp; \\
\$(MAKE) -C "\$(CADICALBUILD)" clean; \\
fi; \\
rm -rf "\$(CADICALBUILD)"; \\
fi
rm -f "$makefile"
test:
\$(MAKE) -j1 -C "\$(CADICALBUILD)" test
cadical:
\$(MAKE) -j1 -C "\$(CADICALBUILD)" cadical
mobical:
\$(MAKE) -j1 -C "\$(CADICALBUILD)" mobical
update:
\$(MAKE) -j1 -C "\$(CADICALBUILD)" update
.PHONY: all cadical clean mobical test update
EOF
msg "generated '../makefile' as proxy to ..."
msg "... '$build/makefile'"
msg "now run ${HILITE}'make'${NORMAL} to compile CaDiCaL"
msg "optionally run 'make test'"