OILS / configure View on Github | oils.pub

701 lines, 432 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-entry.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-entry.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 echo
443
444 echo "PREFIX=$FLAG_prefix"
445 echo "DATAROOTDIR=$FLAG_datarootdir"
446 echo
447
448 if cc_quiet build/detect-cc.c -Wl,--gc-sections; then
449 echo 'STRIP_FLAGS=--gc-sections'
450 elif cc_quiet build/detect-cc.c -Wl,-dead_strip; then
451 echo 'STRIP_FLAGS=-dead_strip'
452 fi
453}
454
455# c.m4 AC_LANG_INT_SAVE
456cc_print_expr() {
457 local c_expr="$1"
458 cat >$TMP/print_expr.c <<EOF
459#include <stdio.h>
460#include <sys/types.h> /* size_t, pid_t */
461
462int main() {
463 printf("%lu", $c_expr);
464}
465EOF
466 cc_or_die -o $TMP/print_expr $TMP/print_expr.c
467 $TMP/print_expr > $TMP/print_expr.out
468}
469
470# Shell note:
471# - local is not POSIX, but most shells have it.
472# C note:
473# - autoconf uses ac_fn_compute_int (in sh) aka AC_COMPUTE_INT (in m4).
474# - it uses different tests when cross compiling.
475# - cross-compiling does binary search?
476# - other one does AC_LANG_INT_SAVE
477# - generates a C program that outputs to conftest.val!
478# - well why not use exit code?
479# - QEMU configure doesn't do any tests
480
481# Hm, don't bother with cross compiling case for now.
482
483# Check if the size of a type is greater than a certain integer.
484check_sizeof() {
485 local pp_var="$1"
486 local c_type="$2"
487 local min_bytes="$3"
488
489 cc_print_expr "sizeof($c_type)"
490
491 local actual_bytes
492 actual_bytes=$(cat $TMP/print_expr.out)
493
494 if test -n "$min_bytes" && test "$actual_bytes" -lt "$min_bytes"; then
495 die "sizeof($c_type) should be at least $min_bytes; got $actual_bytes"
496 fi
497
498 # Echo to stdout!
499 echo "#define $pp_var $actual_bytes"
500}
501
502echo_libc() {
503 # Exported by pyext/libc.c
504 if test "$have_fnm_extmatch" = 1; then
505 echo '#define HAVE_FNM_EXTMATCH 1'
506 else
507 echo '#define HAVE_FNM_EXTMATCH 0'
508 fi
509
510 if test "$have_glob_period" = 1; then
511 echo '#define HAVE_GLOB_PERIOD 1'
512 else
513 echo '#define HAVE_GLOB_PERIOD 0'
514 echo '#define GLOB_PERIOD 0 /* define bit flag to have no effect */'
515 fi
516
517 # Used by cpp/core.cc
518 if test "$have_pwent" = 1; then
519 echo '#define HAVE_PWENT 1'
520 else
521 echo '/* #undef HAVE_PWENT */'
522 fi
523}
524
525# Note: this is only for the OLD oils-ref tarball
526detect_c_language() {
527 echo_libc
528 echo
529
530 # This is the equivalent of AC_CHECK_SIZEOF(int, 4)
531 check_sizeof SIZEOF_INT 'int' 4
532 check_sizeof SIZEOF_LONG 'long' 4
533 check_sizeof SIZEOF_VOID_P 'void *' 4
534 check_sizeof SIZEOF_SHORT 'short' 2
535 check_sizeof SIZEOF_FLOAT 'float' 4
536 check_sizeof SIZEOF_DOUBLE 'double' 8
537
538 check_sizeof SIZEOF_SIZE_T 'size_t' 4
539
540 # NOTE: This might only be relevant for large file support, which we don't
541 # have.
542 check_sizeof SIZEOF_FPOS_T 'fpos_t' 4
543 check_sizeof SIZEOF_PID_T 'pid_t' 4
544
545 check_sizeof SIZEOF_OFF_T 'off_t' ''
546 # autoconf checks if we have time.h, but the check isn't used. We just
547 # assume it's there.
548 check_sizeof SIZEOF_TIME_T 'time_t' ''
549
550 if cc_statement HAVE_LONG_LONG 'long long x; x = (long long)0;'
551 then
552 check_sizeof SIZEOF_LONG_LONG 'long long' 8
553 fi
554 if cc_statement HAVE_LONG_DOUBLE 'long double x; x = (long double)0;'
555 then
556 check_sizeof SIZEOF_LONG_DOUBLE 'long double' 8
557 fi
558
559 if cc_statement HAVE_C99_BOOL '_Bool x; x = (_Bool)0;'
560 then
561 # NOTE: this is mainly used in ctypes.h, which we might not need.
562 check_sizeof SIZEOF__BOOL '_Bool' 1
563 fi
564 # NOTE: Python also has a check for C99 uintptr_t. Just assume we don't
565 # have it?
566
567 #if cc_statement HAVE_C99_BOOL 'wchar_t x; x = (wchar_t)0;'
568 #then
569 # check_sizeof SIZEOF_WCHAR_T 'wchar_t' 4
570 #fi
571
572 # TODO: Detect header and size.
573 echo '#define HAVE_WCHAR_H 1'
574 echo '#define SIZEOF_WCHAR_T 4'
575
576 cat >$TMP/detect_va_list.c <<EOF
577#include <stdarg.h> /* C89 */
578int main() {
579 va_list list1, list2;
580 list1 = list2;
581}
582EOF
583 if cc_quiet $TMP/detect_va_list.c; then
584 echo '' # not an array
585 else
586 echo '#define VA_LIST_IS_ARRAY 1'
587 fi
588
589 # TODO: are these feature checks really necessary, or can we
590 # strip these out of posixmodule.c entirely?
591 cc_header_file HAVE_PTY_H 'pty.h'
592 cc_header_file HAVE_LIBUTIL_H 'libutil.h'
593 cc_header_file HAVE_UTIL_H 'util.h'
594
595 # TODO: are these feature checks really necessary?
596 cc_statement HAVE_STAT_TV_NSEC \
597 'struct stat st; st.st_mtim.tv_nsec = 1; return 0;' \
598 '#include <sys/stat.h>'
599 cc_statement HAVE_STAT_TV_NSEC2 \
600 'struct stat st; st.st_mtimespec.tv_nsec = 1; return 0;' \
601 '#include <sys/stat.h>'
602}
603
604echo_cpp() {
605 if test "$detected_deps" != 1; then
606 die 'called echo_cpp before detecting readline.'
607 fi
608 # Dev builds can use non-portable clock_gettime()
609 if test -n "$_OIL_DEV"; then
610 echo '#define GC_TIMING 1'
611 log 'Turned on -D GC_TIMING because $_OIL_DEV is set'
612 fi
613
614 # Important: HAVE_READLINE is only a SHELL variable, not a preprocessor
615 # variable. This is so _build/oils.sh --without-readline works, not just
616 # ./configure --without-readline.
617
618 if test "$have_readline_callback_sigcleanup" = 1; then
619 echo '#define HAVE_READLINE_CALLBACK_SIGCLEANUP 1'
620 fi
621 if test "$have_readline_catch" = 1; then
622 echo '#define HAVE_READLINE_CATCH 1'
623 fi
624 if test "$have_readline_completion_display_matches_hook" = 1; then
625 echo '#define HAVE_READLINE_COMPLETION_DISPLAY_MATCHES_HOOK 1'
626 fi
627 if test "$have_readline_completion_suppress_append" = 1; then
628 echo '#define HAVE_READLINE_COMPLETION_SUPPRESS_APPEND 1'
629 fi
630 if test "$have_readline_free_history_entry" = 1; then
631 echo '#define HAVE_READLINE_FREE_HISTORY_ENTRY 1'
632 fi
633 if test "$have_readline_list_funmap_names" = 1; then
634 echo '#define HAVE_READLINE_LIST_FUNMAP_NAMES 1'
635 fi
636 if test "$have_readline_resize_terminal" = 1; then
637 echo '#define HAVE_READLINE_RESIZE_TERMINAL 1'
638 fi
639
640 # Used by mycpp/probes.h
641 if test "$have_systemtap_sdt" = 1; then
642 echo '#define HAVE_SYSTEMTAP_SDT 1'
643 else
644 echo '/* #undef HAVE_SYSTEMTAP_SDT */'
645 fi
646
647 echo
648
649 # Shared with detect_c_language
650 echo_libc
651}
652
653# Another way of working: set detected-config.mk ?
654# And set the default target as oil_readline, oil_no_readline, oil_lto,
655# oil_pgo, etc.?
656main() {
657 parse_flags "$@" # sets FLAG_*
658
659 mkdir -p _build
660
661 if ! cc_quiet build/detect-cc.c; then
662 die "Couldn't compile a basic C program (cc not installed?)"
663 fi
664
665 # Sets globals $have_readline, $readline_dir and $have_readline_*
666 detect_readline
667
668 detect_libc
669
670 detect_systemtap_sdt
671
672 # Generate configuration for oils-for-unix
673 local cpp_out=_build/detected-cpp-config.h
674 echo_cpp > $cpp_out
675 log "Wrote $cpp_out"
676
677 # Legacy OVM build: shell build actions will 'source
678 # _build/detected-config.sh'. And then adjust flags to compiler (-D, -l,
679 # etc.)
680 local sh_out=_build/detected-config.sh
681
682 echo_shell_vars > $sh_out
683 log "Wrote $sh_out"
684
685 local c_out=_build/detected-config.h
686
687 # Fast mode
688 if test -n "$_OIL_DEV"; then
689 # Do only this subset
690 echo_libc > $c_out
691 log "Wrote $c_out"
692 return
693 fi
694
695 detect_c_language > $c_out
696 log "Wrote $c_out"
697}
698
699if test -z "$_OIL_CONFIGURE_TEST"; then
700 main "$@"
701fi