blob: 1f8f7ac595fe0f130e292cd7494e73db2badf71a [file] [log] [blame]
#! /bin/sh
#
# Copyright 2018 Gavin D. Howard
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
# OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
#
usage() {
if [ $# -gt 0 ]; then
val=1
echo "$1"
echo ""
else
val=0
fi
echo "usage: $0 [-b|-d|-c] [-hHS] [-g(-m|-r)|-N] [-k KARATSUBA_LEN]"
echo ""
echo " -b"
echo " Build bc only. It is an error if \"-d\" is specified too."
echo " -c"
echo " Generate test coverage code. Requires gcov and regcovr."
echo " It is an error if either \"-b\" or \"-d\" is specified."
echo " Implies \"-N\"."
echo " -d"
echo " Build dc only. It is an error if \"-b\" is specified too."
echo " -g"
echo " Build in debug mode."
echo " -h"
echo " Print this help message and exit."
echo " -H"
echo " Disable history (currently not implemented)."
echo " -k KARATSUBA_LEN"
echo " Set the karatsuba length to KARATSUBA_LEN (default is 32)."
echo " It is an error if KARATSUBA_LEN is not a number or is less than 2."
echo " -m"
echo " Enable minimum-size release flags (-Os -DNDEBUG -s)."
echo " It is an error if \"-r\" or \"-g\" are specified too."
echo " -N"
echo " Disable default CFLAGS. It is an error to specify this option"
echo " with any of \"-g\", \"-m\", or \"-r\"."
echo " -r"
echo " Enable default release flags (-O3 -DNDEBUG -s). On by default."
echo " If given with \"-g\", a debuggable release will be built."
echo " It is an error if \"-m\" is specified too."
echo " -S"
echo " Disable signal handling. On by default."
echo ""
echo "In addition, the following environment variables are used:"
echo ""
echo " CC C compiler. Must be either gcc or clang."
echo " HOSTCC Host C compiler."
echo " CFLAGS C compiler flags. You can use this for extra optimization flags."
echo " CPPFLAGS C preprocessor flags."
echo " LDFLAGS Linker flags."
echo " PREFIX the prefix to install to. Default is /usr/local."
echo " If PREFIX is \"/usr\", install path will be \"/usr/bin\"."
echo " DESTDIR For package creation."
echo " GEN_EMU Emulator to run string generator code under"
echo " (leave empty if not necessary)."
exit "$val"
}
err_exit() {
if [ "$#" -ne 1 ]; then
echo "Invalid number of args to err_exit"
exit 1
fi
echo "$1"
exit 1
}
replace_ext() {
if [ "$#" -ne 3 ]; then
err_exit "Invalid number of args to $0"
fi
file="$1"
ext1="$2"
ext2="$3"
result=$(echo "$file" | sed -e "s@\.$ext1@\.$ext2@")
echo "$result"
}
replace_exts() {
if [ "$#" -ne 3 ]; then
err_exit "Invalid number of args to $0"
fi
files="$1"
ext1="$2"
ext2="$3"
for file in $files; do
new_name=$(replace_ext "$file" "$ext1" "$ext2")
result="$result $new_name"
done
echo "$result"
}
replace() {
if [ "$#" -ne 3 ]; then
err_exit "Invalid number of args to $0"
fi
str="$1"
needle="$2"
replacement="$3"
result=$(printf '%s' "$str" | sed -e "s!%%$needle%%!$replacement!g")
echo "$result"
}
gen_file_lists() {
if [ "$#" -ne 3 ]; then
err_exit "Invalid number of args to $0"
fi
contents="$1"
filedir="$2"
typ="$3"
needle="${typ}SRC"
replacement=$(ls $filedir/*.c | tr '\n' ' ')
contents=$(replace "$contents" "$needle" "$replacement")
needle="${typ}OBJ"
replacement=$(replace_exts "$replacement" "c" "o")
contents=$(replace "$contents" "$needle" "$replacement")
needle="${typ}GCDA"
replacement=$(replace_exts "$replacement" "o" "gcda")
contents=$(replace "$contents" "$needle" "$replacement")
needle="${typ}GCNO"
replacement=$(replace_exts "$replacement" "gcda" "gcno")
contents=$(replace "$contents" "$needle" "$replacement")
echo "$contents"
}
bc_only=0
dc_only=0
coverage=0
karatsuba_len=32
min_size=0
debug=0
release=0
signals=1
hist=1
none=0
while getopts "bcdghHk:mNrS" opt; do
case "$opt" in
b) bc_only=1 ;;
c) coverage=1 ; none=1 ;;
d) dc_only=1 ;;
g) debug=1 ;;
h) usage ;;
H) hist=0 ;;
k) karatsuba_len="$OPTARG" ;;
m) min_size=1 ;;
N) none=1 ;;
r) release=1 ;;
S) signals=0 ;;
t) hist=1 ;;
?) usage "Invalid option" ;;
esac
done
if [ "$bc_only" -eq 1 -a "$dc_only" -eq 1 ]; then
usage "Can only specify one of -b or -d"
fi
case $karatsuba_len in
(*[!0-9]*|'') usage "KARATSUBA_LEN is not a number" ;;
(*) ;;
esac
if [ "$karatsuba_len" -lt 2 ]; then
usage "KARATSUBA_LEN is less than 2"
fi
if [ "$release" -eq 1 -a "$min_size" -eq 1 ]; then
usage "Can only specify one of -r or -m"
fi
if [ "$none" -eq 1 ]; then
if [ "$release" -eq 1 -o "$min_size" -eq 1 -o "$debug" -eq 1 ]; then
usage "Cannot specify -N (or -c) with -r, -m, or -g"
fi
fi
set -e
script="$0"
scriptdir=$(dirname "$script")
contents=$(cat "$scriptdir/Makefile.in")
needle="WARNING"
replacement="# *** WARNING: Autogenerated from Makefile.in. DO NOT MODIFY ***\n#"
contents=$(replace "$contents" "$needle" "$replacement")
contents=$(gen_file_lists "$contents" "$scriptdir/src" "")
contents=$(gen_file_lists "$contents" "$scriptdir/src/bc" "BC_")
contents=$(gen_file_lists "$contents" "$scriptdir/src/dc" "DC_")
link="@echo \"No link necessary\""
main_exec="BC_EXEC"
bc_test="tests/all.sh bc"
dc_test="tests/all.sh dc"
timeconst="tests/bc/timeconst.sh"
# In order to have cleanup at exit, we need to be in
# debug mode, so don't run valgrind without that.
if [ "$debug" -ne 0 ]; then
vg_bc_test="tests/all.sh bc valgrind \$(VALGRIND_ARGS) \$(BC_EXEC)"
vg_dc_test="tests/all.sh dc valgrind \$(VALGRIND_ARGS) \$(DC_EXEC)"
timeconst_vg="echo \"100\" | valgrind \$(VALGRIND_ARGS) \$(BC_EXEC) tests/bc/scripts/timeconst.bc"
else
vg_bc_test="@echo \"Cannot run valgrind without debug flags\""
vg_dc_test="@echo \"Cannot run valgrind without debug flags\""
timeconst_vg="@echo \"Cannot run valgrind without debug flags\""
fi
karatsuba="@echo \"karatsuba cannot be run because one of bc or dc is not built\""
karatsuba_test="@echo \"karatsuba cannot be run because one of bc or dc is not built\""
if [ "$bc_only" -eq 1 ]; then
bc=1
dc=0
executables="bc"
dc_test="@echo \"No dc tests to run\""
vg_dc_test="@echo \"No dc tests to run\""
elif [ "$dc_only" -eq 1 ]; then
bc=0
dc=1
executables="dc"
main_exec="DC_EXEC"
bc_test="@echo \"No bc tests to run\""
vg_bc_test="@echo \"No bc tests to run\""
timeconst="@echo \"timeconst cannot be run because bc is not built\""
timeconst_vg="@echo \"timeconst cannot be run because bc is not built\""
else
bc=1
dc=1
executables="bc and dc"
link="\$(LINK) \$(BIN) \$(DC)"
karatsuba="\$(KARATSUBA)"
karatsuba_test="\$(KARATSUBA) 100 \$(BC_EXEC)"
fi
if [ "$debug" -eq 1 ]; then
CFLAGS="$CFLAGS -g -fno-omit-frame-pointer"
if [ "$release" -ne 1 -a "$min_size" -ne 1 ]; then
CFLAGS="$CFLAGS -O0"
fi
else
CPPFLAGS="$CPPFLAGS -DNDEBUG"
LDFLAGS="$LDFLAGS -s"
fi
if [ "$release" -eq 1 -o "$none" -eq 0 ]; then
if [ "$debug" -ne 1 ]; then
CFLAGS="$CFLAGS -O3"
fi
fi
if [ "$min_size" -eq 1 ]; then
CFLAGS="$CFLAGS -Os"
fi
if [ "$coverage" -eq 1 ]; then
if [ "$bc_only" -eq 1 -o "$dc_only" -eq 1 ]; then
usage "Can only specify -c without -b or -d"
fi
CFLAGS="$CFLAGS -fprofile-arcs -ftest-coverage -g -O0"
CPPFLAGS="$CPPFLAGS -DNDEBUG"
COVERAGE="gcov -pabcdf \$(GCDA) \$(BC_GCDA) \$(DC_GCDA)"
COVERAGE="$COVERAGE;\$(RM) -f \$(GEN)*.gc*"
COVERAGE="$COVERAGE;regcovr --html-details --output index.html"
COVERAGE_PREREQS="all test_all"
else
COVERAGE="@echo \"Coverage not generated\""
COVERAGE_PREREQS=""
fi
if [ "$PREFIX" = "" ]; then
PREFIX="/usr/local"
fi
gcc="gcc"
clang="clang"
if [ "$CC" = "" ]; then
CC="c99"
fi
if [ "$HOSTCC" = "" ]; then
HOSTCC="$CC"
fi
contents=$(replace "$contents" "BC_ENABLED" "$bc")
contents=$(replace "$contents" "DC_ENABLED" "$dc")
contents=$(replace "$contents" "LINK" "$link")
contents=$(replace "$contents" "SIGNALS" "$signals")
contents=$(replace "$contents" "HISTORY" "$hist")
contents=$(replace "$contents" "KARATSUBA_LEN" "$karatsuba_len")
contents=$(replace "$contents" "PREFIX" "$PREFIX")
contents=$(replace "$contents" "DESTDIR" "$DESTDIR")
contents=$(replace "$contents" "CFLAGS" "$CFLAGS")
contents=$(replace "$contents" "CPPFLAGS" "$CPPFLAGS")
contents=$(replace "$contents" "LDFLAGS" "$LDFLAGS")
contents=$(replace "$contents" "CC" "$CC")
contents=$(replace "$contents" "HOSTCC" "$HOSTCC")
contents=$(replace "$contents" "COVERAGE" "$COVERAGE")
contents=$(replace "$contents" "COVERAGE_PREREQS" "$COVERAGE_PREREQS")
contents=$(replace "$contents" "EXECUTABLES" "$executables")
contents=$(replace "$contents" "MAIN_EXEC" "$main_exec")
contents=$(replace "$contents" "BC_TEST" "$bc_test")
contents=$(replace "$contents" "DC_TEST" "$dc_test")
contents=$(replace "$contents" "VG_BC_TEST" "$vg_bc_test")
contents=$(replace "$contents" "VG_DC_TEST" "$vg_dc_test")
contents=$(replace "$contents" "TIMECONST_TARGET" "$timeconst_target")
contents=$(replace "$contents" "TIMECONST" "$timeconst")
contents=$(replace "$contents" "TIMECONST_VG_TARGET" "$timeconst_vg_target")
contents=$(replace "$contents" "TIMECONST_VG" "$timeconst_vg")
contents=$(replace "$contents" "KARATSUBA" "$karatsuba")
contents=$(replace "$contents" "KARATSUBA_TEST" "$karatsuba_test")
contents=$(printf '%s' "$contents" | sed -e "s!\n\n!\n!g")
echo "$contents" > "$scriptdir/Makefile"
cd "$scriptdir"
make clean > /dev/null
echo "Testing C compilers..."
libname=$(make libcname)
set +e
make "$libname" > /dev/null 2>&1
err="$?"
if [ "$err" -ne 0 ]; then
usage "\nHOSTCC ($HOSTCC) is not compatible with gcc/clang options"
fi
make > /dev/null 2>&1
err="$?"
if [ "$err" -ne 0 ]; then
usage "\nCC ($HOSTCC) is not compatible with gcc/clang options"
fi