OILS / configure View on Github | oils.pub

715 lines, 446 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="$(mktemp -d || echo "${TMPDIR:-/tmp}")" # note: mktemp consults $TMPDIR first too
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 features before a build of oils-for-unix.
37
38Usage:
39 ./configure FLAG*
40 ./configure --help
41
42Flags:
43
44 --cxx-for-configure CXX [default 'cc']
45 Use this compiler to detect system features
46
47Installation dirs:
48
49 --prefix PREFIX [default '/usr/local']
50 Prefix for the bin/ directory
51
52 --datarootdir DATAROOTDIR [default $PREFIX/share]
53 Prefix for data files, including man page
54
55Dependencies:
56
57 --with-readline Fail unless readline is available
58 --without-readline Don't compile with readline, even if it's available.
59 The shell won't have any interactive features.
60 --readline DIR An alternative readline installation to link against
61 --without-libc-features Assume no FNM_EXTMATCH, GLOB_PERIOD, *pwent()
62 --with-systemtap-sdt Fail unless systemtap-sdt is available
63 --without-systemtap-sdt Don't compile with systemtap-sdt, even if it's available
64
65EOF
66}
67
68# This script roughly follows the GNU Standards
69# https://www.gnu.org/prep/standards/html_node/Configuration.html
70# https://www.gnu.org/prep/standards/html_node/Directory-Variables.html
71#
72# Default installation is /usr/local/bin/oils-for-unix, but this can be changed with
73# --prefix.
74#
75# While this script only uses a handful of the standard directory variables
76# listed on the above documents, it accepts most of them in the --arg=value
77# form as noops. This helps automated build-systems passing preconfigured
78# sets of arguments to configure oils.
79
80init_flags() {
81 ### Used in tests
82
83 # Quirk: we use a C compiler by default, which seems consistent. We are not
84 # detecting anything about C++.
85 # This is because OLD oils-ref tarball only depends on C. In contrast,
86 # oils-for-unix depends on C++.
87 FLAG_cxx_for_configure=cc
88
89 FLAG_prefix='/usr/local'
90 FLAG_datarootdir='' # default initialized after processing flags
91 FLAG_with_readline='' # Fail if it's not available.
92 FLAG_without_readline='' # Don't even check if it's available
93 FLAG_readline=''
94 FLAG_without_systemtap_sdt='' # Don't even check if it's available
95 FLAG_without_libc_features=''
96}
97
98init_flags # Set GLOBALS
99
100
101# These variables are set by detect_readline and used by echo_cpp and
102# echo_shell_vars
103detected_deps=''
104
105have_readline=''
106readline_dir=''
107have_readline_callback_sigcleanup=''
108have_readline_catch=''
109have_readline_completion_display_matches_hook=''
110have_readline_completion_suppress_append=''
111have_readline_free_history_entry=''
112have_readline_list_funmap_names=''
113have_readline_resize_terminal=''
114
115have_systemtap_sdt=''
116
117# libc
118have_fnm_extmatch=''
119have_glob_period=''
120have_pwent=''
121
122parse_flags() {
123 while true; do
124 case "$1" in
125 '')
126 break
127 ;;
128 --help)
129 show_help
130 exit 0
131 ;;
132
133 --cxx-for-configure=*)
134 FLAG_cxx_for_configure="${1#*=}"
135 ;;
136 --cxx-for-configure)
137 if test $# -eq 1; then
138 die "--cxx-for-configure requires an argument"
139 fi
140 shift
141 FLAG_cxx_for_configure=$1
142 ;;
143
144 --with-readline)
145 FLAG_with_readline=1
146 ;;
147
148 --without-readline)
149 FLAG_without_readline=1
150 ;;
151
152 --readline=*)
153 FLAG_readline="${1#*=}"
154 ;;
155 --readline)
156 if test $# -eq 1; then
157 die "--readline requires an argument"
158 fi
159 shift
160 FLAG_readline=$1
161 ;;
162
163 --without-systemtap-sdt)
164 FLAG_without_systemtap_sdt=1
165 ;;
166
167 --without-libc-features)
168 FLAG_without_libc_features=1
169 ;;
170
171 # TODO: Maybe prefix only needs to be part of the install step? I'm not
172 # sure if we need it for building anything.
173 --prefix=*)
174 FLAG_prefix="${1#*=}"
175 ;;
176 --prefix)
177 if test $# -eq 1; then
178 die "--prefix requires an argument"
179 fi
180 shift
181 FLAG_prefix=$1
182 ;;
183
184 # Following autoconf's spelling of --mandir
185 --datarootdir=*)
186 FLAG_datarootdir="${1#*=}"
187 ;;
188 --datarootdir)
189 if test $# -eq 1; then
190 die "--datarootdir requires an argument"
191 fi
192 shift
193 FLAG_datarootdir=$1
194 ;;
195
196 --with-*|--enable-*)
197 info "Argument '$1' not used by this configure script"
198 ;;
199
200 --build=*|--host=*)
201 info "Argument '$1' not used by this configure script"
202 ;;
203
204 --exec-prefix=*|--bindir=*|--sbindir=*|--libexecdir=*|--sysconfdir=*)
205 info "Argument '$1' not used by this configure script"
206 ;;
207 --sharedstatedir=*|--localstatedir=*|--runstatedir=*)
208 info "Argument '$1' not used by this configure script"
209 ;;
210 --libdir=*|--includedir=*|--oldincludedir=*)
211 info "Argument '$1' not used by this configure script"
212 ;;
213 --datadir=*|--infodir=*|--localedir=*|--mandir=*|--docdir=*)
214 info "Argument '$1' not used by this configure script"
215 ;;
216 --htmldir=*|--dvidir=*|--pdfdir=*|--psdir=*)
217 info "Argument '$1' not used by this configure script"
218 ;;
219
220 *)
221 die "Invalid argument '$1'"
222 ;;
223 esac
224 shift
225 done
226
227 # If not set, fallback to --prefix
228 FLAG_datarootdir=${FLAG_datarootdir:-$FLAG_prefix/share}
229}
230
231# No output file, no logging, no stderr.
232# TODO: Maybe send stdout/stderr to config.log?
233cc_quiet() {
234 "$FLAG_cxx_for_configure" "$@" -o /dev/null >/dev/null 2>&1
235}
236
237cc_or_die() {
238 # Used to detect
239 local log_path=$TMP/cc_or_die.log
240 if ! "$FLAG_cxx_for_configure" "$@" >"$log_path" 2>&1; then
241 log "Error running 'cc $@':"
242 cat "$log_path"
243 die "Fatal compile error running feature test"
244 fi
245}
246
247# Check if a given program compiles
248cc_statement() {
249 local pp_var="$1"
250 local prog="$2"
251 local includes="$3"
252
253 cat >$TMP/cc_statement.c <<EOF
254$includes
255int main() {
256 $prog
257}
258EOF
259 # Return exit code of compiler
260 if cc_quiet $TMP/cc_statement.c; then
261 echo "#define $pp_var 1"
262 return 0
263 else
264 return 1
265 fi
266}
267
268# Check if a given library is installed via compilation
269cc_header_file() {
270 local pp_var="$1"
271 local c_lib="$2"
272
273 cc_statement "$pp_var" 'return 0;' "#include <$c_lib>"
274}
275
276detect_readline() {
277 detected_deps=1 # for assertions in echo_shell_vars and echo_cpp
278
279 # User disabled readline
280 if test -n "$FLAG_without_readline"; then
281 # have_readline remains false
282 return
283 fi
284
285 # User requested specific location
286 if test -n "$FLAG_readline"; then
287 if cc_quiet build/detect-readline.c \
288 -L "$FLAG_readline/lib" \
289 -I "$FLAG_readline/include" \
290 -l readline; then
291
292 readline_dir="$FLAG_readline"
293 have_readline=1
294
295 if cc_quiet build/detect-readline-callback-sigcleanup.c \
296 -L "$FLAG_readline/lib" \
297 -I "$FLAG_readline/include" \
298 -l readline; then
299
300 have_readline_callback_sigcleanup=1
301 fi
302
303 if cc_quiet build/detect-readline-catch.c \
304 -L "$FLAG_readline/lib" \
305 -I "$FLAG_readline/include" \
306 -l readline; then
307
308 have_readline_catch=1
309 fi
310
311 if cc_quiet build/detect-readline-completion-display-matches-hook.c \
312 -L "$FLAG_readline/lib" \
313 -I "$FLAG_readline/include" \
314 -l readline; then
315
316 have_readline_completion_display_matches_hook=1
317 fi
318
319 if cc_quiet build/detect-readline-completion-suppress-append.c \
320 -L "$FLAG_readline/lib" \
321 -I "$FLAG_readline/include" \
322 -l readline; then
323
324 have_readline_completion_suppress_append=1
325 fi
326
327 if cc_quiet build/detect-readline-free-history.c \
328 -L "$FLAG_readline/lib" \
329 -I "$FLAG_readline/include" \
330 -l readline; then
331
332 have_readline_free_history_entry=1
333 fi
334
335 if cc_quiet build/detect-readline-list-funmap-names.c \
336 -L "$FLAG_readline/lib" \
337 -I "$FLAG_readline/include" \
338 -l readline; then
339
340 have_readline_list_funmap_names=1
341 fi
342
343 if cc_quiet build/build/detect-resize-terminal.c \
344 -L "$FLAG_readline/lib" \
345 -I "$FLAG_readline/include" \
346 -l readline; then
347
348 have_readline_resize_terminal=1
349 fi
350 fi
351 return
352 fi
353
354 # Detect in default location
355 if cc_quiet build/detect-readline.c -l readline; then
356 have_readline=1
357 if cc_quiet build/detect-readline-callback-sigcleanup.c -l readline; then
358 have_readline_callback_sigcleanup=1
359 fi
360
361 if cc_quiet build/detect-readline-catch.c -l readline; then
362 have_readline_catch=1
363 fi
364
365 if cc_quiet build/detect-readline-completion-display-matches-hook.c -l readline; then
366 have_readline_completion_display_matches_hook=1
367 fi
368
369 if cc_quiet build/detect-readline-completion-suppress-append.c -l readline; then
370 have_readline_completion_suppress_append=1
371 fi
372
373 if cc_quiet build/detect-readline-free-history.c -l readline; then
374 have_readline_free_history_entry=1
375 fi
376
377 if cc_quiet build/detect-readline-list-funmap-names.c -l readline; then
378 have_readline_list_funmap_names=1
379 fi
380
381 if cc_quiet build/detect-readline-resize-terminal.c -l readline; then
382 have_readline_resize_terminal=1
383 fi
384
385 return
386 fi
387
388 # User requested that it be found
389 if test "$FLAG_with_readline" = 1 && test "$have_readline" != 1; then
390 die 'readline was not detected on the system (--with-readline passed).'
391 fi
392}
393
394detect_systemtap_sdt() {
395 detected_deps=1 # for assertions in echo_shell_vars and echo_cpp
396
397 if test -n "$FLAG_without_systemtap_sdt"; then
398 return
399 fi
400
401 if cc_quiet build/detect-systemtap-sdt.c; then
402 have_systemtap_sdt=1
403 return
404 fi
405}
406
407detect_libc() {
408 if test -n "$FLAG_without_libc_features"; then
409 return
410 fi
411
412 # Check if non-POSIX FNM_EXTMATCH is available
413 if cc_quiet build/detect-fnm-extmatch.c; then
414 have_fnm_extmatch=1
415 fi
416
417 # Check if non-POSIX GLOB_PERIOD is available
418 if cc_quiet build/detect-glob-period.c; then
419 have_glob_period=1
420 fi
421
422 # Check if pwent is callable. E.g. bionic libc (Android) doesn't have it
423 if cc_quiet build/detect-pwent.c; then
424 have_pwent=1
425 fi
426}
427
428echo_shell_vars() {
429 if test "$detected_deps" != 1; then
430 die 'called echo_shell_vars before detecting readline.'
431 fi
432
433 # Present a consistent interface to build/ninja-rules-cpp.sh
434 if test "$have_readline" = 1; then
435 echo 'HAVE_READLINE=1'
436 echo "READLINE_DIR=$readline_dir"
437 else
438 echo 'HAVE_READLINE='
439 echo 'READLINE_DIR='
440 fi
441
442 if test "$have_readline_callback_sigcleanup" = 1; then
443 echo 'HAVE_READLINE_CALLBACK_SIGCLEANUP=1'
444 else
445 echo 'HAVE_READLINE_CALLBACK_SIGCLEANUP=0'
446 fi
447 if test "$have_readline_catch" = 1; then
448 echo 'HAVE_READLINE_CATCH=1'
449 else
450 echo 'HAVE_READLINE_CATCH=0'
451 fi
452 if test "$have_readline_completion_display_matches_hook" = 1; then
453 echo 'HAVE_READLINE_COMPLETION_DISPLAY_MATCHES_HOOK=1'
454 else
455 echo 'HAVE_READLINE_COMPLETION_DISPLAY_MATCHES_HOOK=0'
456 fi
457 if test "$have_readline_completion_suppress_append" = 1; then
458 echo 'HAVE_READLINE_COMPLETION_SUPPRESS_APPEND=1'
459 else
460 echo 'HAVE_READLINE_COMPLETION_SUPPRESS_APPEND=0'
461 fi
462 if test "$have_readline_free_history_entry" = 1; then
463 echo 'HAVE_READLINE_FREE_HISTORY_ENTRY=1'
464 else
465 echo 'HAVE_READLINE_FREE_HISTORY_ENTRY=0'
466 fi
467 if test "$have_readline_list_funmap_names" = 1; then
468 echo 'HAVE_READLINE_LIST_FUNMAP_NAMES=1'
469 else
470 echo 'HAVE_READLINE_LIST_FUNMAP_NAMES=0'
471 fi
472 if test "$have_readline_resize_terminal" = 1; then
473 echo 'HAVE_READLINE_RESIZE_TERMINAL=1'
474 else
475 echo 'HAVE_READLINE_RESIZE_TERMINAL=0'
476 fi
477
478 echo
479
480 echo "PREFIX=$FLAG_prefix"
481 echo "DATAROOTDIR=$FLAG_datarootdir"
482 echo
483
484 if cc_quiet build/detect-cc.c -Wl,--gc-sections; then
485 echo 'STRIP_FLAGS=--gc-sections'
486 elif cc_quiet build/detect-cc.c -Wl,-dead_strip; then
487 echo 'STRIP_FLAGS=-dead_strip'
488 fi
489}
490
491# c.m4 AC_LANG_INT_SAVE
492cc_print_expr() {
493 local c_expr="$1"
494 cat >$TMP/print_expr.c <<EOF
495#include <stdio.h>
496#include <sys/types.h> /* size_t, pid_t */
497
498int main() {
499 printf("%lu", $c_expr);
500}
501EOF
502 cc_or_die -o $TMP/print_expr $TMP/print_expr.c
503 $TMP/print_expr > $TMP/print_expr.out
504}
505
506# Shell note:
507# - local is not POSIX, but most shells have it.
508# C note:
509# - autoconf uses ac_fn_compute_int (in sh) aka AC_COMPUTE_INT (in m4).
510# - it uses different tests when cross compiling.
511# - cross-compiling does binary search?
512# - other one does AC_LANG_INT_SAVE
513# - generates a C program that outputs to conftest.val!
514# - well why not use exit code?
515# - QEMU configure doesn't do any tests
516
517# Hm, don't bother with cross compiling case for now.
518
519# Check if the size of a type is greater than a certain integer.
520check_sizeof() {
521 local pp_var="$1"
522 local c_type="$2"
523 local min_bytes="$3"
524
525 cc_print_expr "sizeof($c_type)"
526
527 local actual_bytes
528 actual_bytes=$(cat $TMP/print_expr.out)
529
530 if test -n "$min_bytes" && test "$actual_bytes" -lt "$min_bytes"; then
531 die "sizeof($c_type) should be at least $min_bytes; got $actual_bytes"
532 fi
533
534 # Echo to stdout!
535 echo "#define $pp_var $actual_bytes"
536}
537
538echo_libc() {
539 # Exported by pyext/libc.c
540 if test "$have_fnm_extmatch" = 1; then
541 echo '#define HAVE_FNM_EXTMATCH 1'
542 else
543 echo '#define HAVE_FNM_EXTMATCH 0'
544 fi
545
546 if test "$have_glob_period" = 1; then
547 echo '#define HAVE_GLOB_PERIOD 1'
548 else
549 echo '#define HAVE_GLOB_PERIOD 0'
550 echo '#define GLOB_PERIOD 0 /* define bit flag to have no effect */'
551 fi
552
553 # Used by cpp/core.cc
554 if test "$have_pwent" = 1; then
555 echo '#define HAVE_PWENT 1'
556 else
557 echo '/* #undef HAVE_PWENT */'
558 fi
559}
560
561# Note: this is only for the OLD oils-ref tarball
562detect_c_language() {
563 echo_libc
564 echo
565
566 # This is the equivalent of AC_CHECK_SIZEOF(int, 4)
567 check_sizeof SIZEOF_INT 'int' 4
568 check_sizeof SIZEOF_LONG 'long' 4
569 check_sizeof SIZEOF_VOID_P 'void *' 4
570 check_sizeof SIZEOF_SHORT 'short' 2
571 check_sizeof SIZEOF_FLOAT 'float' 4
572 check_sizeof SIZEOF_DOUBLE 'double' 8
573
574 check_sizeof SIZEOF_SIZE_T 'size_t' 4
575
576 # NOTE: This might only be relevant for large file support, which we don't
577 # have.
578 check_sizeof SIZEOF_FPOS_T 'fpos_t' 4
579 check_sizeof SIZEOF_PID_T 'pid_t' 4
580
581 check_sizeof SIZEOF_OFF_T 'off_t' ''
582 # autoconf checks if we have time.h, but the check isn't used. We just
583 # assume it's there.
584 check_sizeof SIZEOF_TIME_T 'time_t' ''
585
586 if cc_statement HAVE_LONG_LONG 'long long x; x = (long long)0;'
587 then
588 check_sizeof SIZEOF_LONG_LONG 'long long' 8
589 fi
590 if cc_statement HAVE_LONG_DOUBLE 'long double x; x = (long double)0;'
591 then
592 check_sizeof SIZEOF_LONG_DOUBLE 'long double' 8
593 fi
594
595 if cc_statement HAVE_C99_BOOL '_Bool x; x = (_Bool)0;'
596 then
597 # NOTE: this is mainly used in ctypes.h, which we might not need.
598 check_sizeof SIZEOF__BOOL '_Bool' 1
599 fi
600 # NOTE: Python also has a check for C99 uintptr_t. Just assume we don't
601 # have it?
602
603 #if cc_statement HAVE_C99_BOOL 'wchar_t x; x = (wchar_t)0;'
604 #then
605 # check_sizeof SIZEOF_WCHAR_T 'wchar_t' 4
606 #fi
607
608 # TODO: Detect header and size.
609 echo '#define HAVE_WCHAR_H 1'
610 echo '#define SIZEOF_WCHAR_T 4'
611
612 cat >$TMP/detect_va_list.c <<EOF
613#include <stdarg.h> /* C89 */
614int main() {
615 va_list list1, list2;
616 list1 = list2;
617}
618EOF
619 if cc_quiet $TMP/detect_va_list.c; then
620 echo '' # not an array
621 else
622 echo '#define VA_LIST_IS_ARRAY 1'
623 fi
624
625 # TODO: are these feature checks really necessary, or can we
626 # strip these out of posixmodule.c entirely?
627 cc_header_file HAVE_PTY_H 'pty.h'
628 cc_header_file HAVE_LIBUTIL_H 'libutil.h'
629 cc_header_file HAVE_UTIL_H 'util.h'
630
631 # TODO: are these feature checks really necessary?
632 cc_statement HAVE_STAT_TV_NSEC \
633 'struct stat st; st.st_mtim.tv_nsec = 1; return 0;' \
634 '#include <sys/stat.h>'
635 cc_statement HAVE_STAT_TV_NSEC2 \
636 'struct stat st; st.st_mtimespec.tv_nsec = 1; return 0;' \
637 '#include <sys/stat.h>'
638}
639
640echo_cpp() {
641 if test "$detected_deps" != 1; then
642 die 'called echo_cpp before detecting readline.'
643 fi
644 # Dev builds can use non-portable clock_gettime()
645 if test -n "$_OIL_DEV"; then
646 echo '#define GC_TIMING 1'
647 log 'Turned on -D GC_TIMING because $_OIL_DEV is set'
648 fi
649
650 # Important: HAVE_READLINE is only a SHELL variable, not a preprocessor
651 # variable. This is so _build/oils.sh --without-readline works, not just
652 # ./configure --without-readline.
653
654 # Used by mycpp/probes.h
655 if test "$have_systemtap_sdt" = 1; then
656 echo '#define HAVE_SYSTEMTAP_SDT 1'
657 else
658 echo '/* #undef HAVE_SYSTEMTAP_SDT */'
659 fi
660
661 echo
662
663 # Shared with detect_c_language
664 echo_libc
665}
666
667# Another way of working: set detected-config.mk ?
668# And set the default target as oil_readline, oil_no_readline, oil_lto,
669# oil_pgo, etc.?
670main() {
671 parse_flags "$@" # sets FLAG_*
672
673 mkdir -p _build
674
675 if ! cc_quiet build/detect-cc.c; then
676 die "Couldn't compile a basic C program (cc not installed?)"
677 fi
678
679 # Sets globals $have_readline, $readline_dir and $have_readline_*
680 detect_readline
681
682 detect_libc
683
684 detect_systemtap_sdt
685
686 # Generate configuration for oils-for-unix
687 local cpp_out=_build/detected-cpp-config.h
688 echo_cpp > $cpp_out
689 log "Wrote $cpp_out"
690
691 # Legacy OVM build: shell build actions will 'source
692 # _build/detected-config.sh'. And then adjust flags to compiler (-D, -l,
693 # etc.)
694 local sh_out=_build/detected-config.sh
695
696 echo_shell_vars > $sh_out
697 log "Wrote $sh_out"
698
699 local c_out=_build/detected-config.h
700
701 # Fast mode
702 if test -n "$_OIL_DEV"; then
703 # Do only this subset
704 echo_libc > $c_out
705 log "Wrote $c_out"
706 return
707 fi
708
709 detect_c_language > $c_out
710 log "Wrote $c_out"
711}
712
713if test -z "$_OIL_CONFIGURE_TEST"; then
714 main "$@"
715fi