#!/bin/sh # vim: ts=2 sts=2 sw=2 et: progname="$0" cf_log="config.log" usage() { cat <> "${cf_log}" printf "fatal: ${mesg}\n" "$@" exit 1 } msg() { local mesg="$1"; shift printf "configure: ${mesg}\n" "$@" >> "${cf_log}" printf "configure: ${mesg}\n" "$@" } logprint() { local mesg="$1"; shift printf "${mesg}\n" "$@" >> "${cf_log}" } log() { echo "$@" >> "${cf_log}" "$@" } # # Some library functions # need_cmd() { if which $1 >/dev/null 2>&1 then msg "found $1" else die "need $1" fi } # so we don't have to repeat the >/dev/null all the time # also TODO: # strip parameters (ie, 'need_cmd $CC' with CC="gcc -m32" should work) has_cmd() { which $1 >/dev/null 2>&1 } # # Check environment # Well we can expect those to exist, no? # need_cmd uname need_cmd awk need_cmd tr need_cmd readlink # # default host specific values: # host="$(uname -s | tr A-Z a-z)" case "${host}" in linux|*bsd*) cf_prefix="${cf_prefix:-/usr/local}" cf_bindir="${cf_bindir:-${cf_prefix}/bin}" cf_datadir="${cf_datadir:-${cf_prefix}/share}" cf_mandir="${cf_mandir:-${cf_datadir}/man}" cf_man1dir="${cf_man1dir:-${cf_mandir}/man1}" cf_exesuffix="" ;; *) cf_prefix="${cf_prefix:-}" cf_bindir="${cf_bindir:-}" cf_datadir="${cf_datadir:-}" cf_mandir="${cf_mandir:-}" cf_man1dir="${cf_man1dir:-}" cf_exesuffix=".exe" ;; esac # will be set to one if the compiler can generate .d files cf_dynamic_depends=0 # for the default-supported compilers: cf_cflags_gcc="-Wall -Wextra -Werror -Wstrict-aliasing -Wno-attributes" cf_ldflags_gcc="" cf_libs_gcc="-lm" cflags_gcc() { cf_cflags_gcc="${cf_cflags_gcc} $@" } ldflags_gcc() { cf_ldflags_gcc="${cf_ldflags_gcc} $@" } libs_gcc() { cf_libs_gcc="${cf_libs_gcc} $@" } # Let's figure out where we are... cf_wd="${PWD}" cf_log="${cf_wd}/config.log" cf_dir="$(readlink -f "${progname}")" # or should we use the hopefully more reliable basename command? cf_dir="${cf_dir%/*}" if [ "x${cf_dir}" = "x${cf_wd}" ]; then echo "Please run this script in a different directory \ to not overwrite the git working tree." exit 1 fi # execute a command inside $cf_dir indir() { # do it in a subshell so we don't change directory ourselves ( cd "${cf_dir}" && "$@" ) || false } # # Find a compiler... # msg "looking for C compiler..." CC=${CC:-clang} has_cmd "${CC}" || CC=clang has_cmd "${CC}" || CC=gcc has_cmd "${CC}" || CC=cc has_cmd "${CC}" || CC=tcc has_cmd "${CC}" || die "no compiler found" msg 'using CC = %s' "${CC}" # We might add support for different compilers with a different CLI cf_cctype="gcc" if [ "x${CC}" != "xclang" -a "x${CC}" != "gcc" -a "x${CC}" != "g++" ]; then msg "checking compiler type" cf_ccver="$(${CC} -v 2>&1)" [ $? -eq 0 ] || die "Failed to retrieve compiler version info" if (echo "${cf_ccver}" | grep -q '\'); then msg "found compatible compiler" else die "don't know how to use this compiler..." fi fi # Find a preprocessor too msg "looking for a C preprocessor..." CPP=${CPP:-clang-cpp} has_cmd "${CPP}" || CPP=cpp if ! has_cmd "${CPP}"; then msg "no C preprocessor found, trying -E" logprint 'executing the following program with %s' "$CC -E" prog="#define SHOW(X) :X:\nSHOW(THIS WORKS)\n" logprint '%s' "${prog}" if echo "${prog}" | $CC -E - 2>&1 \ | awk '/^:THIS WORKS:$/{ exit(0); } END {exit(1);}'; then msg 'using preprocessor: %s' "$CC -E" CPP="${CC} -E" else fatal "cannot find a working C preprocessor" fi else msg 'using CPP = %s' "${CPP}" fi # Git information - that is, if git is available cf_gitinfo=0 if has_cmd git; then # And provided we're in a git repo: if [ -d "${cf_dir}/.git" ]; then cf_gitinfo=1 msg "reading git info" cf_gitinfo_text="$(indir git describe --always)" fi fi # valgrind? cf_valgrind=0 has_cmd valgrind && cf_valgrind=1 # compiler specific flags: [ "x${CC}" != "xg++" ] && \ cflags_gcc -Wmissing-prototypes -Wstrict-prototypes if [ "x${CC}" = "xclang" ]; then cflags_gcc -Weverything cflags_gcc -Wno-padded cflags_gcc -Wno-format-nonliteral cflags_gcc -Wno-disabled-macro-expansion cflags_gcc -Wno-conversion cflags_gcc -Wno-float-equal cflags_gcc -Wno-unknown-warning-option cflags_gcc -Wno-cast-align fi if [ "x${CC}" != "xtcc" ]; then cflags_gcc -pedantic-errors else cflags_gcc -Wno-pointer-sign -fno-common fi parse_cmdline if [ ${cf_gitinfo} -ne 0 ]; then cflags_gcc '-DGMQCC_GITINFO="${cf_gitinfo_text}"' fi if [ ${cf_valgrind} -eq 0 ]; then cflags_gcc -DNVALGRIND fi # # Put the cflags/ldflags/libs we use into cf_cflags/ldflags/libs # case "${cf_cctype}" in gcc|clang) cf_cflags="${cf_cflags_gcc}" cf_ldflags="${cf_ldflags_gcc}" cf_libs="${cf_libs_gcc}" ;; *) die "compiler type '%s' not handled here!" "${cf_cctype}" esac # # Dependency generation # depgrep() { (echo "${cf_dir}"; $CPP "$@") | awk \ 'BEGIN { getline cf_dir; cf_len=length(cf_dir); } /^#/{ gsub("\"","",$3); if (substr($3,1,cf_len) == cf_dir) print $3; }' \ | sort \ | uniq } # # Makefile generation routines # # executables is an array of variable names used in the makefile to # name an executable; the list of objects is assumed to be # in ${var}_OBJ executables="GMQCC QCVM TESTSUITE PAK" all_c_obj="" add_c_obj() { all_c_obj="${all_c_obj} $@" } print_all_rule() { printf 'all:' for i in ${executables}; do printf ' $(%s)' "${i}" done echo } # create all the object variables: print_objects() { common="ansi.o util.o hash.o stat.o fs.o opts.o conout.o" add_c_obj ${common} gmqcc="main.o utf8.o lexer.o parser.o ftepp.o fold.o" gmqcc="${gmqcc} intrin.o correct.o ast.o ir.o code.o" add_c_obj ${gmqcc} qcvm=exec.o add_c_obj ${qcvm} testsuite=test.o add_c_obj ${testsuite} pak=pak.o add_c_obj ${pak} cat < "${cf_wd}/Makefile"