OILS / configure View on Github | oilshell.org

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