]> git.xonotic.org Git - xonotic/gmqcc.git/blob - configure
shellification...
[xonotic/gmqcc.git] / configure
1 #!/bin/sh
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 cflags_gcc() {
106   cf_cflags_gcc="${cf_cflags_gcc} $@"
107 }
108 ldflags_gcc() {
109   cf_ldflags_gcc="${cf_ldflags_gcc} $@"
110 }
111 libs_gcc() {
112   cf_libs_gcc="${cf_libs_gcc} $@"
113 }
114
115 # Let's figure out where we are...
116 cf_wd="${PWD}"
117 cf_dir="$(readlink -f "${progname}")"
118 # or should we use the hopefully more reliable basename command?
119 cf_dir="${cf_dir%/*}"
120
121 if [ "x${cf_dir}" = "x${cf_wd}" ]; then
122   echo "Please run this script in a different directory \
123 to not overwrite the git working tree."
124   exit 1
125 fi
126
127 # execute a command inside $cf_dir
128 indir() {
129   # do it in a subshell so we don't change directory ourselves
130   ( cd "${cf_dir}" && "$@" ) || false
131 }
132
133 #
134 # Find a compiler...
135 #
136 CC=${CC:-clang}
137 has_cmd "${CC}" || CC=clang
138 has_cmd "${CC}" || CC=gcc
139 has_cmd "${CC}" || CC=cc
140 has_cmd "${CC}" || CC=tcc
141 has_cmd "${CC}" || die "No compiler found"
142
143 # We might add support for different compilers with a different CLI
144 cf_cctype="gcc"
145
146 if [ "x${CC}" != "xclang" -a "x${CC}" != "gcc" -a "x${CC}" != "g++" ]; then
147   cf_ccver="$(${CC} -v 2>&1)"
148   [ $? -eq 0 ] || die "Failed to retrieve compiler version info"
149   if (echo "${cf_ccver}" | grep -q '\<clang\|gcc\>'); then
150     msg "found compatible compiler"
151   else
152     die "don't know how to use this compiler..."
153   fi
154 fi
155
156 # Git information - that is, if git is available
157 cf_gitinfo=0
158 if has_cmd git; then
159   # And provided we're in a git repo:
160   if [ -d "${cf_dir}/.git" ]; then
161     cf_gitinfo=1
162     msg "reading git info"
163     cf_gitinfo_text="$(indir git describe --always)"
164   fi
165 fi
166
167 # valgrind?
168 cf_valgrind=0
169 has_cmd valgrind && cf_valgrind=1
170
171 # compiler specific flags:
172 [ "x${CC}" != "xg++" ] && \
173   cflags_gcc -Wmissing-prototypes -Wstrict-prototypes
174
175 if [ "x${CC}" = "xclang" ]; then
176   cflags_gcc -Weverything
177   cflags_gcc -Wno-padded
178   cflags_gcc -Wno-format-nonliteral
179   cflags_gcc -Wno-disabled-macro-expansion
180   cflags_gcc -Wno-conversion
181   cflags_gcc -Wno-float-equal
182   cflags_gcc -Wno-unknown-warning-option
183   cflags_gcc -Wno-cast-align
184 fi
185
186 if [ "x${CC}" != "xtcc" ]; then
187   cflags_gcc -pedantic-errors
188 else
189   cflags_gcc -Wno-pointer-sign -fno-common
190 fi
191
192 parse_cmdline
193
194 if [ ${cf_gitinfo} -ne 0 ]; then
195   cflags_gcc '-DGMQCC_GITINFO="${cf_gitinfo_text}"'
196 fi
197
198 if [ ${cf_valgrind} -eq 0 ]; then
199   cflags_gcc -DNVALGRIND
200 fi
201
202 #
203 # Put the cflags/ldflags/libs we use into cf_cflags/ldflags/libs
204 #
205 case "${cf_cctype}" in
206   gcc|clang)
207     cf_cflags="${cf_cflags_gcc}"
208     cf_ldflags="${cf_ldflags_gcc}"
209     cf_libs="${cf_libs_gcc}"
210     ;;
211   *)
212     die "compiler type '%s' not handled here!" "${cf_cctype}"
213 esac
214
215 #
216 # Makefile generation routines
217 #
218
219 # executables is an array of variable names used in the makefile to
220 # name an executable; the list of objects is assumed to be
221 # in ${var}_OBJ
222 executables="GMQCC QCVM TESTSUITE PAK"
223 all_c_obj=""
224 add_c_obj() {
225   all_c_obj="${all_c_obj} $@"
226 }
227
228 print_all_rule() {
229   printf 'all:'
230   for i in ${executables}; do
231     printf ' $(%s)' "${i}"
232   done
233   echo
234 }
235
236 # create all the object variables:
237 print_objects() {
238   common="ansi.o util.o hash.o stat.o fs.o opts.o conout.o"
239   add_c_obj ${common}
240
241   gmqcc="main.o utf8.o lexer.o parser.o ftepp.o fold.o"
242   gmqcc="${gmqcc} intrin.o correct.o ast.o ir.o code.o"
243   add_c_obj ${gmqcc}
244
245   qcvm=exec.o
246   add_c_obj ${qcvm}
247
248   testsuite=test.o
249   add_c_obj ${testsuite}
250
251   pak=pak.o
252   add_c_obj ${pak}
253
254   cat <<EOF
255 GMQCC     = gmqcc${cf_exesuffix}
256 QCVM      = qcvm${cf_exesuffix}
257 TESTSUITE = testsuite${cf_exesuffix}
258 PAK       = pak${cf_exesuffix}
259
260 QCVM_OBJ      := ${common} ${qcvm}
261 GMQCC_OBJ     := ${common} ${gmqcc}
262 TESTSUITE_OBJ := ${common} ${testsuite}
263 PAK_OBJ       := ${common} ${pak}
264
265 EOF
266   printf 'ALL_PROGRAMS ='
267   for i in ${executables}; do
268     printf ' $(%s)' "${i}"
269   done
270   echo
271 }
272
273 # generate the commands used to build objects and executables
274 # in a way that works with both BSD make and gmake by not relying
275 # on special vars like - also generate the .d files
276 print_targets() {
277   # generate object rules to get the right path: $cf_dir
278   for obj in ${all_c_obj}; do
279     local c_src="${cf_dir}/${obj%.o}.c"
280     local d_inc="${obj}.d"
281     echo "${obj}: ${c_src}"
282     printf '\t$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ "%s"' "${c_src}"
283     if [ "x$cf_cctype" == "xgcc" ]; then
284       printf ' -MMD -MF "%s" -MT $@\n' "${d_inc}"
285     else
286       echo
287     fi
288   done
289
290   for exe in ${executables}; do
291     echo "\$(${exe}): \$(${exe}_OBJ)"
292     printf '\t$(CC) $(LDFLAGS) -o $(%s) $(%s_OBJ) $(LIBS)\n' "${exe}" "${exe}"
293   done
294 }
295
296 #
297 # Now generate our output file
298 #
299 echo "Generating Makefile"
300 ( cd "${cf_dir}"
301
302   # First: cflags and directories
303
304   cat <<EOF
305 CC      = ${CC}
306
307 CFLAGS  = ${CFLAGS}  ${cf_cflags}
308 LDFLAGS = ${LDFLAGS} ${cf_ldflags}
309 LIBS    = ${LIBS}    ${cf_libs}
310
311 SRCDIR = "${cf_dir}"
312 CFGDIR = "${cf_wd}"
313
314 PREFIX  = ${cf_prefix}
315 BINDIR  = ${cf_bindir}
316 DATADIR = ${cf_datadir}
317 MANDIR  = ${cf_mandir}
318 MAN1DIR = ${cf_man1dir}
319 EOF
320   echo
321
322   # now all object variables
323   print_objects
324   echo
325
326   # the all rule to include all executables
327   print_all_rule
328
329   # Now the Makefile.in
330   echo "# Makefile.in contents:"
331   echo
332   cat Makefile.in
333   echo
334
335   # all the targets and how to build them
336   print_targets
337
338   # include dependency files too
339   echo "-include *.o.d"
340 ) > "${cf_wd}/Makefile"