OILS / configure View on Github | oils.pub

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