OILS / configure View on Github | oils.pub

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