OILS / configure View on Github | oilshell.org

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