OILS / configure View on Github | oils.pub

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