#!/usr/bin/bash # vim: ts=2 sts=2 sw=2 et: progname="$0" usage() { cat </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 } # # Check environment # Well we can expect those to exist, no? # need_cmd uname 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 # for the default-supported compilers: cf_cflags_gcc=(-Wall -Wextra -Werror -Wstrict-aliasing -Wno-attributes) cf_ldflags_gcc=() cf_libs_gcc=(-lm) # Let's figure out where we are... cf_wd="${PWD}" cf_dir="$(readlink -f "${progname}")" # or should we use the hopefully more reliable basename command? cf_dir="${cf_dir%/*}" if [[ $cf_dir == $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... # 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" # We might add support for different compilers with a different CLI cf_cctype="gcc" if [[ $CC != clang && $CC != gcc && $CC != g++ ]]; then cf_ccver="$(${CC} -v 2>&1)" (( $? )) && 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 # 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: [[ $CC != g++ ]] && cf_cflags_gcc+=(-Wmissing-prototypes -Wstrict-prototypes) [[ $CC = clang ]] && \ cf_cflags_gcc+=( -Weverything -Wno-padded -Wno-format-nonliteral -Wno-disabled-macro-expansion -Wno-conversion -Wno-float-equal -Wno-unknown-warning-option -Wno-cast-align) if [[ $CC != tcc ]]; then cf_cflags_gcc+=(-pedantic-errors) else cf_cflags_gcc+=(-Wno-pointer-sign -fno-common) fi parse_cmdline if (( cf_gitinfo )); then cf_cflags_gcc+=(-DGMQCC_GITINFO="\"${cf_gitinfo_text}\"") fi if (( ! cf_valgrind )); then cf_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 # # 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=() # filled by print_objects print_all_rule() { printf 'all:' for i in "${executables[@]}"; do printf ' $(%s)' "$i" done echo } # create all the object variables: print_objects() { local common=(ansi.o util.o hash.o stat.o fs.o opts.o conout.o) all_c_obj+=("${common[@]}") local gmqcc=(main.o utf8.o lexer.o parser.o ftepp.o fold.o intrin.o correct.o ast.o ir.o code.o) all_c_obj+=("${gmqcc[@]}") local qcvm=(exec.o) all_c_obj+=("${qcvm[@]}") local testsuite=(test.o) all_c_obj+=("${testsuite[@]}") local pak=(pak.o) all_c_obj+=("${pak[@]}") cat < "${cf_wd}/Makefile"