OILS / configure View on Github | oilshell.org

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