]> git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - configure
set this where the compiler type is set...
[xonotic/gmqcc.git] / configure
index 56f1233235831f2c1b63310e0f3370463cd89e5e..28bb83a07e9162936b2b04e146007b405c7af4cb 100755 (executable)
--- a/configure
+++ b/configure
@@ -1,7 +1,8 @@
-#!/usr/bin/bash
+#!/bin/sh
 # vim: ts=2 sts=2 sw=2 et:
 
 progname="$0"
+cf_log="config.log"
 
 usage() {
   cat <<EOF
@@ -14,7 +15,7 @@ options:
     --mandir=MANDIR      target of manpages [DATADIR/man]
     --man1dir=MAN1DIR    manual section 1 [MANDIR/man1]
   Environment variables:
-    CC, CFLAGS, CPPFLAGS
+    CC, CPP, CFLAGS, CPPFLAGS
 EOF
   exit 1
 }
@@ -40,15 +41,27 @@ parse_cmdline() {
 # TODO: colors
 die() {
   local mesg="$1"; shift
+  printf "fatal: ${mesg}\n" "$@" >> "${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
 #
@@ -63,7 +76,7 @@ need_cmd() {
 # also TODO:
 #    strip parameters (ie, 'need_cmd $CC' with CC="gcc -m32" should work)
 has_cmd() {
-  which $1 >/dev/null
+  which $1 >/dev/null 2>&1
 }
 
 #
@@ -71,6 +84,7 @@ has_cmd() {
 # Well we can expect those to exist, no?
 #
 need_cmd uname
+need_cmd awk
 need_cmd tr
 need_cmd readlink
 
@@ -97,18 +111,32 @@ case "${host}" in
     ;;
 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)
+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 [[ $cf_dir == $cf_wd ]]; then
+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
@@ -123,19 +151,24 @@ indir() {
 #
 # 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"
+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"
+cf_dynamic_depends=1
 
-if [[ $CC != clang && $CC != gcc && $CC != g++ ]]; then
+if [ "x${CC}" != "xclang" -a "x${CC}" != "gcc" -a "x${CC}" != "g++" ]; then
+  cf_dynamic_depends=0
+  msg "checking compiler type"
   cf_ccver="$(${CC} -v 2>&1)"
-  (( $? )) && die "Failed to retrieve compiler version info"
+  [ $? -eq 0 ] || die "Failed to retrieve compiler version info"
   if (echo "${cf_ccver}" | grep -q '\<clang\|gcc\>'); then
     msg "found compatible compiler"
   else
@@ -143,11 +176,31 @@ if [[ $CC != clang && $CC != gcc && $CC != g++ ]]; then
   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
+  if [ -d "${cf_dir}/.git" ]; then
     cf_gitinfo=1
     msg "reading git info"
     cf_gitinfo_text="$(indir git describe --always)"
@@ -159,32 +212,34 @@ 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)
+[ "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
-  cf_cflags_gcc+=(-Wno-pointer-sign -fno-common)
+  cflags_gcc -Wno-pointer-sign -fno-common
 fi
 
 parse_cmdline
 
-if (( cf_gitinfo )); then
-  cf_cflags_gcc+=(-DGMQCC_GITINFO="\"${cf_gitinfo_text}\"")
+if [ ${cf_gitinfo} -ne 0 ]; then
+  cflags_gcc '-DGMQCC_GITINFO="${cf_gitinfo_text}"'
 fi
 
-if (( ! cf_valgrind )); then
-  cf_cflags_gcc+=(-DNVALGRIND)
+if [ ${cf_valgrind} -eq 0 ]; then
+  cflags_gcc -DNVALGRIND
 fi
 
 #
@@ -192,14 +247,32 @@ fi
 #
 case "${cf_cctype}" in
   gcc|clang)
-    cf_cflags=("${cf_cflags_gcc[@]}")
-    cf_ldflags=("${cf_ldflags_gcc[@]}")
-    cf_libs=("${cf_libs_gcc[@]}")
+    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
 #
@@ -207,46 +280,53 @@ esac
 # 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
+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"
+  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[@]}")
+  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 <<EOF
 GMQCC     = gmqcc${cf_exesuffix}
 QCVM      = qcvm${cf_exesuffix}
 TESTSUITE = testsuite${cf_exesuffix}
 PAK       = pak${cf_exesuffix}
 
-QCVM_OBJ      := ${common[@]} ${qcvm[@]}
-GMQCC_OBJ     := ${common[@]} ${gmqcc[@]}
-TESTSUITE_OBJ := ${common[@]} ${testsuite[@]}
-PAK_OBJ       := ${common[@]} ${pak[@]}
+QCVM_OBJ      := ${common} ${qcvm}
+GMQCC_OBJ     := ${common} ${gmqcc}
+TESTSUITE_OBJ := ${common} ${testsuite}
+PAK_OBJ       := ${common} ${pak}
 
 EOF
   printf 'ALL_PROGRAMS ='
-  for i in "${executables[@]}"; do
-    printf ' $(%s)' "$i"
+  for i in ${executables}; do
+    printf ' $(%s)' "${i}"
   done
   echo
 }
@@ -256,19 +336,19 @@ EOF
 # on special vars like - also generate the .d files
 print_targets() {
   # generate object rules to get the right path: $cf_dir
-  for obj in "${all_c_obj[@]}"; do
+  for obj in ${all_c_obj}; do
     local c_src="${cf_dir}/${obj%.o}.c"
     local d_inc="${obj}.d"
     echo "${obj}: ${c_src}"
     printf '\t$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ "%s"' "${c_src}"
-    if [[ $cf_cctype == gcc ]]; then
+    if [ "x$cf_cctype" == "xgcc" ]; then
       printf ' -MMD -MF "%s" -MT $@\n' "${d_inc}"
     else
       echo
     fi
   done
 
-  for exe in "${executables[@]}"; do
+  for exe in ${executables}; do
     echo "\$(${exe}): \$(${exe}_OBJ)"
     printf '\t$(CC) $(LDFLAGS) -o $(%s) $(%s_OBJ) $(LIBS)\n' "${exe}" "${exe}"
   done
@@ -285,9 +365,9 @@ echo "Generating Makefile"
   cat <<EOF
 CC      = ${CC}
 
-CFLAGS  = ${CFLAGS}  ${cf_cflags[@]}
-LDFLAGS = ${LDFLAGS} ${cf_ldflags[@]}
-LIBS    = ${LIBS}    ${cf_libs[@]}
+CFLAGS  = ${CFLAGS}  ${cf_cflags}
+LDFLAGS = ${LDFLAGS} ${cf_ldflags}
+LIBS    = ${LIBS}    ${cf_libs}
 
 SRCDIR = "${cf_dir}"
 CFGDIR = "${cf_wd}"
@@ -317,5 +397,17 @@ EOF
   print_targets
 
   # include dependency files too
-  echo "-include *.o.d"
+  echo
+  echo '# Dependency rules'
+  if [ ${cf_dynamic_depends} -ne 0 ]; then
+    echo "-include *.o.d"
+  else
+    for obj in ${all_c_obj}; do
+      src="${obj%.o}.c"
+      logprint 'generating dependencies for: %s' "${src}"
+      deps=$(depgrep "${cf_dir}/${src}" | tr "\n" " ")
+      logprint 'found: %s' "${deps}"
+      printf '%s: %s\n' "${obj}" "${cf_dir}/${src} ${deps}"
+    done
+  fi
 ) > "${cf_wd}/Makefile"