]> git.xonotic.org Git - xonotic/gmqcc.git/blob - configure
ordering it this way seems better
[xonotic/gmqcc.git] / configure
1 #!/usr/bin/bash
2 # vim: ts=2 sts=2 sw=2 et:
3
4 progname="$0"
5
6 usage() {
7   cat <<EOF
8 ${progname} [options]
9 options:
10   Target directories:
11     --prefix=PREFIX      change the install prefix [/usr/local]
12     --bindir=BINDIR      target of executables [PREFIX/bin]
13     --datadir=DATADIR    target of additional data [PREFIX/share]
14     --mandir=MANDIR      target of manpages [DATADIR/man]
15     --man1dir=MAN1DIR    manual section 1 [MANDIR/man1]
16   Environment variables:
17     CC, CFLAGS, CPPFLAGS
18 EOF
19   exit 1
20 }
21
22 parse_cmdline() {
23   while [ $# -ge 1 ]; do
24     case "$1" in
25       --prefix=*)  cf_prefix="${1#--prefix=}" ;;
26       --bindir=*)  cf_bindir="${1#--bindir=}" ;;
27       --datadir=*) cf_datadir="${1#--datadir=}" ;;
28       --mandir=*)  cf_mandir="${1#--mandir=}"   ;;
29       --man1dir=*) cf_man1dir="${1#--man1dir=}" ;;
30       -h|--help) usage ;;
31       *)
32         echo "Unknown parameter: $1"
33         usage
34         ;;
35     esac
36     shift
37   done
38 }
39
40 # TODO: colors
41 die() {
42   local mesg="$1"; shift
43   printf "fatal: ${mesg}\n" "$@"
44   exit 1
45 }
46
47 msg() {
48   local mesg="$1"; shift
49   printf "configure: ${mesg}\n" "$@"
50 }
51
52 #
53 # Some library functions
54 #
55 need_cmd() {
56   if which $1 >/dev/null 2>&1
57   then msg "found $1"
58   else die "need $1"
59   fi
60 }
61
62 # so we don't have to repeat the >/dev/null all the time
63 # also TODO:
64 #    strip parameters (ie, 'need_cmd $CC' with CC="gcc -m32" should work)
65 has_cmd() {
66   which $1 >/dev/null
67 }
68
69 #
70 # Check environment
71 # Well we can expect those to exist, no?
72 #
73 need_cmd uname
74 need_cmd tr
75 need_cmd readlink
76
77 #
78 # default host specific values:
79 #
80 host="$(uname -s | tr A-Z a-z)"
81 case "${host}" in
82   linux|*bsd*)
83     cf_prefix="${cf_prefix:-/usr/local}"
84     cf_bindir="${cf_bindir:-${cf_prefix}/bin}"
85     cf_datadir="${cf_datadir:-${cf_prefix}/share}"
86     cf_mandir="${cf_mandir:-${cf_datadir}/man}"
87     cf_man1dir="${cf_man1dir:-${cf_mandir}/man1}"
88     cf_exesuffix=""
89     ;;
90   *)
91     cf_prefix="${cf_prefix:-}"
92     cf_bindir="${cf_bindir:-}"
93     cf_datadir="${cf_datadir:-}"
94     cf_mandir="${cf_mandir:-}"
95     cf_man1dir="${cf_man1dir:-}"
96     cf_exesuffix=".exe"
97     ;;
98 esac
99
100 # for the default-supported compilers:
101 cf_cflags_gcc=(-Wall -Wextra -Werror -Wstrict-aliasing -Wno-attributes)
102 cf_ldflags_gcc=()
103 cf_libs_gcc=(-lm)
104
105 # Let's figure out where we are...
106 cf_wd="${PWD}"
107 cf_dir="$(readlink -f "${progname}")"
108 # or should we use the hopefully more reliable basename command?
109 cf_dir="${cf_dir%/*}"
110
111 if [[ $cf_dir == $cf_wd ]]; then
112   echo "Please run this script in a different directory \
113 to not overwrite the git working tree."
114   exit 1
115 fi
116
117 # execute a command inside $cf_dir
118 indir() {
119   # do it in a subshell so we don't change directory ourselves
120   ( cd "${cf_dir}" && "$@" ) || false
121 }
122
123 #
124 # Find a compiler...
125 #
126 CC=${CC:-clang}
127 has_cmd "${CC}" || CC=clang
128 has_cmd "${CC}" || CC=gcc
129 has_cmd "${CC}" || CC=cc
130 has_cmd "${CC}" || CC=tcc
131 has_cmd "${CC}" || die "No compiler found"
132
133 # We might add support for different compilers with a different CLI
134 cf_cctype="gcc"
135
136 if [[ $CC != clang && $CC != gcc && $CC != g++ ]]; then
137   cf_ccver="$(${CC} -v 2>&1)"
138   (( $? )) && die "Failed to retrieve compiler version info"
139   if (echo "${cf_ccver}" | grep -q '\<clang\|gcc\>'); then
140     msg "found compatible compiler"
141   else
142     die "don't know how to use this compiler..."
143   fi
144 fi
145
146 # Git information - that is, if git is available
147 cf_gitinfo=0
148 if has_cmd git; then
149   # And provided we're in a git repo:
150   if [[ -d "${cf_dir}/.git" ]]; then
151     cf_gitinfo=1
152     msg "reading git info"
153     cf_gitinfo_text="$(indir git describe --always)"
154   fi
155 fi
156
157 # valgrind?
158 cf_valgrind=0
159 has_cmd valgrind && cf_valgrind=1
160
161 # compiler specific flags:
162 [[ $CC != g++ ]] && cf_cflags_gcc+=(-Wmissing-prototypes -Wstrict-prototypes)
163 [[ $CC = clang ]] && \
164   cf_cflags_gcc+=(
165     -Weverything
166     -Wno-padded
167     -Wno-format-nonliteral
168     -Wno-disabled-macro-expansion
169     -Wno-conversion
170     -Wno-float-equal
171     -Wno-unknown-warning-option
172     -Wno-cast-align)
173
174 if [[ $CC != tcc ]]; then
175   cf_cflags_gcc+=(-pedantic-errors)
176 else
177   cf_cflags_gcc+=(-Wno-pointer-sign -fno-common)
178 fi
179
180 parse_cmdline
181
182 if (( cf_gitinfo )); then
183   cf_cflags_gcc+=(-DGMQCC_GITINFO="\"${cf_gitinfo_text}\"")
184 fi
185
186 if (( ! cf_valgrind )); then
187   cf_cflags_gcc+=(-DNVALGRIND)
188 fi
189
190 #
191 # Put the cflags/ldflags/libs we use into cf_cflags/ldflags/libs
192 #
193 case "${cf_cctype}" in
194   gcc|clang)
195     cf_cflags=("${cf_cflags_gcc[@]}")
196     cf_ldflags=("${cf_ldflags_gcc[@]}")
197     cf_libs=("${cf_libs_gcc[@]}")
198     ;;
199   *)
200     die "compiler type '%s' not handled here!" "${cf_cctype}"
201 esac
202
203 #
204 # Makefile generation routines
205 #
206
207 # executables is an array of variable names used in the makefile to
208 # name an executable; the list of objects is assumed to be
209 # in ${var}_OBJ
210 executables=(GMQCC QCVM TESTSUITE PAK)
211 all_c_obj=() # filled by print_objects
212 print_all_rule() {
213   printf 'all:'
214   for i in "${executables[@]}"; do
215     printf ' $(%s)' "$i"
216   done
217   echo
218 }
219
220 # create all the object variables:
221 print_objects() {
222   local common=(ansi.o util.o hash.o stat.o fs.o opts.o conout.o)
223     all_c_obj+=("${common[@]}")
224   local gmqcc=(main.o utf8.o
225                lexer.o parser.o ftepp.o
226                fold.o intrin.o correct.o
227                ast.o ir.o code.o)
228     all_c_obj+=("${gmqcc[@]}")
229   local qcvm=(exec.o)
230     all_c_obj+=("${qcvm[@]}")
231   local testsuite=(test.o)
232     all_c_obj+=("${testsuite[@]}")
233   local pak=(pak.o)
234     all_c_obj+=("${pak[@]}")
235   cat <<EOF
236 GMQCC     = gmqcc${cf_exesuffix}
237 QCVM      = qcvm${cf_exesuffix}
238 TESTSUITE = testsuite${cf_exesuffix}
239 PAK       = pak${cf_exesuffix}
240
241 QCVM_OBJ      := ${common[@]} ${qcvm[@]}
242 GMQCC_OBJ     := ${common[@]} ${gmqcc[@]}
243 TESTSUITE_OBJ := ${common[@]} ${testsuite[@]}
244 PAK_OBJ       := ${common[@]} ${pak[@]}
245
246 EOF
247   printf 'ALL_PROGRAMS ='
248   for i in "${executables[@]}"; do
249     printf ' $(%s)' "$i"
250   done
251   echo
252 }
253
254 # generate the commands used to build objects and executables
255 # in a way that works with both BSD make and gmake by not relying
256 # on special vars like - also generate the .d files
257 print_targets() {
258   # generate object rules to get the right path: $cf_dir
259   for obj in "${all_c_obj[@]}"; do
260     local c_src="${cf_dir}/${obj%.o}.c"
261     local d_inc="${obj}.d"
262     echo "${obj}: ${c_src}"
263     echo $'\t'"\$(CC) \$(CFLAGS) \$(CPPFLAGS) -c -o \$@ \"${c_src}\" -MMD -MF \"${d_inc}\" -MT \$@"
264   done
265
266   for exe in "${executables[@]}"; do
267     echo "\$(${exe}): \$(${exe}_OBJ)"
268     echo $'\t'"\$(CC) \$(LDFLAGS) -o \$(${exe}) \$(${exe}_OBJ) \$(LIBS)"
269   done
270 }
271
272 #
273 # Now generate our output file
274 #
275 echo "Generating Makefile"
276 ( cd "${cf_dir}"
277
278   # First: cflags and directories
279
280   cat <<EOF
281 CC      = ${CC}
282
283 CFLAGS  = ${CFLAGS}  ${cf_cflags[@]}
284 LDFLAGS = ${LDFLAGS} ${cf_ldflags[@]}
285 LIBS    = ${LIBS}    ${cf_libs[@]}
286
287 SRCDIR = "${cf_dir}"
288 CFGDIR = "${cf_wd}"
289
290 PREFIX  = ${cf_prefix}
291 BINDIR  = ${cf_bindir}
292 DATADIR = ${cf_datadir}
293 MANDIR  = ${cf_mandir}
294 MAN1DIR = ${cf_man1dir}
295 EOF
296   echo
297
298   # now all object variables
299   print_objects
300   echo
301
302   # the all rule to include all executables
303   print_all_rule
304
305   # Now the Makefile.in
306   echo "# Makefile.in contents:"
307   echo
308   cat Makefile.in
309   echo
310
311   # all the targets and how to build them
312   print_targets
313
314   # include dependency files too
315   echo "-include *.o.d"
316 ) > "${cf_wd}/Makefile"