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