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