OILS / configure View on Github | oilshell.org

447 lines, 267 significant
1#!/bin/sh
2#
3# POSIX shell script to detect target system properties required by Oil.
4# Distributed with the source tarball.
5#
6# The only library Oil needs is readline.
7#
8# External utilities used: cc
9#
10# TODO: Should be able to run this from another directory.
11#
12# Other settings: LTO, PGO? Consider moving prefix, LTO, PGO to build and
13# install steps.
14
15TMP=${TMPDIR:-/tmp} # Assume that any system has $TMPDIR set or /tmp exists
16readonly TMP # POSIX sh supports 'readonly'
17
18log() {
19 echo "$0: $@" 1>&2
20}
21
22info() {
23 echo "$0 INFO: $@" 1>&2
24}
25
26die() {
27 echo "$0 ERROR: $@" 1>&2
28 exit 1
29}
30
31show_help() {
32 cat <<'EOF'
33Usage: ./configure [OPTION...]
34
35Detects system settings before a build of Oil.
36
37Installation directories:
38 --prefix=PREFIX Prefix for the bin/ directory [/usr/local]
39 --datarootdir=DATAROOTDIR Prefix for data files, including man page [PREFIX/share]
40
41Optional features:
42 --with-readline Fail unless readline is available.
43 --without-readline Don't compile with readline, even if it's available.
44 The shell won't have any interactive features.
45 --readline=DIR An alternative readline installation to link against
46EOF
47}
48
49# This script roughly follows the GNU Standards
50# https://www.gnu.org/prep/standards/html_node/Configuration.html
51# https://www.gnu.org/prep/standards/html_node/Directory-Variables.html
52#
53# Default installation is /usr/local/bin/oil, but this can be changed with
54# --prefix.
55#
56# While this script only uses a handful of the standard directory variables
57# listed on the above documents, it accepts most of them in the --arg=value
58# form as noops. This helps automated build-systems passing preconfigured
59# sets of arguments to configure oil.
60FLAG_prefix='/usr/local'
61FLAG_datarootdir='' # default initialized after processing flags
62FLAG_with_readline='' # Fail if it's not available.
63FLAG_without_readline='' # Don't even check if it's available
64FLAG_readline=''
65
66# These variables are set by detect_readline and used by echo_cpp and
67# echo_shell_vars
68detected_readline=''
69have_readline=''
70readline_dir=''
71
72parse_flags() {
73 while true; do
74 case "$1" in
75 '')
76 break
77 ;;
78 --help)
79 # TODO: Fill out help
80 show_help
81 exit 0
82 ;;
83
84 --with-readline)
85 FLAG_with_readline=1
86 ;;
87
88 --without-readline)
89 FLAG_without_readline=1
90 ;;
91
92 --readline=*)
93 FLAG_readline="${1#*=}"
94 ;;
95 --readline)
96 if test $# -eq 1; then
97 die "--readline requires an argument"
98 fi
99 shift
100 FLAG_readline=$1
101 ;;
102
103 # TODO: Maybe prefix only needs to be part of the install step? I'm not
104 # sure if we need it for building anything.
105 --prefix=*)
106 FLAG_prefix="${1#*=}"
107 ;;
108 --prefix)
109 if test $# -eq 1; then
110 die "--prefix requires an argument"
111 fi
112 shift
113 FLAG_prefix=$1
114 ;;
115
116 # Following autoconf's spelling of --mandir
117 --datarootdir=*)
118 FLAG_datarootdir="${1#*=}"
119 ;;
120 --datarootdir)
121 if test $# -eq 1; then
122 die "--datarootdir requires an argument"
123 fi
124 shift
125 FLAG_datarootdir=$1
126 ;;
127
128 --with-*|--enable-*)
129 info "Argument '$1' not used by this configure script"
130 ;;
131
132 --build=*|--host=*)
133 info "Argument '$1' not used by this configure script"
134 ;;
135
136 --exec-prefix=*|--bindir=*|--sbindir=*|--libexecdir=*|--sysconfdir=*)
137 info "Argument '$1' not used by this configure script"
138 ;;
139 --sharedstatedir=*|--localstatedir=*|--runstatedir=*)
140 info "Argument '$1' not used by this configure script"
141 ;;
142 --libdir=*|--includedir=*|--oldincludedir=*)
143 info "Argument '$1' not used by this configure script"
144 ;;
145 --datadir=*|--infodir=*|--localedir=*|--mandir=*|--docdir=*)
146 info "Argument '$1' not used by this configure script"
147 ;;
148 --htmldir=*|--dvidir=*|--pdfdir=*|--psdir=*)
149 info "Argument '$1' not used by this configure script"
150 ;;
151
152 *)
153 die "Invalid argument '$1'"
154 ;;
155 esac
156 shift
157 done
158
159 # If not set, fallback to --prefix
160 FLAG_datarootdir=${FLAG_datarootdir:-$FLAG_prefix/share}
161}
162
163# No output file, no logging, no stderr.
164# TODO: Maybe send stdout/stderr to config.log?
165cc_quiet() {
166 cc "$@" -o /dev/null >/dev/null 2>&1
167}
168
169cc_or_die() {
170 if ! cc "$@" >$TMP/cc.log 2>&1; then
171 log "Error running 'cc $@':"
172 cat $TMP/cc.log
173 die "Fatal compile error running feature test"
174 fi
175}
176
177# Check if a given program compiles
178cc_statement() {
179 local pp_var="$1"
180 local prog="$2"
181 local includes="$3"
182
183 cat >$TMP/cc_statement.c <<EOF
184$includes
185int main() {
186 $prog
187}
188EOF
189 # Return exit code of compiler
190 if cc_quiet $TMP/cc_statement.c; then
191 echo "#define $pp_var 1"
192 return 0
193 else
194 return 1
195 fi
196}
197
198# Check if a given library is installed via compilation
199cc_header_file() {
200 local pp_var="$1"
201 local c_lib="$2"
202
203 cc_statement "$pp_var" 'return 0;' "#include <$c_lib>"
204}
205
206detect_readline() {
207 detected_readline=1 # for assertions in echo_shell_vars and echo_cpp
208
209 # User disabled readline
210 if test -n "$FLAG_without_readline"; then
211 # have_readline remains false
212 return
213 fi
214
215 # User requested specific location
216 if test -n "$FLAG_readline"; then
217 if cc_quiet build/detect-readline.c \
218 -L "$FLAG_readline/lib" \
219 -I "$FLAG_readline/include" \
220 -l readline; then
221
222 readline_dir="$FLAG_readline"
223 have_readline=1
224 fi
225 return
226 fi
227
228 # Detect in default location
229 if cc_quiet build/detect-readline.c -l readline; then
230 have_readline=1
231 return
232 fi
233
234 # User requested that it be found
235 if test "$FLAG_with_readline" = 1 && test "$have_readline" != 1; then
236 die 'readline was not detected on the system (--with-readline passed).'
237 fi
238}
239
240echo_shell_vars() {
241 if test "$detected_readline" != 1; then
242 die 'called echo_shell_vars before detecting readline.'
243 fi
244 if test "$have_readline" = 1; then
245 echo 'HAVE_READLINE=1'
246 echo "READLINE_DIR=$readline_dir"
247 else
248 echo 'HAVE_READLINE='
249 # Present a consistent interface to build/ninja-rules-cpp.sh
250 echo 'READLINE_DIR='
251 fi
252 echo "PREFIX=$FLAG_prefix"
253 echo "DATAROOTDIR=$FLAG_datarootdir"
254 if cc_quiet build/detect-cc.c -Wl,--gc-sections; then
255 echo 'STRIP_FLAGS=--gc-sections'
256 elif cc_quiet build/detect-cc.c -Wl,-dead_strip; then
257 echo 'STRIP_FLAGS=-dead_strip'
258 fi
259}
260
261# c.m4 AC_LANG_INT_SAVE
262cc_print_expr() {
263 local c_expr="$1"
264 cat >$TMP/print_expr.c <<EOF
265#include <stdio.h>
266#include <sys/types.h> /* size_t, pid_t */
267
268int main() {
269 printf("%lu", $c_expr);
270}
271EOF
272 cc_or_die -o $TMP/print_expr $TMP/print_expr.c
273 $TMP/print_expr > $TMP/print_expr.out
274}
275
276# Shell note:
277# - local is not POSIX, but most shells have it.
278# C note:
279# - autoconf uses ac_fn_compute_int (in sh) aka AC_COMPUTE_INT (in m4).
280# - it uses different tests when cross compiling.
281# - cross-compiling does binary search?
282# - other one does AC_LANG_INT_SAVE
283# - generates a C program that outputs to conftest.val!
284# - well why not use exit code?
285# - QEMU configure doesn't do any tests
286
287# Hm, don't bother with cross compiling case for now.
288
289# Check if the size of a type is greater than a certain integer.
290check_sizeof() {
291 local pp_var="$1"
292 local c_type="$2"
293 local min_bytes="$3"
294
295 cc_print_expr "sizeof($c_type)"
296
297 local actual_bytes
298 actual_bytes=$(cat $TMP/print_expr.out)
299
300 if test -n "$min_bytes" && test "$actual_bytes" -lt "$min_bytes"; then
301 die "sizeof($c_type) should be at least $min_bytes; got $actual_bytes"
302 fi
303
304 # Echo to stdout!
305 echo "#define $pp_var $actual_bytes"
306}
307
308detect_c_language() {
309 # This is the equivalent of AC_CHECK_SIZEOF(int, 4)
310 check_sizeof SIZEOF_INT 'int' 4
311 check_sizeof SIZEOF_LONG 'long' 4
312 check_sizeof SIZEOF_VOID_P 'void *' 4
313 check_sizeof SIZEOF_SHORT 'short' 2
314 check_sizeof SIZEOF_FLOAT 'float' 4
315 check_sizeof SIZEOF_DOUBLE 'double' 8
316
317 check_sizeof SIZEOF_SIZE_T 'size_t' 4
318
319 # NOTE: This might only be relevant for large file support, which we don't
320 # have.
321 check_sizeof SIZEOF_FPOS_T 'fpos_t' 4
322 check_sizeof SIZEOF_PID_T 'pid_t' 4
323
324 check_sizeof SIZEOF_OFF_T 'off_t' ''
325 # autoconf checks if we have time.h, but the check isn't used. We just
326 # assume it's there.
327 check_sizeof SIZEOF_TIME_T 'time_t' ''
328
329 if cc_statement HAVE_LONG_LONG 'long long x; x = (long long)0;'
330 then
331 check_sizeof SIZEOF_LONG_LONG 'long long' 8
332 fi
333 if cc_statement HAVE_LONG_DOUBLE 'long double x; x = (long double)0;'
334 then
335 check_sizeof SIZEOF_LONG_DOUBLE 'long double' 8
336 fi
337
338 if cc_statement HAVE_C99_BOOL '_Bool x; x = (_Bool)0;'
339 then
340 # NOTE: this is mainly used in ctypes.h, which we might not need.
341 check_sizeof SIZEOF__BOOL '_Bool' 1
342 fi
343 # NOTE: Python also has a check for C99 uintptr_t. Just assume we don't
344 # have it?
345
346 #if cc_statement HAVE_C99_BOOL 'wchar_t x; x = (wchar_t)0;'
347 #then
348 # check_sizeof SIZEOF_WCHAR_T 'wchar_t' 4
349 #fi
350
351 # TODO: Detect header and size.
352 echo '#define HAVE_WCHAR_H 1'
353 echo '#define SIZEOF_WCHAR_T 4'
354
355 cat >$TMP/detect_va_list.c <<EOF
356#include <stdarg.h> /* C89 */
357int main() {
358 va_list list1, list2;
359 list1 = list2;
360}
361EOF
362 if cc_quiet $TMP/detect_va_list.c; then
363 echo '' # not an array
364 else
365 echo '#define VA_LIST_IS_ARRAY 1'
366 fi
367
368 # TODO: are these feature checks really necessary, or can we
369 # strip these out of posixmodule.c entirely?
370 cc_header_file HAVE_PTY_H 'pty.h'
371 cc_header_file HAVE_LIBUTIL_H 'libutil.h'
372 cc_header_file HAVE_UTIL_H 'util.h'
373
374 # TODO: are these feature checks really necessary?
375 cc_statement HAVE_STAT_TV_NSEC \
376 'struct stat st; st.st_mtim.tv_nsec = 1; return 0;' \
377 '#include <sys/stat.h>'
378 cc_statement HAVE_STAT_TV_NSEC2 \
379 'struct stat st; st.st_mtimespec.tv_nsec = 1; return 0;' \
380 '#include <sys/stat.h>'
381}
382
383echo_cpp() {
384 if test "$detected_readline" != 1; then
385 die 'called echo_cpp before detecting readline.'
386 fi
387 # Dev builds can use non-portable clock_gettime()
388 if test -n "$_OIL_DEV"; then
389 echo '#define GC_TIMING 1'
390 log 'Turned on -D GC_TIMING because $_OIL_DEV is set'
391 fi
392
393 if test "$have_readline" = 1; then
394 echo '#define HAVE_READLINE 1'
395 else
396 echo '/* #undef HAVE_READLINE */'
397 fi
398
399 # Check if pwent is callable. E.g. bionic libc (Android) doesn't have it
400 if cc_quiet build/detect-pwent.c; then
401 echo '#define HAVE_PWENT 1'
402 else
403 echo '/* #undef HAVE_PWENT */'
404 fi
405}
406
407# Another way of working: set detected-config.mk ?
408# And set the default target as oil_readline, oil_no_readline, oil_lto,
409# oil_pgo, etc.?
410main() {
411 parse_flags "$@" # sets FLAG_*
412
413 mkdir -p _build
414
415 if ! cc_quiet build/detect-cc.c; then
416 die "Couldn't compile a basic C program (cc not installed?)"
417 fi
418
419 # Sets globals $have_readline and $readline_dir
420 detect_readline
421
422 # Generate configuration for oil-native
423 local cpp_out=_build/detected-cpp-config.h
424 echo_cpp > $cpp_out
425 log "Wrote $cpp_out"
426
427 # Legacy OVM build: shell build actions will 'source
428 # _build/detected-config.sh'. And then adjust flags to compiler (-D, -l,
429 # etc.)
430 local sh_out=_build/detected-config.sh
431
432 echo_shell_vars > $sh_out
433 log "Wrote $sh_out"
434
435 # Fast mode
436 if test -n "$_OIL_DEV"; then
437 return
438 fi
439
440 local c_out=_build/detected-config.h
441 detect_c_language > $c_out
442 log "Wrote $c_out"
443}
444
445if test -z "$_OIL_CONFIGURE_TEST"; then
446 main "$@"
447fi