c_addrcodec(): CID 1549184 (not on [next])
[s-mailx.git] / mk / make-config.sh
blobb851e0b87a63e2cd3cfdad6d483ffbef40ecff2d
1 #!/bin/sh -
2 #@ Please see INSTALL and make.rc instead.
4 LC_ALL=C
5 export LC_ALL
7 # For heaven's sake auto-redirect on SunOS/Solaris
8 if [ -z "${__MAKE_CONFIG_UP}" ] && [ -d /usr/xpg4 ]; then
9 __MAKE_CONFIG_UP=y
10 PATH=/usr/xpg4/bin:${PATH}
11 export __MAKE_CONFIG_UP PATH
13 if [ "x${SHELL}" = x ] || [ "${SHELL}" = /bin/sh ]; then
14 SHELL=/usr/xpg4/bin/sh
15 export SHELL
16 echo >&2 'SunOS/Solaris, redirecting through $SHELL=/usr/xpg4/bin/sh'
17 exec /usr/xpg4/bin/sh "${0}" "${@}"
21 if [ -z "${SHELL}" ]; then
22 SHELL=/bin/sh
23 export SHELL
26 # The feature set, to be kept in sync with make.rc
27 # If no documentation given, the option is used as such; if doc is '-',
28 # entry is suppressed when configuration overview is printed, and also in the
29 # *features* string: most likely for obsolete features etc.
30 XOPTIONS="\
31 CMD_CSOP='csop command: C-style string operations' \
32 CMD_VEXPR='vexpr command: evaluate arguments as expressions' \
33 COLOUR='Coloured message display' \
34 DOCSTRINGS='Command documentation help strings' \
35 DOTLOCK='Dotlock files and privilege-separated dotlock program' \
36 ERRORS='Log message ring' \
37 FILTER_HTML_TAGSOUP='Simple built-in HTML-to-text display filter' \
38 FILTER_QUOTE_FOLD='Extended *quote-fold*ing filter' \
39 ICONV='Character set conversion using iconv(3)' \
40 IDNA='Internationalized Domain Names for Applications (encode only)' \
41 IMAP_SEARCH='IMAP-style search expressions' \
42 MAILCAP='MIME type handlers defined via mailcap file(s)' \
43 MAILDIR='Maildir E-mail directories' \
44 MLE='Mailx Line Editor' \
45 HISTORY='Line editor history management' \
46 KEY_BINDINGS='Configurable key bindings' \
47 TERMCAP='Terminal capability queries (termcap(5))' \
48 TERMCAP_VIA_TERMINFO='Terminal capability queries use terminfo(5)' \
49 MTA_ALIASES='MTA aliases(5) (text file) support' \
50 REGEX='Regular expressions' \
51 NET='Network support' \
52 GSSAPI='Generic Security Service authentication' \
53 IMAP='IMAP v4r1 client' \
54 MD5='MD5 message digest (APOP, CRAM-MD5)' \
55 NETRC='.netrc file support' \
56 POP3='Post Office Protocol Version 3 client' \
57 SMTP='Simple Mail Transfer Protocol client' \
58 TLS='Transport Layer Security (OpenSSL / LibreSSL)' \
59 TLS_ALL_ALGORITHMS='Support of all digest and cipher algorithms' \
60 SPAM_FILTER='Freely configurable *spam-filter-..*s' \
61 SPAM_SPAMC='Spam management via spamc(1) of spamassassin(1)' \
62 UISTRINGS='User interface and error message strings' \
65 # Options which are automatically deduced from host environment, i.e., these
66 # need special treatment all around here to warp from/to OPT_ stuff
67 # setlocale, C90AMEND1, NL_LANGINFO, wcwidth
68 XOPTIONS_DETECT="\
69 LOCALES='Locale support - printable characters etc. depend on environment' \
70 MULTIBYTE_CHARSETS='Multibyte character sets' \
71 TERMINAL_CHARSET='Automatic detection of terminal character set' \
72 WIDE_GLYPHS='Wide glyph support' \
75 # Rather special options, for custom building, or which always exist.
76 # Mostly for generating the visual overview and the *features* string
77 XOPTIONS_XTRA="\
78 CROSS_BUILD='Cross-compilation: trust any detected environment' \
79 DEBUG='Debug enabled binary, not for end-users: THANKS!' \
80 DEVEL='Computers do not blunder' \
81 MIME='Multipurpose Internet Mail Extensions' \
82 SMIME='S/MIME message signing, verification, en- and decryption' \
85 # To avoid too many recompilations we use a two-stage "configuration changed"
86 # detection, the first uses mk-config.env, which only goes for actual user
87 # config settings etc. the second uses mk-config.h, which thus includes the
88 # things we have truly detected. This does not work well for multiple choice
89 # values of which only one will be really used, so those user wishes may not be
90 # placed in the header, only the really detected one (but that has to!).
91 # Used for grep(1), for portability assume fixed matching only.
92 H_BLACKLIST='-e VAL_ICONV -e VAL_IDNA -e VAL_RANDOM'
94 # The problem is that we don't have any tools we can use right now, so
95 # encapsulate stuff in functions which get called in right order later on
97 option_reset() {
98 set -- ${OPTIONS}
99 for i
101 eval j=\$OPT_${i}
102 [ -n "${j}" ] && eval SAVE_OPT_${i}=${j}
103 eval OPT_${i}=0
104 done
107 option_maximal() {
108 set -- ${OPTIONS}
109 for i
111 eval OPT_${i}=1
112 done
113 OPT_DOTLOCK=require OPT_ICONV=require OPT_REGEX=require
116 option_restore() {
117 any=
118 set -- ${OPTIONS}
119 for i
121 eval j=\$SAVE_OPT_${i}
122 if [ -n "${j}" ]; then
123 msg_nonl "${any}${i}=${j}"
124 any=', '
125 eval OPT_${i}=${j}
127 done
128 [ -n "${any}" ] && msg_nonl ' ... '
131 option_setup() {
132 option_parse OPTIONS_DETECT "${XOPTIONS_DETECT}"
133 option_parse OPTIONS "${XOPTIONS}"
134 option_parse OPTIONS_XTRA "${XOPTIONS_XTRA}"
135 OPT_MIME=1
137 # Predefined CONFIG= urations take precedence over anything else
138 if [ -n "${CONFIG}" ]; then
139 option_reset
140 case "${CONFIG}" in
141 [nN][uU][lL][lL])
143 [nN][uU][lL][lL][iI])
144 OPT_ICONV=require
145 OPT_UISTRINGS=1
147 [mM][iI][nN][iI][mM][aA][lL])
148 OPT_CMD_CSOP=1
149 OPT_CMD_VEXPR=1
150 OPT_COLOUR=1
151 OPT_DOCSTRINGS=1
152 OPT_DOTLOCK=require OPT_ICONV=require OPT_REGEX=require
153 OPT_ERRORS=1
154 OPT_IDNA=1
155 OPT_MAILDIR=1
156 OPT_MLE=1
157 OPT_HISTORY=1 OPT_KEY_BINDINGS=1
158 OPT_SPAM_FILTER=1
159 OPT_UISTRINGS=1
161 [nN][eE][tT][sS][eE][nN][dD])
162 OPT_CMD_CSOP=1
163 OPT_CMD_VEXPR=1
164 OPT_COLOUR=1
165 OPT_DOCSTRINGS=1
166 OPT_DOTLOCK=require OPT_ICONV=require OPT_REGEX=require
167 OPT_ERRORS=1
168 OPT_IDNA=1
169 OPT_MAILDIR=1
170 OPT_MLE=1
171 OPT_HISTORY=1 OPT_KEY_BINDINGS=1
172 OPT_MTA_ALIASES=1
173 OPT_NET=require
174 OPT_GSSAPI=1
175 OPT_NETRC=1
176 OPT_SMTP=require
177 OPT_TLS=require
178 OPT_SPAM_FILTER=1
179 OPT_UISTRINGS=1
181 [mM][aA][xX][iI][mM][aA][lL])
182 option_maximal
184 [dD][eE][vV][eE][lL])
185 option_maximal
186 OPT_DEVEL=1 OPT_DEBUG=1
188 [oO][dD][eE][vV][eE][lL])
189 option_maximal
190 OPT_DEVEL=1
193 msg 'failed'
194 msg 'ERROR: unknown CONFIG= setting: '${CONFIG}
195 msg ' Available are NULL, NULLI, MINIMAL, NETSEND, MAXIMAL'
196 exit 1
198 esac
199 msg_nonl "CONFIG=${CONFIG} ... "
200 option_restore
204 # Inter-relationships XXX sort this!
205 option_update() {
206 if feat_no TLS; then
207 OPT_TLS_ALL_ALGORITHMS=0
210 if feat_no SMTP && feat_no POP3 && feat_no IMAP; then
211 OPT_NET=0
213 if feat_no NET; then
214 if feat_require IMAP; then
215 msg 'ERROR: need NETwork for required feature IMAP'
216 config_exit 13
218 if feat_require POP3; then
219 msg 'ERROR: need NETwork for required feature POP3'
220 config_exit 13
222 if feat_require SMTP; then
223 msg 'ERROR: need NETwork for required feature SMTP'
224 config_exit 13
226 OPT_GSSAPI=0
227 OPT_IMAP=0
228 OPT_MD5=0
229 OPT_NETRC=0
230 OPT_POP3=0
231 OPT_SMTP=0
232 OPT_TLS=0 OPT_TLS_ALL_ALGORITHMS=0
234 if feat_no SMTP && feat_no IMAP; then
235 OPT_GSSAPI=0
238 if feat_no ICONV; then
239 if feat_yes IMAP; then
240 if feat_yes ALWAYS_UNICODE_LOCALE; then
241 msg 'WARN: no ICONV, keeping IMAP due to ALWAYS_UNICODE_LOCALE!'
242 elif feat_require IMAP; then
243 msg 'ERROR: need ICONV for required feature IMAP'
244 config_exit 13
245 else
246 msg 'ERROR: disabling IMAP due to missing ICONV'
247 OPT_IMAP=0
251 if feat_yes IDNA; then
252 if feat_require IDNA; then
253 msg 'ERROR: need ICONV for required feature IDNA'
254 config_exit 13
256 msg 'ERROR: disabling IDNA due to missing ICONV'
257 OPT_IDNA=0
261 if feat_no MLE; then
262 OPT_HISTORY=0 OPT_KEY_BINDINGS=0
263 OPT_TERMCAP=0 OPT_TERMCAP_VIA_TERMINFO=0
264 elif feat_no TERMCAP; then
265 OPT_TERMCAP_VIA_TERMINFO=0
269 ## -- >8 - << OPTIONS | EARLY >> - 8< -- ##
271 # Note that potential duplicates in PATH, C_INCLUDE_PATH etc. will be cleaned
272 # via path_check() later on once possible
274 COMMLINE="${*}"
276 # which(1) not standardized, command(1) -v may return non-executable: unroll!
277 SU_FIND_COMMAND_INCLUSION=1 . "${TOPDIR}"mk/su-find-command.sh
278 # Also not standardized: a way to round-trip quote
279 . "${TOPDIR}"mk/su-quote-rndtrip.sh
281 ## -- >8 - << EARLY | OS/CC >> - 8< -- ##
283 # TODO cc_maxopt is brute simple, we should compile test program and dig real
284 # compiler versions for known compilers, then be more specific
285 [ -n "${cc_maxopt}" ] || cc_maxopt=100
286 cc_os_search=
287 cc_no_stackprot=
288 cc_no_fortify=
289 cc_no_flagtest=
290 ld_need_R_flags=
291 ld_no_bind_now=
292 ld_rpath_not_runpath=
294 _CFLAGS= _LDFLAGS=
296 os_early_setup() {
297 # We don't "have any utility" (see make.rc)
298 [ -n "${OS}" ] && [ -n "${OSFULLSPEC}" ] ||
299 thecmd_testandset_fail uname uname
301 [ -n "${OS}" ] || OS=`${uname} -s`
302 export OS
303 msg 'Operating system is %s' "${OS}"
305 if [ ${OS} = SunOS ]; then
306 # According to standards(5), this is what we need to do
307 if [ -d /usr/xpg4 ]; then :; else
308 msg 'ERROR: On SunOS / Solaris we need /usr/xpg4 environment! Sorry.'
309 config_exit 1
311 # xpg4/bin was already added at top, but we need it first and it will be
312 # cleaned up via path_check along the way
313 PATH="/usr/xpg4/bin:/usr/ccs/bin:/usr/bin:${PATH}"
314 [ -d /usr/xpg6 ] && PATH="/usr/xpg6/bin:${PATH}"
315 export PATH
319 os_setup() {
320 # OSFULLSPEC is used to recognize changes (i.e., machine type, updates
321 # etc.), it is not baked into the binary
322 [ -n "${OSFULLSPEC}" ] || OSFULLSPEC=`${uname} -a`
324 if [ ${OS} = darwin ]; then
325 msg ' . have special Darwin environmental addons...'
326 LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${DYLD_LIBRARY_PATH}
327 elif [ ${OS} = sunos ]; then
328 msg ' . have special SunOS / Solaris "setup" rules ...'
329 cc_os_search=_cc_os_sunos
330 _os_setup_sunos
331 elif [ ${OS} = unixware ]; then
332 cc_os_search=_cc_os_unixware
333 elif [ -n "${VERBOSE}" ]; then
334 msg ' . no special treatment for this system necessary or known'
337 # Sledgehammer: better set _GNU_SOURCE
338 # And in general: oh, boy!
339 OS_DEFINES="${OS_DEFINES}#define _GNU_SOURCE\n"
340 #OS_DEFINES="${OS_DEFINES}#define _POSIX_C_SOURCE 200809L\n"
341 #OS_DEFINES="${OS_DEFINES}#define _XOPEN_SOURCE 700\n"
342 #[ ${OS} = darwin ] && OS_DEFINES="${OS_DEFINES}#define _DARWIN_C_SOURCE\n"
344 # On pkgsrc(7) systems automatically add /usr/pkg/*
345 if feat_yes USE_PKGSYS; then
346 if [ -d /usr/pkg ]; then
347 msg ' . found pkgsrc(7), merging C_INCLUDE_PATH and LD_LIBRARY_PATH'
348 C_INCLUDE_PATH=/usr/pkg/include:${C_INCLUDE_PATH}
349 LD_LIBRARY_PATH=/usr/pkg/lib:${LD_LIBRARY_PATH}
350 ld_rpath_not_runpath=1
355 _os_setup_sunos() {
356 C_INCLUDE_PATH=/usr/xpg4/include:${C_INCLUDE_PATH}
357 LD_LIBRARY_PATH=/usr/xpg4/lib:${LD_LIBRARY_PATH}
359 # Include packages
360 if feat_yes USE_PKGSYS; then
361 if [ -d /opt/csw ]; then
362 msg ' . found OpenCSW PKGSYS'
363 C_INCLUDE_PATH=/opt/csw/include:${C_INCLUDE_PATH}
364 LD_LIBRARY_PATH=/opt/csw/lib:${LD_LIBRARY_PATH}
365 ld_no_bind_now=1 ld_rpath_not_runpath=1
367 if [ -d /opt/schily ]; then
368 msg ' . found Schily PKGSYS'
369 C_INCLUDE_PATH=/opt/schily/include:${C_INCLUDE_PATH}
370 LD_LIBRARY_PATH=/opt/schily/lib:${LD_LIBRARY_PATH}
371 ld_no_bind_now=1 ld_rpath_not_runpath=1
375 OS_DEFINES="${OS_DEFINES}#define __EXTENSIONS__\n"
376 #OS_DEFINES="${OS_DEFINES}#define _POSIX_C_SOURCE 200112L\n"
378 msg 'Whatever $CC, turning off stack protection (see INSTALL)!'
379 cc_maxopt=2 cc_no_stackprot=1
380 return 1
383 # Check out compiler ($CC) and -flags ($CFLAGS)
384 cc_setup() {
385 # Even though it belongs into cc_flags we will try to compile and link
386 # something, so ensure we have a clean state regarding CFLAGS/LDFLAGS or
387 # EXTRA_CFLAGS/EXTRA_LDFLAGS
388 if feat_no AUTOCC; then
389 _cc_default
390 # Ensure those don't do any harm
391 EXTRA_CFLAGS= EXTRA_LDFLAGS=
392 export CC EXTRA_CFLAGS EXTRA_LDFLAGS
393 return
394 else
395 CFLAGS= LDFLAGS=
396 export CFLAGS LDFLAGS
399 if [ -n "${CC}" ]; then
400 _cc_default
401 export CC
402 return
405 if [ -n "${cc_os_search}" ] && ${cc_os_search}; then
406 cc_no_flagtest=1
407 else
408 msg_nonl 'Searching for a usable C compiler .. $CC='
409 if acmd_set CC clang || acmd_set CC gcc ||
410 acmd_set CC tcc || acmd_set CC pcc ||
411 acmd_set CC c89 || acmd_set CC c99; then
412 case "${CC}" in
413 *pcc*) cc_no_fortify=1;;
414 *) ;;
415 esac
416 else
417 msg 'boing booom tschak'
418 msg 'ERROR: I cannot find a compiler!'
419 msg ' Neither of clang(1), gcc(1), tcc(1), pcc(1), c89(1) and c99(1).'
420 msg ' Please set ${CC} environment variable, maybe ${CFLAGS}, rerun.'
421 config_exit 1
424 msg '%s' "${CC}"
425 export CC
428 _cc_os_unixware() {
429 if feat_yes AUTOCC && acmd_set CC cc; then
430 msg_nonl ' . have special UnixWare rules for $CC ...'
431 feat_yes DEBUG && _CFLAGS='-v -Xa -g' || _CFLAGS='-Xa -O'
433 CFLAGS="${_CFLAGS} ${EXTRA_CFLAGS}"
434 LDFLAGS="${_LDFLAGS} ${EXTRA_LDFLAGS}"
435 export CC CFLAGS LDFLAGS
436 OPT_AUTOCC=0 ld_need_R_flags=-R
437 return 0
439 return 1
442 _cc_os_sunos() {
443 if feat_yes AUTOCC && acmd_set CC cc && "${CC}" -flags >/dev/null 2>&1; then
444 msg_nonl ' . have special SunOS rules for $CC ...'
445 feat_yes DEBUG && _CFLAGS="-v -Xa -g" || _CFLAGS="-Xa -O"
447 CFLAGS="${_CFLAGS} ${EXTRA_CFLAGS}"
448 LDFLAGS="${_LDFLAGS} ${EXTRA_LDFLAGS}"
449 export CC CFLAGS LDFLAGS
450 OPT_AUTOCC=0 ld_need_R_flags=-R
451 return 0
452 else
454 : # cc_maxopt=2 cc_no_stackprot=1
456 return 1
459 _cc_default() {
460 if [ -z "${CC}" ]; then
461 msg 'To go on like you have chosen, please set $CC, rerun.'
462 config_exit 1
465 if [ -z "${VERBOSE}" ] && [ -f ${env} ] && feat_no DEBUG; then
467 else
468 msg 'Using C compiler ${CC}=%s' "${CC}"
471 case "${CC}" in
472 *pcc*) cc_no_fortify=1;;
473 *) ;;
474 esac
477 cc_create_testfile() {
478 ${cat} > ${tmp}.c <<\!
479 #include <stdio.h>
480 #include <string.h>
481 static void doit(char const *s);
483 main(int argc, char **argv){
484 (void)argc;
485 (void)argv;
486 doit("Hello world");
487 return 0;
489 static void
490 doit(char const *s){
491 char buf[12];
492 memcpy(buf, s, strlen(s) +1);
493 puts(s);
498 cc_hello() {
499 [ -n "${cc_check_silent}" ] || msg_nonl ' . CC compiles "Hello world" .. '
500 if ${CC} ${INCS} ${CFLAGS} ${EXTRA_CFLAGS} ${LDFLAGS} ${EXTRA_LDFLAGS} \
501 -o ${tmp2} ${tmp}.c ${LIBS}; then
502 [ -n "${cc_check_silent}" ] || msg 'yes'
503 feat_yes CROSS_BUILD && return 0
504 [ -n "${cc_check_silent}" ] || msg_nonl ' . Compiled program works .. '
505 if ( [ "`\"${tmp2}\"`" = 'Hello world' ] ) >/dev/null 2>&1; then
506 [ -n "${cc_check_silent}" ] || msg 'yes'
507 return 0
510 [ -n "${cc_check_silent}" ] || msg 'no'
511 msg 'ERROR: i cannot compile or run a "Hello world" via'
512 msg ' %s' \
513 "${CC} ${INCS} ${CFLAGS} ${EXTRA_CFLAGS} ${LDFLAGS} ${EXTRA_LDFLAGS} ${LIBS}"
514 msg 'ERROR: Please read INSTALL, rerun'
515 config_exit 1
518 cc_flags() {
519 if [ -n "${cc_no_flagtest}" ]; then
520 ld_runtime_flags # update!
521 elif feat_yes AUTOCC; then
522 if [ -f ${env} ] && feat_no DEBUG && [ -z "${VERBOSE}" ]; then
523 cc_check_silent=1
524 msg 'Detecting ${CFLAGS}/${LDFLAGS} for ${CC}=%s, just a second..' \
525 "${CC}"
526 else
527 cc_check_silent=
528 msg 'Testing usable ${CFLAGS}/${LDFLAGS} for ${CC}=%s' "${CC}"
531 i=`echo "${CC}" | ${awk} 'BEGIN{FS="/"}{print $NF}'`
532 if { echo "${i}" | ${grep} tcc; } >/dev/null 2>&1; then
533 msg ' . have special tcc(1) environmental rules ...'
534 _cc_flags_tcc
535 else
536 # As of pcc CVS 2016-04-02, stack protection support is announced but
537 # will break if used on Linux
538 #if { echo "${i}" | ${grep} pcc; } >/dev/null 2>&1; then
539 # cc_no_stackprot=1
541 _cc_flags_generic
544 feat_no DEBUG && feat_no DEVEL && _CFLAGS="-DNDEBUG ${_CFLAGS}"
545 CFLAGS="${_CFLAGS} ${EXTRA_CFLAGS}"
546 LDFLAGS="${_LDFLAGS} ${EXTRA_LDFLAGS}"
547 else
548 if feat_no DEBUG && feat_no DEVEL; then
549 CFLAGS="-DNDEBUG ${CFLAGS}"
552 export CFLAGS LDFLAGS
555 _cc_flags_tcc() {
556 __cflags=${_CFLAGS} __ldflags=${_LDFLAGS}
557 _CFLAGS= _LDFLAGS=
559 cc_check -W
560 cc_check -Wall
561 cc_check -Wextra
562 cc_check -pedantic
564 if feat_yes DEBUG; then
565 # May have problems to find libtcc cc_check -b
566 cc_check -g
569 if ld_check -Wl,-rpath =./ no; then
570 ld_need_R_flags=-Wl,-rpath=
571 if [ -z "${ld_rpath_not_runpath}" ]; then
572 ld_check -Wl,--enable-new-dtags
573 else
574 msg ' ! $LD_LIBRARY_PATH adjusted, not trying --enable-new-dtags'
576 ld_runtime_flags # update!
579 _CFLAGS="${_CFLAGS} ${__cflags}" _LDFLAGS="${_LDFLAGS} ${__ldflags}"
580 unset __cflags __ldflags
583 _cc_flags_generic() {
584 __cflags=${_CFLAGS} __ldflags=${_LDFLAGS}
585 _CFLAGS= _LDFLAGS=
586 feat_yes DEVEL && cc_check -std=c89 || cc_check -std=c99
588 # E.g., valgrind does not work well with high optimization
589 if [ ${cc_maxopt} -gt 1 ] && feat_yes NOMEMDBG &&
590 feat_no ASAN_ADDRESS && feat_no ASAN_MEMORY; then
591 msg ' ! OPT_NOMEMDBG, setting cc_maxopt=1 (-O1)'
592 cc_maxopt=1
594 # Check -g first since some others may rely upon -g / optim. level
595 if feat_yes DEBUG; then
596 cc_check -O
597 cc_check -g
598 elif [ ${cc_maxopt} -gt 2 ] && cc_check -O3; then
600 elif [ ${cc_maxopt} -gt 1 ] && cc_check -O2; then
602 elif [ ${cc_maxopt} -gt 0 ] && cc_check -O1; then
604 else
605 cc_check -O
608 if feat_yes AMALGAMATION; then
609 cc_check -pipe
612 #if feat_yes DEVEL && cc_check -Weverything; then
614 #else
615 cc_check -W
616 cc_check -Wall
617 cc_check -Wextra
618 if feat_yes DEVEL; then
619 cc_check -Wbad-function-cast
620 cc_check -Wcast-align
621 cc_check -Wcast-qual
622 cc_check -Wformat-security # -Wformat via -Wall
623 cc_check -Wformat-signedness
624 cc_check -Winit-self
625 cc_check -Wmissing-prototypes
626 cc_check -Wshadow
627 cc_check -Wunused
628 cc_check -Wwrite-strings
629 cc_check -Wno-long-long
632 cc_check -pedantic
633 if feat_no DEVEL; then
634 if feat_yes AMALGAMATION; then
635 cc_check -Wno-unused-function
637 if cc_check -Wno-uninitialized; then :; else
638 cc_check -Wno-maybe-uninitialized
640 cc_check -Wno-unused-result
641 cc_check -Wno-unused-value
644 cc_check -fno-asynchronous-unwind-tables
645 cc_check -fno-common
646 cc_check -fno-unwind-tables
647 cc_check -fstrict-aliasing
648 if cc_check -fstrict-overflow && feat_yes DEVEL; then
649 cc_check -Wstrict-overflow=5
652 if feat_yes AUTOCC_STACKPROT; then
653 if [ -z "${cc_no_stackprot}" ]; then
654 if cc_check -fstack-protector-strong ||
655 cc_check -fstack-protector-all; then
656 if [ -z "${cc_no_fortify}" ]; then
657 cc_check -D_FORTIFY_SOURCE=2
658 else
659 msg ' ! Not checking for -D_FORTIFY_SOURCE=2 compiler option,'
660 msg ' ! since that caused errors in a "similar" configuration.'
661 msg ' ! You may turn off OPT_AUTOCC, then rerun with your own'
664 else
665 msg ' ! Not checking for -fstack-protector compiler option,'
666 msg ' ! since that caused errors in a "similar" configuration.'
667 msg ' ! You may turn off OPT_AUTOCC, then rerun with your own'
671 # LD (+ dependent CC)
673 if feat_yes ASAN_ADDRESS; then
674 _ccfg=${_CFLAGS}
675 if cc_check -fsanitize=address && ld_check -fsanitize=address; then
677 else
678 feat_bail_required ASAN_ADDRESS
679 _CFLAGS=${_ccfg}
683 if feat_yes ASAN_MEMORY; then
684 _ccfg=${_CFLAGS}
685 if cc_check -fsanitize=memory && ld_check -fsanitize=memory &&
686 cc_check -fsanitize-memory-track-origins=2 &&
687 ld_check -fsanitize-memory-track-origins=2; then
689 else
690 feat_bail_required ASAN_MEMORY
691 _CFLAGS=${_ccfg}
695 if feat_yes USAN; then
696 _ccfg=${_CFLAGS}
697 if cc_check -fsanitize=undefined && ld_check -fsanitize=undefined; then
699 else
700 feat_bail_required USAN
701 _CFLAGS=${_ccfg}
705 ld_check -Wl,-z,relro
706 if [ -z "${ld_no_bind_now}" ]; then
707 ld_check -Wl,-z,now
708 else
709 msg ' ! $LD_LIBRARY_PATH adjusted, not trying -Wl,-z,now'
711 ld_check -Wl,-z,noexecstack
712 ld_check -Wl,--as-needed
713 if ld_check -Wl,-rpath =./ no; then
714 ld_need_R_flags=-Wl,-rpath=
715 # Choose DT_RUNPATH (after $LD_LIBRARY_PATH) over DT_RPATH (before)
716 if [ -z "${ld_rpath_not_runpath}" ]; then
717 ld_check -Wl,--enable-new-dtags
718 else
719 msg ' ! $LD_LIBRARY_PATH adjusted, not trying --enable-new-dtags'
721 ld_runtime_flags # update!
722 elif ld_check -Wl,-R ./ no; then
723 ld_need_R_flags=-Wl,-R
724 if [ -z "${ld_rpath_not_runpath}" ]; then
725 ld_check -Wl,--enable-new-dtags
726 else
727 msg ' ! $LD_LIBRARY_PATH adjusted, not trying --enable-new-dtags'
729 ld_runtime_flags # update!
732 # Address randomization
733 _ccfg=${_CFLAGS}
734 if cc_check -fPIE || cc_check -fpie; then
735 ld_check -pie || _CFLAGS=${_ccfg}
737 unset _ccfg
739 # Retpoline (xxx maybe later?)
740 # _ccfg=${_CFLAGS} _i=
741 # if cc_check -mfunction-return=thunk; then
742 # if cc_check -mindirect-branch=thunk; then
743 # _i=1
744 # fi
745 # elif cc_check -mretpoline; then
746 # _i=1
747 # fi
748 # if [ -n "${_i}" ]; then
749 # ld_check -Wl,-z,retpolineplt || _i=
750 # fi
751 # [ -n "${_i}" ] || _CFLAGS=${_ccfg}
752 # unset _ccfg
754 _CFLAGS="${_CFLAGS} ${__cflags}" _LDFLAGS="${_LDFLAGS} ${__ldflags}"
755 unset __cflags __ldflags
758 ## -- >8 - <<OS/CC | SUPPORT FUNS>> - 8< -- ##
760 ## Notes:
761 ## - Heirloom sh(1) (and same origin) have _sometimes_ problems with ': >'
762 ## redirection, so use "printf '' >" instead
764 ## Very first: we undergo several states regarding I/O redirection etc.,
765 ## but need to deal with option updates from within all. Since all the
766 ## option stuff should be above the scissor line, define utility functions
767 ## and redefine them as necessary.
768 ## And, since we have those functions, simply use them for whatever
770 t1=ten10one1ten10one1
771 if ( [ ${t1##*ten10} = one1 ] && [ ${t1#*ten10} = one1ten10one1 ] &&
772 [ ${t1%%one1*} = ten10 ] && [ ${t1%one1*} = ten10one1ten10 ]
773 ) > /dev/null 2>&1; then
774 good_shell=1
775 else
776 unset good_shell
778 unset t1
780 ( set -o noglob ) >/dev/null 2>&1 && noglob_shell=1 || unset noglob_shell
782 config_exit() {
783 exit ${1}
786 # Our feature check environment
787 _feats_eval_done=0
789 _feat_val_no() {
790 [ "x${1}" = x0 ] || [ "x${1}" = xn ] ||
791 [ "x${1}" = xfalse ] || [ "x${1}" = xno ] || [ "x${1}" = xoff ]
794 _feat_val_yes() {
795 [ "x${1}" = x1 ] || [ "x${1}" = xy ] ||
796 [ "x${1}" = xtrue ] || [ "x${1}" = xyes ] || [ "x${1}" = xon ] ||
797 [ "x${1}" = xrequire ]
800 _feat_val_require() {
801 [ "x${1}" = xrequire ]
804 _feat_check() {
805 eval _fc_i=\$OPT_${1}
806 if [ "$_feats_eval_done" = 1 ]; then
807 [ "x${_fc_i}" = x0 ] && return 1
808 return 0
810 _fc_i="`echo ${_fc_i} | ${tr} '[A-Z]' '[a-z]'`"
811 if _feat_val_no "${_fc_i}"; then
812 return 1
813 elif _feat_val_yes "${_fc_i}"; then
814 return 0
815 else
816 msg "ERROR: %s: 0/n/false/no/off or 1/y/true/yes/on/require, got: %s" \
817 "${1}" "${_fc_i}"
818 config_exit 11
822 feat_yes() {
823 _feat_check ${1}
826 feat_no() {
827 _feat_check ${1} && return 1
828 return 0
831 feat_require() {
832 eval _fr_i=\$OPT_${1}
833 _fr_i="`echo ${_fr_i} | ${tr} '[A-Z]' '[a-z]'`"
834 [ "x${_fr_i}" = xrequire ] || [ "x${_fr_i}" = xrequired ]
837 feat_bail_required() {
838 if feat_require ${1}; then
839 msg 'ERROR: feature OPT_%s is required but not available' "${1}"
840 config_exit 13
842 feat_is_unsupported "${1}"
845 feat_is_disabled() {
846 [ ${#} -eq 1 ] && msg ' . (disabled: OPT_%s)' "${1}"
847 echo "/* OPT_${1} -> mx_HAVE_${1} */" >> ${h}
850 feat_is_unsupported() {
851 msg ' ! NOTICE: unsupported: OPT_%s' "${1}"
852 echo "/* OPT_${1} -> mx_HAVE_${1} */" >> ${h}
853 eval OPT_${1}=0
854 option_update # XXX this is rather useless here (dependency chain..)
857 feat_def() {
858 if feat_yes ${1}; then
859 [ -n "${VERBOSE}" ] && msg ' . %s ... yes' "${1}"
860 echo '#define mx_HAVE_'${1}'' >> ${h}
861 return 0
862 else
863 feat_is_disabled "${@}"
864 return 1
868 option_parse() {
869 # Parse one of our XOPTIONS* in $2 and assign the sh(1) compatible list of
870 # options, without documentation, to $1
871 j=\'
872 i="`${awk} -v input=\"${2}\" '
873 BEGIN{
874 for(i = 0;;){
875 voff = match(input, /[0-9a-zA-Z_]+(='${j}'[^'${j}']+)?/)
876 if(voff == 0)
877 break
878 v = substr(input, voff, RLENGTH)
879 input = substr(input, voff + RLENGTH)
880 doff = index(v, "=")
881 if(doff > 0){
882 d = substr(v, doff + 2, length(v) - doff - 1)
883 v = substr(v, 1, doff - 1)
885 print v
889 eval ${1}=\"${i}\"
892 option_doc_of() {
893 # Return the "documentation string" for option $1, itself if none such
894 j=\'
895 ${awk} -v want="${1}" \
896 -v input="${XOPTIONS_DETECT}${XOPTIONS}${XOPTIONS_XTRA}" '
897 BEGIN{
898 for(;;){
899 voff = match(input, /[0-9a-zA-Z_]+(='${j}'[^'${j}']+)?/)
900 if(voff == 0)
901 break
902 v = substr(input, voff, RLENGTH)
903 input = substr(input, voff + RLENGTH)
904 doff = index(v, "=")
905 if(doff > 0){
906 d = substr(v, doff + 2, length(v) - doff - 1)
907 v = substr(v, 1, doff - 1)
908 }else
909 d = v
910 if(v == want){
911 if(d != "-")
912 print d
913 exit
920 option_join_rc() {
921 # Join the values from make.rc into what currently is defined, not
922 # overwriting yet existing settings
923 ${rm} -f ${tmp}
924 # We want read(1) to perform reverse solidus escaping in order to be able to
925 # use multiline values in make.rc; the resulting sh(1)/sed(1) code was very
926 # slow in VMs (see [fa2e248]), Aharon Robbins suggested the following
927 < ${rc} ${awk} 'BEGIN{line = ""}{
928 sub(/^[ ]+/, "", $0)
929 sub(/[ ]+$/, "", $0)
930 if(sub(/\\$/, "", $0)){
931 line = line $0
932 next
933 }else
934 line = line $0
935 if(index(line, "#") == 1){
936 line = ""
937 }else if(length(line)){
938 print line
939 line = ""
941 }' |
942 while read line; do
943 if [ -n "${good_shell}" ]; then
944 i=${line%%=*}
945 else
946 i=`${awk} -v LINE="${line}" 'BEGIN{
947 sub(/=.*$/, "", LINE)
948 print LINE
951 if [ "${i}" = "${line}" ]; then
952 msg 'ERROR: invalid syntax in: %s' "${line}"
953 continue
956 eval j="\$${i}" jx="\${${i}+x}"
957 if [ -n "${j}" ] || [ "${jx}" = x ]; then
958 : # Yet present
959 else
960 j=`${awk} -v LINE="${line}" 'BEGIN{
961 sub(/^[^=]*=/, "", LINE)
962 sub(/^"*/, "", LINE)
963 sub(/"*$/, "", LINE)
964 # Sun xpg4/bin/awk expands those twice:
965 # Notice that backslash escapes are interpreted twice, once in
966 # lexical processing of the string and once in processing the
967 # regular expression.
968 i = "\""
969 gsub(/"/, "\\\\\"", i)
970 i = (i == "\134\"")
971 gsub(/"/, (i ? "\\\\\"" : "\134\""), LINE)
972 print LINE
975 [ "${i}" = "DESTDIR" ] && continue
976 [ "${i}" = "OBJDIR" ] && continue
977 echo "${i}=\"${j}\""
978 done > ${tmp}
979 # Reread the mixed version right now
980 . ${tmp}
983 option_evaluate() {
984 # Expand the option values, which may contain shell snippets
985 # Set booleans to 0 or 1, or require, set _feats_eval_done=1
986 ${rm} -f ${newenv} ${newmk}
988 exec 7<&0 8>&1 <${tmp} >${newenv}
989 while read line; do
991 if [ -n "${good_shell}" ]; then
992 i=${line%%=*}
993 [ "${i}" != "${i#OPT_}" ] && z=1
994 else
995 i=`${awk} -v LINE="${line}" 'BEGIN{
996 gsub(/=.*$/, "", LINE);\
997 print LINE
999 if echo "${i}" | ${grep} '^OPT_' >/dev/null 2>&1; then
1004 eval j=\$${i}
1005 if [ -n "${z}" ]; then
1006 j="`echo ${j} | ${tr} '[A-Z]' '[a-z]'`"
1007 if [ -z "${j}" ] || _feat_val_no "${j}"; then
1009 printf " /* #undef ${i} */\n" >> ${newh}
1010 elif _feat_val_yes "${j}"; then
1011 if _feat_val_require "${j}"; then
1012 j=require
1013 else
1016 printf " /* #define ${i} */\n" >> ${newh}
1017 else
1018 msg 'ERROR: cannot parse <%s>' "${line}"
1019 config_exit 1
1021 elif { echo ${i} | ${grep} ${H_BLACKLIST} >/dev/null 2>&1; }; then
1023 else
1024 printf "#define ${i} \"${j}\"\n" >> ${newh}
1026 printf -- "${i} = ${j}\n" >> ${newmk}
1027 printf -- "${i}=%s;export ${i}\n" "`quote_string ${j}`"
1028 eval "${i}=\"${j}\""
1029 done
1030 exec 0<&7 1>&8 7<&- 8<&-
1032 _feats_eval_done=1
1035 val_allof() {
1036 eval __expo__=\$${1}
1037 ${awk} -v HEAP="${2}" -v USER="${__expo__}" '
1038 BEGIN{
1039 i = split(HEAP, ha, /[, ]/)
1040 if((j = split(USER, ua, /[, ]/)) == 0)
1041 exit
1042 for(; j != 0; --j){
1043 us = tolower(ua[j])
1044 if(us == "all" || us == "any")
1045 continue
1046 ok = 0
1047 for(ii = i; ii != 0; --ii)
1048 if(tolower(ha[ii]) == us){
1049 ok = 1
1050 break
1052 if(!ok)
1053 exit 1
1057 __rv__=${?}
1058 [ ${__rv__} -ne 0 ] && return ${__rv__}
1060 if ${awk} -v USER="${__expo__}" '
1061 BEGIN{
1062 if((j = split(USER, ua, /[, ]/)) == 0)
1063 exit
1064 for(; j != 0; --j){
1065 us = tolower(ua[j])
1066 if(us == "all" || us == "any")
1067 exit 0
1069 exit 1
1071 '; then
1072 eval "${1}"=\"${2}\"
1073 else
1074 # Enforce lowercase also in otherwise unchanged user value..
1075 eval "${1}"=\""`echo ${__expo__} | ${tr} '[A-Z]_' '[a-z]-'`"\"
1077 return 0
1080 oneslash() {
1081 </dev/null ${awk} -v X="${1}" '
1082 BEGIN{
1083 i = match(X, "/+$")
1084 if(RSTART != 0)
1085 X = substr(X, 1, RSTART - 1)
1086 X = X "/"
1087 print X
1092 path_is_absolute() {
1093 { echo "${*}" | ${grep} ^/; } >/dev/null 2>&1
1094 return $?
1097 path_check() {
1098 # "path_check VARNAME" or "path_check VARNAME FLAG VARNAME"
1099 varname=${1} addflag=${2} flagvarname=${3}
1100 j=${IFS}
1101 IFS=:
1102 [ -n "${noglob_shell}" ] && set -o noglob
1103 eval "set -- \$${1}"
1104 [ -n "${noglob_shell}" ] && set +o noglob
1105 IFS=${j}
1106 j= k= y= z=
1107 for i
1109 [ -z "${i}" ] && continue
1110 [ -d "${i}" ] || continue
1111 if [ -n "${j}" ]; then
1112 if { z=${y}; echo "${z}"; } | ${grep} ":${i}:" >/dev/null 2>&1; then
1114 else
1115 y="${y} :${i}:"
1116 j="${j}:${i}"
1117 # But do not link any fakeroot path into our binaries!
1118 if [ -n "${addflag}" ]; then
1119 case "${i}" in *fakeroot*) continue;; esac
1120 k="${k} ${addflag}${i}"
1123 else
1124 y=" :${i}:"
1125 j="${i}"
1126 # But do not link any fakeroot injected path into our binaries!
1127 if [ -n "${addflag}" ]; then
1128 case "${i}" in *fakeroot*) continue;; esac
1129 k="${k} ${addflag}${i}"
1132 done
1133 eval "${varname}=\"${j}\""
1134 [ -n "${addflag}" ] && eval "${flagvarname}=\"${k}\""
1135 unset varname
1138 ld_runtime_flags() {
1139 if [ -n "${ld_need_R_flags}" ]; then
1140 i=${IFS}
1141 IFS=:
1142 set -- ${LD_LIBRARY_PATH}
1143 IFS=${i}
1144 for i
1146 # But do not link any fakeroot injected path into our binaries!
1147 case "${i}" in *fakeroot*) continue;; esac
1148 LDFLAGS="${LDFLAGS} ${ld_need_R_flags}${i}"
1149 _LDFLAGS="${_LDFLAGS} ${ld_need_R_flags}${i}"
1150 done
1151 export LDFLAGS
1153 # Disable it for a possible second run.
1154 ld_need_R_flags=
1157 _cc_check_ever= _cc_check_testprog=
1158 cc_check() {
1159 if [ -z "${_cc_check_ever}" ]; then
1160 _cc_check_ever=' '
1161 __occ=${cc_check_silent}
1162 __oCFLAGS=${_CFLAGS}
1164 cc_check_silent=y
1165 if cc_check -Werror; then
1166 _cc_check_ever=-Werror
1167 _CFLAGS=${__oCFLAGS}
1168 # Overcome a _GNU_SOURCE related glibc 2.32.3 bug (?!)
1169 if cc_check -Werror=implicit-function-declaration; then
1170 _cc_check_testprog=-Werror=implicit-function-declaration
1174 _CFLAGS=${__oCFLAGS}
1175 cc_check_silent=${__occ}
1176 unset __occ __oCFLAGS
1179 [ -n "${cc_check_silent}" ] || msg_nonl ' . CC %s .. ' "${1}"
1181 trap "exit 11" ABRT BUS ILL SEGV # avoid error messages (really)
1182 ${CC} ${INCS} ${_cc_check_ever} \
1183 ${_CFLAGS} ${1} ${EXTRA_CFLAGS} ${_LDFLAGS} ${EXTRA_LDFLAGS} \
1184 -o ${tmp2} ${tmp}.c ${LIBS} || exit 1
1185 feat_no CROSS_BUILD || exit 0
1186 ${tmp2}
1187 ) >/dev/null
1188 if [ $? -eq 0 ]; then
1189 _CFLAGS="${_CFLAGS} ${1}"
1190 [ -n "${cc_check_silent}" ] || msg 'yes'
1191 return 0
1193 [ -n "${cc_check_silent}" ] || msg 'no'
1194 return 1
1197 ld_check() {
1198 # $1=option [$2=option argument] [$3=if set, shall NOT be added to _LDFLAGS]
1199 [ -n "${cc_check_silent}" ] || msg_nonl ' . LD %s .. ' "${1}"
1201 trap "exit 11" ABRT BUS ILL SEGV # avoid error messages (really)
1202 ${CC} ${INCS} ${_cc_check_ever} \
1203 ${_CFLAGS} ${_LDFLAGS} ${1}${2} ${EXTRA_LDFLAGS} \
1204 -o ${tmp2} ${tmp}.c ${LIBS} || exit 1
1205 feat_no CROSS_BUILD || exit 0
1206 ${tmp2}
1207 ) >/dev/null
1208 if [ $? -eq 0 ]; then
1209 [ -n "${3}" ] || _LDFLAGS="${_LDFLAGS} ${1}"
1210 [ -n "${cc_check_silent}" ] || msg 'yes'
1211 return 0
1213 [ -n "${cc_check_silent}" ] || msg 'no'
1214 return 1
1217 dump_test_program=1
1218 _check_preface() {
1219 variable=$1 topic=$2 define=$3
1221 echo '@@@'
1222 msg_nonl ' . %s ... ' "${topic}"
1223 #echo "/* checked ${topic} */" >> ${h}
1224 ${rm} -f ${tmp} ${tmp}.o
1225 if [ "${dump_test_program}" = 1 ]; then
1226 { echo '#include <'"${h_name}"'>'; cat; } | ${tee} ${tmp}.c
1227 else
1228 { echo '#include <'"${h_name}"'>'; cat; } > ${tmp}.c
1230 #echo '@P'
1231 #MAKEFLAGS= ${make} -f ${makefile} ${tmp}.x
1232 #${cat} ${tmp}.x
1233 echo '@R'
1236 without_check() {
1237 oneorzero=$1 variable=$2 topic=$3 define=$4 libs=$5 incs=$6
1239 echo '@@@'
1240 msg_nonl ' . %s ... ' "${topic}"
1242 if [ "${oneorzero}" = 1 ]; then
1243 if [ -n "${incs}" ] || [ -n "${libs}" ]; then
1244 echo "@ INCS<${incs}> LIBS<${libs}>"
1245 LIBS="${LIBS} ${libs}"
1246 INCS="${INCS} ${incs}"
1248 msg 'yes (deduced)'
1249 echo "${define}" >> ${h}
1250 eval have_${variable}=yes
1251 return 0
1252 else
1253 #echo "/* ${define} */" >> ${h}
1254 msg 'no (deduced)'
1255 eval unset have_${variable}
1256 return 1
1260 compile_check() {
1261 variable=$1 topic=$2 define=$3
1263 _check_preface "${variable}" "${topic}" "${define}"
1265 if MAKEFLAGS= ${make} -f ${makefile} XINCS="${INCS}" \
1266 CFLAGS="${_cc_check_testprog} ${CFLAGS}" \
1267 LDFLAGS="${_cc_check_testprog} ${LDFLAGS}" ${tmp}.o &&
1268 [ -f ${tmp}.o ]; then
1269 msg 'yes'
1270 echo "${define}" >> ${h}
1271 eval have_${variable}=yes
1272 return 0
1273 else
1274 #echo "/* ${define} */" >> ${h}
1275 msg 'no'
1276 eval unset have_${variable}
1277 return 1
1281 _link_mayrun() {
1282 run=$1 variable=$2 topic=$3 define=$4 libs=$5 incs=$6
1284 _check_preface "${variable}" "${topic}" "${define}"
1286 if feat_yes CROSS_BUILD; then
1287 if [ ${run} = 1 ]; then
1288 run=0
1292 if MAKEFLAGS= ${make} -f ${makefile} XINCS="${INCS} ${incs}" \
1293 CFLAGS="${_cc_check_testprog} ${CFLAGS}" \
1294 LDFLAGS="${_cc_check_testprog} ${LDFLAGS}" \
1295 XLIBS="${LIBS} ${libs}" ${tmp} &&
1296 [ -f ${tmp} ] && { [ ${run} -eq 0 ] || ${tmp}; }; then
1297 echo "@ INCS<${incs}> LIBS<${libs}>; executed: ${run}"
1298 msg 'yes'
1299 echo "${define}" >> ${h}
1300 LIBS="${LIBS} ${libs}"
1301 INCS="${INCS} ${incs}"
1302 eval have_${variable}=yes
1303 return 0
1304 else
1305 msg 'no'
1306 #echo "/* ${define} */" >> ${h}
1307 eval unset have_${variable}
1308 return 1
1312 link_check() {
1313 _link_mayrun 0 "${1}" "${2}" "${3}" "${4}" "${5}"
1316 run_check() {
1317 _link_mayrun 1 "${1}" "${2}" "${3}" "${4}" "${5}"
1320 xrun_check() {
1321 _link_mayrun 2 "${1}" "${2}" "${3}" "${4}" "${5}"
1324 string_to_char_array() {
1325 ${awk} -v xy="${@}" 'BEGIN{
1326 # POSIX: unspecified behaviour.
1327 # Does not work for SunOS /usr/xpg4/bin/awk!
1328 if(split("abc", xya, "") == 3)
1329 i = split(xy, xya, "")
1330 else{
1331 j = length(xy)
1332 for(i = 0; j > 0; --j){
1333 xya[++i] = substr(xy, 1, 1)
1334 xy = substr(xy, 2)
1337 xya[++i] = "\\0"
1338 for(j = 1; j <= i; ++j){
1339 if(j != 1)
1340 printf ", "
1341 y = xya[j]
1342 if(y == "\012")
1343 y = "\\n"
1344 else if(y == "\\")
1345 y = "\\\\"
1346 printf "'"'"'%s'"'"'", y
1351 squeeze_ws() {
1352 echo "${*}" |
1353 ${sed} -e 's/^[ ]\{1,\}//' -e 's/[ ]\{1,\}$//' -e 's/[ ]\{1,\}/ /g'
1356 ## -- >8 - <<SUPPORT FUNS | RUNNING>> - 8< -- ##
1358 msg() {
1359 fmt=${1}
1360 shift
1361 printf -- "${fmt}\n" "${@}"
1364 msg_nonl() {
1365 fmt=${1}
1366 shift
1367 printf -- "${fmt}" "${@}"
1370 # Very easy checks for the operating system in order to be able to adjust paths
1371 # or similar very basic things which we need to be able to go at all
1372 os_early_setup
1374 # Check those tools right now that we need before including $rc
1375 msg 'Checking for basic utility set'
1376 thecmd_testandset_fail awk awk
1377 thecmd_testandset_fail rm rm
1378 thecmd_testandset_fail tr tr
1380 # Lowercase this now in order to isolate all the remains from case matters
1381 OS_ORIG_CASE=${OS}
1382 OS=`echo ${OS} | ${tr} '[A-Z]' '[a-z]'`
1383 export OS
1385 # But first of all, create new configuration and check whether it changed
1386 if [ -z "${OBJDIR}" ]; then
1387 OBJDIR=.obj
1388 else
1389 OBJDIR=`${awk} -v input="${OBJDIR}" 'BEGIN{
1390 if(index(input, "/"))
1391 sub("/+$", "", input)
1392 print input
1396 rc=./make.rc
1397 env="${OBJDIR}"/mk-config.env
1398 h="${OBJDIR}"/mk-config.h h_name=mk-config.h
1399 mk="${OBJDIR}"/mk-config.mk
1401 newmk="${OBJDIR}"/mk-nconfig.mk
1402 oldmk="${OBJDIR}"/mk-oconfig.mk
1403 newenv="${OBJDIR}"/mk-nconfig.env
1404 newh="${OBJDIR}"/mk-nconfig.h
1405 oldh="${OBJDIR}"/mk-oconfig.h
1406 tmp0="${OBJDIR}"/___tmp
1407 tmp=${tmp0}1$$
1408 tmp2=${tmp0}2$$
1410 if [ -d "${OBJDIR}" ] || mkdir -p "${OBJDIR}"; then :; else
1411 msg 'ERROR: cannot create '"${OBJDIR}"' build directory'
1412 exit 1
1415 # !!
1416 log="${OBJDIR}"/mk-config.log
1417 exec 5>&2 > ${log} 2>&1
1419 msg() {
1420 fmt=${1}
1421 shift
1422 printf -- "${fmt}\n" "${@}"
1423 printf -- "${fmt}\n" "${@}" >&5
1426 msg_nonl() {
1427 fmt=${1}
1428 shift
1429 printf -- "${fmt}" "${@}"
1430 printf -- "${fmt}" "${@}" >&5
1433 # Initialize the option set
1434 msg_nonl 'Setting up configuration options ... '
1435 option_setup
1436 msg 'done'
1438 # Include $rc, but only take from it what wasn't overwritten by the user from
1439 # within the command line or from a chosen fixed CONFIG=
1440 # Note we leave alone the values
1441 trap "exit 1" HUP INT TERM
1442 trap "${rm} -f ${tmp}" EXIT
1444 msg_nonl 'Joining in %s ... ' ${rc}
1445 option_join_rc
1446 msg 'done'
1448 # We need to know about that now, in order to provide utility overwrites etc.
1449 os_setup
1451 msg 'Checking for remaining set of utilities'
1452 thecmd_testandset_fail getconf getconf
1453 thecmd_testandset_fail grep grep
1455 # Before we step ahead with the other utilities perform a path cleanup first.
1456 path_check PATH
1458 # awk(1) above
1459 thecmd_testandset_fail basename basename
1460 thecmd_testandset_fail cat cat
1461 thecmd_testandset_fail chmod chmod
1462 thecmd_testandset_fail cp cp
1463 thecmd_testandset_fail cmp cmp
1464 # grep(1) above
1465 thecmd_testandset ln ln # only for tests
1466 thecmd_testandset_fail mkdir mkdir
1467 thecmd_testandset_fail mv mv
1468 # We always need pwd(1), for at least mx-test.sh
1469 thecmd_testandset_fail pwd pwd
1470 # rm(1) above
1471 thecmd_testandset_fail sed sed
1472 thecmd_testandset_fail sort sort
1473 thecmd_testandset_fail tee tee
1474 __PATH=${PATH}
1475 thecmd_testandset chown chown ||
1476 PATH="/sbin:${PATH}" thecmd_set chown chown ||
1477 PATH="/usr/sbin:${PATH}" thecmd_set_fail chown chown
1478 PATH=${__PATH}
1479 thecmd_testandset_fail MAKE make
1480 make=${MAKE}
1481 export MAKE
1482 thecmd_testandset strip strip
1484 # For ./mx-test.sh only
1485 thecmd_testandset_fail cksum cksum
1487 # Update OPT_ options now, in order to get possible inter-dependencies right
1488 option_update
1490 # (No functions since some shells loose non-exported variables in traps)
1491 trap "trap \"\" HUP INT TERM; exit 1" HUP INT TERM
1492 trap "trap \"\" HUP INT TERM EXIT;\
1493 ${rm} -rf ${tmp0}.* ${tmp0}* \
1494 ${newmk} ${oldmk} ${newenv} ${newh} ${oldh}" EXIT
1496 printf '#ifdef mx_SOURCE\n' > ${newh}
1498 # Now that we have pwd(1) and options at least permit some more actions, set
1499 # our build paths unless make-emerge.sh has been used; it would have created
1500 # a makefile with the full paths otherwise
1501 if [ -z "${CWDDIR}" ]; then
1502 CWDDIR=`${pwd}`
1503 CWDDIR=`oneslash "${CWDDIR}"`
1505 if [ -z "${TOPDIR}" ]; then
1506 TOPDIR=${CWDDIR}
1508 INCDIR="${TOPDIR}"include/
1509 SRCDIR="${TOPDIR}"src/
1511 MX_CWDDIR=${CWDDIR}
1512 MX_INCDIR=${INCDIR}
1513 MX_SRCDIR=${SRCDIR}
1514 PS_DOTLOCK_CWDDIR=${CWDDIR}
1515 PS_DOTLOCK_INCDIR=${INCDIR}
1516 PS_DOTLOCK_SRCDIR=${SRCDIR}
1517 SU_CWDDIR=${CWDDIR}
1518 SU_INCDIR=${INCDIR}
1519 SU_SRCDIR=${SRCDIR}
1521 # Our configuration options may at this point still contain shell snippets,
1522 # we need to evaluate them in order to get them expanded, and we need those
1523 # evaluated values not only in our new configuration file, but also at hand..
1524 msg_nonl 'Evaluating all configuration items ... '
1525 option_evaluate
1526 msg 'done'
1529 printf "#define VAL_UAGENT \"${VAL_SID}${VAL_MAILX}\"\n" >> ${newh}
1530 printf "VAL_UAGENT = ${VAL_SID}${VAL_MAILX}\n" >> ${newmk}
1531 printf "VAL_UAGENT=${VAL_SID}${VAL_MAILX};export VAL_UAGENT\n" >> ${newenv}
1533 # The problem now is that the test should be able to run in the users linker
1534 # and path environment, so we need to place the test: rule first, before
1535 # injecting the relevant make variables. Set up necessary environment
1536 if [ -z "${VERBOSE}" ]; then
1537 printf -- "ECHO_CC = @echo ' 'CC \$(@);\n" >> ${newmk}
1538 printf -- "ECHO_LINK = @echo ' 'LINK \$(@);\n" >> ${newmk}
1539 printf -- "ECHO_GEN = @echo ' 'GEN \$(@);\n" >> ${newmk}
1540 printf -- "ECHO_TEST = @\n" >> ${newmk}
1541 printf -- "ECHO_CMD = @echo ' CMD';\n" >> ${newmk}
1543 printf 'test: all\n\t$(ECHO_TEST)%s %smx-test.sh --check %s\n' \
1544 "${SHELL}" "${TOPDIR}" "./${VAL_SID}${VAL_MAILX}" >> ${newmk}
1545 printf \
1546 'testnj: all\n\t$(ECHO_TEST)%s %smx-test.sh --no-jobs --check %s\n' \
1547 "${SHELL}" "${TOPDIR}" "./${VAL_SID}${VAL_MAILX}" >> ${newmk}
1549 # Add the known utility and some other variables
1550 printf "#define VAL_PS_DOTLOCK \"${VAL_SID}${VAL_MAILX}-dotlock\"\n" >> ${newh}
1551 printf "VAL_PS_DOTLOCK = \$(VAL_UAGENT)-dotlock\n" >> ${newmk}
1552 printf 'VAL_PS_DOTLOCK=%s;export VAL_PS_DOTLOCK\n' \
1553 "${VAL_SID}${VAL_MAILX}-dotlock" >> ${newenv}
1554 if feat_yes DOTLOCK; then
1555 printf "#real below OPTIONAL_PS_DOTLOCK = \$(VAL_PS_DOTLOCK)\n" >> ${newmk}
1558 for i in \
1559 CWDDIR TOPDIR OBJDIR INCDIR SRCDIR \
1560 MX_CWDDIR MX_INCDIR MX_SRCDIR \
1561 PS_DOTLOCK_CWDDIR PS_DOTLOCK_INCDIR PS_DOTLOCK_SRCDIR \
1562 SU_CWDDIR SU_INCDIR SU_SRCDIR \
1563 awk basename cat chmod chown cp cmp grep getconf \
1564 ln mkdir mv pwd rm sed sort tee tr \
1565 MAKE MAKEFLAGS make SHELL strip \
1566 cksum; do
1567 eval j=\$${i}
1568 printf -- "${i} = ${j}\n" >> ${newmk}
1569 printf -- "${i}=%s;export ${i}\n" "`quote_string ${j}`" >> ${newenv}
1570 done
1572 # Build a basic set of INCS and LIBS according to user environment.
1573 C_INCLUDE_PATH="${INCDIR}:${SRCDIR}:${C_INCLUDE_PATH}"
1574 if path_is_absolute "${OBJDIR}"; then
1575 C_INCLUDE_PATH="${OBJDIR}:${C_INCLUDE_PATH}"
1576 else
1577 C_INCLUDE_PATH="${CWDDIR}${OBJDIR}:${C_INCLUDE_PATH}"
1579 C_INCLUDE_PATH="${CWDDIR}include:${C_INCLUDE_PATH}"
1581 path_check C_INCLUDE_PATH -I _INCS
1582 INCS="${INCS} ${_INCS}"
1583 path_check LD_LIBRARY_PATH -L _LIBS
1584 LIBS="${LIBS} ${_LIBS}"
1585 unset _INCS _LIBS
1586 export C_INCLUDE_PATH LD_LIBRARY_PATH
1588 # Some environments need runtime path flags to be able to go at all
1589 ld_runtime_flags
1591 ## Detect CC, whether we can use it, and possibly which CFLAGS we can use
1593 cc_setup
1594 cc_create_testfile
1595 cc_hello
1596 # This may also update ld_runtime_flags() (again)
1597 cc_flags
1599 for i in \
1600 COMMLINE \
1601 PATH C_INCLUDE_PATH LD_LIBRARY_PATH \
1602 CC CFLAGS LDFLAGS \
1603 INCS LIBS \
1604 OSFULLSPEC \
1605 ; do
1606 eval j="\$${i}"
1607 printf -- "${i}=%s;export ${i}\n" "`quote_string ${j}`" >> ${newenv}
1608 done
1610 # Now finally check whether we already have a configuration and if so, whether
1611 # all those parameters are still the same.. or something has actually changed
1612 config_updated=
1613 if [ -f ${env} ] && ${cmp} ${newenv} ${env} >/dev/null 2>&1; then
1614 msg 'Configuration is up-to-date'
1615 exit 0
1616 elif [ -f ${env} ]; then
1617 config_updated=1
1618 msg 'Configuration has been updated..'
1619 else
1620 msg 'Shiny configuration..'
1623 ### WE ARE STARTING OVER ###
1625 # Time to redefine helper 1
1626 config_exit() {
1627 ${rm} -f ${h} ${mk}
1628 exit ${1}
1631 ${mv} -f ${newenv} ${env}
1632 [ -f ${h} ] && ${mv} -f ${h} ${oldh}
1633 ${mv} -f ${newh} ${h} # Note this has still #ifdef mx_SOURCE open
1634 [ -f ${mk} ] && ${mv} -f ${mk} ${oldmk}
1635 ${mv} -f ${newmk} ${mk}
1637 ## Compile and link checking
1639 tmp3=${tmp0}3$$
1640 makefile=${tmp0}.mk
1642 # (No function since some shells loose non-exported variables in traps)
1643 trap "trap \"\" HUP INT TERM;\
1644 ${rm} -f ${oldh} ${h} ${oldmk} ${mk}; exit 1" \
1645 HUP INT TERM
1646 trap "trap \"\" HUP INT TERM EXIT;\
1647 ${rm} -rf ${oldh} ${oldmk} ${tmp0}.* ${tmp0}*" EXIT
1649 # Time to redefine helper 2
1650 msg() {
1651 fmt=${1}
1652 shift
1653 printf "@ ${fmt}\n" "${@}"
1654 printf -- "${fmt}\n" "${@}" >&5
1656 msg_nonl() {
1657 fmt=${1}
1658 shift
1659 printf "@ ${fmt}\n" "${@}"
1660 printf -- "${fmt}" "${@}" >&5
1664 ${cat} > ${makefile} << \!
1665 .SUFFIXES: .o .c .x .y
1666 .c.o:
1667 $(CC) -Dmx_SOURCE -I./ $(XINCS) $(CFLAGS) -o $(@) -c $(<)
1668 .c.x:
1669 $(CC) -Dmx_SOURCE -I./ $(XINCS) -E $(<) > $(@)
1671 $(CC) -Dmx_SOURCE -I./ $(XINCS) $(CFLAGS) $(LDFLAGS) -o $(@) $(<) $(XLIBS)
1674 ## Generics
1676 echo '#define VAL_BUILD_OS "'"${OS_ORIG_CASE}"'"' >> ${h}
1678 printf '#endif /* mx_SOURCE */\n\n' >> ${h} # Opened when it was $newh
1680 [ -n "${OS_DEFINES}" ] && printf \
1681 '#if defined mx_SOURCE || defined mx_EXT_SOURCE || defined su_SOURCE
1682 '"${OS_DEFINES}"'
1683 #endif /* mx_SOURCE || mx_EXT_SOURCE || su_SOURCE */
1685 ' >> ${h}
1687 ## SU
1689 i=`${getconf} PAGESIZE 2>/dev/null`
1690 [ $? -eq 0 ] || i=`${getconf} PAGE_SIZE 2>/dev/null`
1691 if [ $? -ne 0 ]; then
1692 msg 'Cannot query PAGESIZE via getconf(1), assuming 4096'
1693 i=0x1000
1695 printf '#define su_PAGE_SIZE %su\n' "${i}" >> ${h}
1697 # Generate SU <> OS error number mappings
1698 msg_nonl ' . OS error mapping table generated ... '
1699 feat_yes DEVEL && NV= || NV=noverbose
1700 SRCDIR="${SRCDIR}" TARGET="${h}" awk="${awk}" rm="${rm}" sort="${sort}" \
1701 ${SHELL} "${TOPDIR}"mk/su-make-errors.sh ${NV} compile_time || {
1702 msg 'no'
1703 config_exit 1
1705 msg 'yes'
1707 ## /SU
1709 ## Test for "basic" system-calls / functionality that is used by all parts
1710 ## of our program. Once this is done fork away BASE_LIBS and other BASE_*
1711 ## macros to be used by only the subprograms (potentially).
1713 if run_check clock_gettime 'clock_gettime(2)' \
1714 '#define mx_HAVE_CLOCK_GETTIME' << \!
1715 #include <time.h>
1716 # include <errno.h>
1717 int main(void){
1718 struct timespec ts;
1720 if(!clock_gettime(CLOCK_REALTIME, &ts) || errno != ENOSYS)
1721 return 0;
1722 return 1;
1725 then
1727 elif run_check clock_gettime 'clock_gettime(2) (via -lrt)' \
1728 '#define mx_HAVE_CLOCK_GETTIME' '-lrt' << \!
1729 #include <time.h>
1730 # include <errno.h>
1731 int main(void){
1732 struct timespec ts;
1734 if(!clock_gettime(CLOCK_REALTIME, &ts) || errno != ENOSYS)
1735 return 0;
1736 return 1;
1739 then
1741 elif run_check gettimeofday 'gettimeofday(2)' \
1742 '#define mx_HAVE_GETTIMEOFDAY' << \!
1743 #include <stdio.h> /* For C89 NULL */
1744 #include <sys/time.h>
1745 # include <errno.h>
1746 int main(void){
1747 struct timeval tv;
1749 if(!gettimeofday(&tv, NULL) || errno != ENOSYS)
1750 return 0;
1751 return 1;
1754 then
1756 else
1757 have_no_subsecond_time=1
1760 if run_check nanosleep 'nanosleep(2)' \
1761 '#define mx_HAVE_NANOSLEEP' << \!
1762 #include <time.h>
1763 # include <errno.h>
1764 int main(void){
1765 struct timespec ts;
1767 ts.tv_sec = 1;
1768 ts.tv_nsec = 100000;
1769 if(!nanosleep(&ts, NULL) || errno != ENOSYS)
1770 return 0;
1771 return 1;
1774 then
1776 elif run_check nanosleep 'nanosleep(2) (via -lrt)' \
1777 '#define mx_HAVE_NANOSLEEP' '-lrt' << \!
1778 #include <time.h>
1779 # include <errno.h>
1780 int main(void){
1781 struct timespec ts;
1783 ts.tv_sec = 1;
1784 ts.tv_nsec = 100000;
1785 if(!nanosleep(&ts, NULL) || errno != ENOSYS)
1786 return 0;
1787 return 1;
1790 then
1792 # link_check is enough for this, that function is so old, trust the proto
1793 elif link_check sleep 'sleep(3)' \
1794 '#define mx_HAVE_SLEEP' << \!
1795 #include <unistd.h>
1796 # include <errno.h>
1797 int main(void){
1798 if(!sleep(1) || errno != ENOSYS)
1799 return 0;
1800 return 1;
1803 then
1805 else
1806 msg 'ERROR: we require one of nanosleep(2) and sleep(3).'
1807 config_exit 1
1810 if run_check userdb 'gete?[gu]id(2), getpwuid(3), getpwnam(3)' << \!
1811 #include <pwd.h>
1812 #include <unistd.h>
1813 # include <errno.h>
1814 int main(void){
1815 struct passwd *pw;
1816 gid_t gid;
1817 uid_t uid;
1819 if((gid = getgid()) != 0)
1820 gid = getegid();
1821 if((uid = getuid()) != 0)
1822 uid = geteuid();
1823 if((pw = getpwuid(uid)) == NULL && errno == ENOSYS)
1824 return 1;
1825 if((pw = getpwnam("root")) == NULL && errno == ENOSYS)
1826 return 1;
1827 return 0;
1830 then
1832 else
1833 msg 'ERROR: we require user and group info / database searches.'
1834 msg 'That much Unix we indulge ourselves.'
1835 config_exit 1
1838 if link_check ftruncate 'ftruncate(2)' \
1839 '#define mx_HAVE_FTRUNCATE' << \!
1840 #include <unistd.h>
1841 #include <sys/types.h>
1842 int main(void){
1843 return (ftruncate(0, 0) != 0);
1846 then
1848 else
1849 # TODO support mx_HAVE_FTRUNCATE *everywhere*, do not require this syscall!
1850 msg 'ERROR: we require the ftruncate(2) system call.'
1851 config_exit 1
1854 if run_check sa_restart 'SA_RESTART (for sigaction(2))' << \!
1855 #include <signal.h>
1856 # include <errno.h>
1857 int main(void){
1858 struct sigaction nact, oact;
1860 nact.sa_handler = SIG_DFL;
1861 sigemptyset(&nact.sa_mask);
1862 nact.sa_flags = SA_RESTART;
1863 return !(!sigaction(SIGCHLD, &nact, &oact) || errno != ENOSYS);
1866 then
1868 else
1869 msg 'ERROR: we (yet) require the SA_RESTART flag for sigaction(2).'
1870 config_exit 1
1873 if link_check snprintf 'snprintf(3)' << \!
1874 #include <stdio.h>
1875 int main(void){
1876 char b[20];
1878 snprintf(b, sizeof b, "%s", "string");
1879 return 0;
1882 then
1884 else
1885 msg 'ERROR: we require the snprintf(3) function.'
1886 config_exit 1
1889 if link_check environ 'environ(3)' << \!
1890 #include <stdio.h> /* For C89 NULL */
1891 int main(void){
1892 extern char **environ;
1894 return environ[0] == NULL;
1897 then
1899 else
1900 msg 'ERROR: we require the environ(3) array for subprocess control.'
1901 config_exit 1
1904 if link_check setenv '(un)?setenv(3)' '#define mx_HAVE_SETENV' << \!
1905 #include <stdlib.h>
1906 int main(void){
1907 setenv("s-mailx", "i want to see it cute!", 1);
1908 unsetenv("s-mailx");
1909 return 0;
1912 then
1914 elif link_check setenv 'putenv(3)' '#define mx_HAVE_PUTENV' << \!
1915 #include <stdlib.h>
1916 int main(void){
1917 putenv("s-mailx=i want to see it cute!");
1918 return 0;
1921 then
1923 else
1924 msg 'ERROR: we require either the setenv(3) or putenv(3) functions.'
1925 config_exit 1
1928 if link_check termios 'termios.h and tc*(3) family' << \!
1929 #include <termios.h>
1930 int main(void){
1931 struct termios tios;
1932 speed_t ospeed;
1934 tcgetattr(0, &tios);
1935 tcsetattr(0, TCSANOW | TCSADRAIN | TCSAFLUSH, &tios);
1936 ospeed = ((tcgetattr(0, &tios) == -1) ? B9600 : cfgetospeed(&tios));
1937 return 0;
1940 then
1942 else
1943 msg 'ERROR: we require termios.h and the tc[gs]etattr() function family.'
1944 msg 'That much Unix we indulge ourselves.'
1945 config_exit 1
1948 ## optional stuff
1950 if link_check vsnprintf 'vsnprintf(3)' << \!
1951 #include <stdarg.h>
1952 #include <stdio.h>
1953 static void dome(char *buf, size_t blen, ...){
1954 va_list ap;
1956 va_start(ap, blen);
1957 vsnprintf(buf, blen, "%s", ap);
1958 va_end(ap);
1960 int main(void){
1961 char b[20];
1963 dome(b, sizeof b, "string");
1964 return 0;
1967 then
1969 else
1970 feat_bail_required ERRORS
1973 if [ "${have_vsnprintf}" = yes ]; then
1974 __va_copy() {
1975 link_check va_copy "va_copy(3) (as ${2})" \
1976 "#define mx_HAVE_N_VA_COPY
1977 #define n_va_copy ${2}" <<_EOT
1978 #include <stdarg.h>
1979 #include <stdio.h>
1980 #if ${1}
1981 # if defined __va_copy && !defined va_copy
1982 # define va_copy __va_copy
1983 # endif
1984 #endif
1985 static void dome2(char *buf, size_t blen, va_list src){
1986 va_list ap;
1988 va_copy(ap, src);
1989 vsnprintf(buf, blen, "%s", ap);
1990 va_end(ap);
1992 static void dome(char *buf, size_t blen, ...){
1993 va_list ap;
1995 va_start(ap, blen);
1996 dome2(buf, blen, ap);
1997 va_end(ap);
1999 int main(void){
2000 char b[20];
2002 dome(b, sizeof b, "string");
2003 return 0;
2005 _EOT
2007 __va_copy 0 va_copy || __va_copy 1 __va_copy
2010 run_check pathconf 'f?pathconf(2)' '#define mx_HAVE_PATHCONF' << \!
2011 #include <unistd.h>
2012 #include <errno.h>
2013 int main(void){
2014 int rv = 0;
2016 errno = 0;
2017 rv |= !(pathconf(".", _PC_NAME_MAX) >= 0 || errno == 0 || errno != ENOSYS);
2018 errno = 0;
2019 rv |= !(pathconf(".", _PC_PATH_MAX) >= 0 || errno == 0 || errno != ENOSYS);
2021 /* Only link check */
2022 fpathconf(0, _PC_NAME_MAX);
2024 return rv;
2028 run_check pipe2 'pipe2(2)' '#define mx_HAVE_PIPE2' << \!
2029 #include <fcntl.h>
2030 #include <unistd.h>
2031 # include <errno.h>
2032 int main(void){
2033 int fds[2];
2035 if(!pipe2(fds, O_CLOEXEC) || errno != ENOSYS)
2036 return 0;
2037 return 1;
2041 link_check tcgetwinsize 'tcgetwinsize(3)' '#define mx_HAVE_TCGETWINSIZE' << \!
2042 #include <termios.h>
2043 int main(void){
2044 struct winsize ws;
2046 tcgetwinsize(0, &ws);
2047 return 0;
2051 # We use this only then for now (need NOW+1)
2052 run_check utimensat 'utimensat(2)' '#define mx_HAVE_UTIMENSAT' << \!
2053 #include <fcntl.h> /* For AT_* */
2054 #include <sys/stat.h>
2055 # include <errno.h>
2056 int main(void){
2057 struct timespec ts[2];
2059 ts[0].tv_nsec = UTIME_NOW;
2060 ts[1].tv_nsec = UTIME_OMIT;
2061 if(!utimensat(AT_FDCWD, "", ts, 0) || errno != ENOSYS)
2062 return 0;
2063 return 1;
2069 link_check putc_unlocked 'putc_unlocked(3)' \
2070 '#define mx_HAVE_PUTC_UNLOCKED' <<\!
2071 #include <stdio.h>
2072 int main(void){
2073 putc_unlocked('@', stdout);
2074 return 0;
2078 link_check fchdir 'fchdir(3)' '#define mx_HAVE_FCHDIR' << \!
2079 #include <unistd.h>
2080 int main(void){
2081 fchdir(0);
2082 return 0;
2086 if link_check realpath 'realpath(3)' '#define mx_HAVE_REALPATH' << \!
2087 #include <stdlib.h>
2088 int main(void){
2089 char x_buf[4096], *x = realpath(".", x_buf);
2091 return (x != NULL) ? 0 : 1;
2094 then
2095 if run_check realpath_malloc 'realpath(3) takes NULL' \
2096 '#define mx_HAVE_REALPATH_NULL' << \!
2097 #include <stdlib.h>
2098 int main(void){
2099 char *x = realpath(".", NULL);
2101 if(x != NULL)
2102 free(x);
2103 return (x != NULL) ? 0 : 1;
2106 then
2111 link_check tm_gmtoff 'struct tm::tm_gmtoff' '#define mx_HAVE_TM_GMTOFF' << \!
2112 #include <time.h>
2113 int main(void){
2114 time_t t;
2116 t = time((void*)0);
2117 return gmtime(&t)->tm_gmtoff != 0;
2122 ## optional and selectable
2125 if feat_yes DOTLOCK; then
2126 if run_check readlink 'readlink(2)' << \!
2127 #include <unistd.h>
2128 # include <errno.h>
2129 int main(void){
2130 char buf[128];
2132 if(!readlink("here", buf, sizeof buf) || errno != ENOSYS)
2133 return 0;
2134 return 1;
2137 then
2139 else
2140 feat_bail_required DOTLOCK
2144 if feat_yes DOTLOCK; then
2145 if run_check fchown 'fchown(2)' << \!
2146 #include <unistd.h>
2147 # include <errno.h>
2148 int main(void){
2149 if(!fchown(0, 0, 0) || errno != ENOSYS)
2150 return 0;
2151 return 1;
2154 then
2156 else
2157 feat_bail_required DOTLOCK
2161 if feat_yes DOTLOCK; then
2162 if run_check prctl_dumpable 'prctl(2) + PR_SET_DUMPABLE' \
2163 '#define mx_HAVE_PRCTL_DUMPABLE' << \!
2164 #include <sys/prctl.h>
2165 # include <errno.h>
2166 int main(void){
2167 if(!prctl(PR_SET_DUMPABLE, 0) || errno != ENOSYS)
2168 return 0;
2169 return 1;
2172 then
2174 elif run_check procctl_trace_ctl 'procctl(2) + PROC_TRACE_CTL_DISABLE' \
2175 '#define mx_HAVE_PROCCTL_TRACE_CTL' << \!
2176 #include <sys/procctl.h>
2177 #include <unistd.h>
2178 # include <errno.h>
2179 int main(void){
2180 int disable_trace = PROC_TRACE_CTL_DISABLE;
2181 if(procctl(P_PID, getpid(), PROC_TRACE_CTL, &disable_trace) != -1 ||
2182 errno != ENOSYS)
2183 return 0;
2184 return 1;
2187 then
2189 elif run_check prtrace_deny 'ptrace(2) + PT_DENY_ATTACH' \
2190 '#define mx_HAVE_PTRACE_DENY' << \!
2191 #include <sys/ptrace.h>
2192 # include <errno.h>
2193 int main(void){
2194 if(ptrace(PT_DENY_ATTACH, 0, 0, 0) != -1 || errno != ENOSYS)
2195 return 0;
2196 return 1;
2199 then
2201 elif run_check setpflags_protect 'setpflags(2) + __PROC_PROTECT' \
2202 '#define mx_HAVE_SETPFLAGS_PROTECT' << \!
2203 #include <priv.h>
2204 # include <errno.h>
2205 int main(void){
2206 if(!setpflags(__PROC_PROTECT, 1) || errno != ENOSYS)
2207 return 0;
2208 return 1;
2211 then
2216 ### FORK AWAY SHARED BASE SERIES ###
2218 BASE_CFLAGS=${CFLAGS}
2219 BASE_INCS=`squeeze_ws "${INCS}"`
2220 BASE_LDFLAGS=${LDFLAGS}
2221 BASE_LIBS=`squeeze_ws "${LIBS}"`
2223 ## The remains are expected to be used only by the main MUA binary!
2224 ## (And possibly by test programs)
2226 OPT_LOCALES=0
2227 link_check setlocale 'setlocale(3)' '#define mx_HAVE_SETLOCALE' << \!
2228 #include <locale.h>
2229 int main(void){
2230 setlocale(LC_ALL, "");
2231 return 0;
2234 [ -n "${have_setlocale}" ] && OPT_LOCALES=1
2236 OPT_MULTIBYTE_CHARSETS=0
2237 OPT_WIDE_GLYPHS=0
2238 OPT_TERMINAL_CHARSET=0
2239 if [ -n "${have_setlocale}" ]; then
2240 link_check c90amend1 'ISO/IEC 9899:1990/Amendment 1:1995' \
2241 '#define mx_HAVE_C90AMEND1' << \!
2242 #include <limits.h>
2243 #include <stdlib.h>
2244 #include <wchar.h>
2245 #include <wctype.h>
2246 int main(void){
2247 char mbb[MB_LEN_MAX + 1];
2248 wchar_t wc;
2250 iswprint(L'c');
2251 towupper(L'c');
2252 mbtowc(&wc, "x", 1);
2253 mbrtowc(&wc, "x", 1, NULL);
2254 wctomb(mbb, wc);
2255 return (mblen("\0", 1) == 0);
2258 [ -n "${have_c90amend1}" ] && OPT_MULTIBYTE_CHARSETS=1
2260 if [ -n "${have_c90amend1}" ]; then
2261 link_check wcwidth 'wcwidth(3)' '#define mx_HAVE_WCWIDTH' << \!
2262 #include <wchar.h>
2263 int main(void){
2264 wcwidth(L'c');
2265 return 0;
2268 [ -n "${have_wcwidth}" ] && OPT_WIDE_GLYPHS=1
2271 link_check nl_langinfo 'nl_langinfo(3)' '#define mx_HAVE_NL_LANGINFO' << \!
2272 #include <langinfo.h>
2273 #include <stdlib.h>
2274 int main(void){
2275 nl_langinfo(DAY_1);
2276 return (nl_langinfo(CODESET) == NULL);
2279 [ -n "${have_nl_langinfo}" ] && OPT_TERMINAL_CHARSET=1
2280 fi # have_setlocale
2282 link_check fnmatch 'fnmatch(3)' '#define mx_HAVE_FNMATCH' << \!
2283 #include <fnmatch.h>
2284 int main(void){
2285 return (fnmatch("*", ".", FNM_PATHNAME | FNM_PERIOD) == FNM_NOMATCH);
2289 link_check dirent_d_type 'struct dirent.d_type' \
2290 '#define mx_HAVE_DIRENT_TYPE' << \!
2291 #include <dirent.h>
2292 int main(void){
2293 struct dirent de;
2294 return !(de.d_type == DT_UNKNOWN ||
2295 de.d_type == DT_DIR || de.d_type == DT_LNK);
2300 ## optional and selectable
2303 # OPT_ICONV, VAL_ICONV {{{
2304 if feat_yes ICONV; then
2305 if val_allof VAL_ICONV libc,iconv; then
2307 else
2308 msg 'ERROR: VAL_ICONV with invalid entries: %s' "${VAL_ICONV}"
2309 config_exit 1
2312 # To be able to create tests we need to figure out which replacement
2313 # sequence the iconv(3) implementation creates
2314 ${cat} > ${tmp2}.c << \!
2315 #include <stdio.h> /* For C89 NULL */
2316 #include <string.h>
2317 #include <iconv.h>
2318 int main(void){
2319 char inb[16], oub[16], *inbp, *oubp;
2320 iconv_t id;
2321 size_t inl, oul;
2322 int rv;
2324 /* U+2013 */
2325 memcpy(inbp = inb, "\342\200\223", sizeof("\342\200\223"));
2326 inl = sizeof("\342\200\223") -1;
2327 oul = sizeof oub;
2328 oubp = oub;
2330 rv = 1;
2331 if((id = iconv_open("us-ascii", "utf-8")) == (iconv_t)-1)
2332 goto jleave;
2334 rv = 14;
2335 if(iconv(id, &inbp, &inl, &oubp, &oul) == (size_t)-1)
2336 goto jleave;
2338 *oubp = '\0';
2339 oul = (size_t)(oubp - oub);
2340 if(oul == 0)
2341 goto jleave;
2342 /* Character-wise replacement? */
2343 if(oul == 1){
2344 rv = 2;
2345 if(oub[0] == '?')
2346 goto jleave;
2347 rv = 3;
2348 if(oub[0] == '*')
2349 goto jleave;
2350 rv = 14;
2351 goto jleave;
2354 /* Byte-wise replacement? */
2355 if(oul == sizeof("\342\200\223") -1){
2356 rv = 12;
2357 if(!memcmp(oub, "???????", sizeof("\342\200\223") -1))
2358 goto jleave;
2359 rv = 13;
2360 if(!memcmp(oub, "*******", sizeof("\342\200\223") -1))
2361 goto jleave;
2362 rv = 14;
2365 jleave:
2366 if(id != (iconv_t)-1)
2367 iconv_close(id);
2369 return rv;
2373 val_iconv_libc() {
2374 < ${tmp2}.c link_check iconv 'iconv(3)' \
2375 '#define mx_HAVE_ICONV'
2376 [ $? -eq 0 ] && return 0
2377 < ${tmp2}.c link_check iconv 'iconv(3), GNU libiconv redirect aware' \
2378 '#define mx_HAVE_ICONV' '' '-DLIBICONV_PLUG'
2381 val_iconv_iconv() {
2382 < ${tmp2}.c link_check iconv 'iconv(3) functionality (via -liconv)' \
2383 '#define mx_HAVE_ICONV' '-liconv'
2386 val_iconv_bye() {
2387 feat_bail_required ICONV
2390 oifs=${IFS}
2391 IFS=", "
2392 VAL_ICONV="${VAL_ICONV},bye"
2393 set -- ${VAL_ICONV}
2394 IFS=${oifs}
2395 for randfun
2397 eval val_iconv_$randfun && break
2398 done
2400 if feat_yes ICONV && feat_no CROSS_BUILD; then
2401 { ${tmp}; } >/dev/null 2>&1
2402 case ${?} in
2404 msg 'WARN: disabling ICONV due to faulty conversion/restrictions'
2405 feat_bail_required ICONV
2407 2) echo 'MAILX_ICONV_MODE=2;export MAILX_ICONV_MODE;' >> ${env};;
2408 3) echo 'MAILX_ICONV_MODE=3;export MAILX_ICONV_MODE;' >> ${env};;
2409 12) echo 'MAILX_ICONV_MODE=12;export MAILX_ICONV_MODE;' >> ${env};;
2410 13) echo 'MAILX_ICONV_MODE=13;export MAILX_ICONV_MODE;' >> ${env};;
2411 *) msg 'WARN: will restrict iconv(3) tests due to unknown replacement';;
2412 esac
2414 else
2415 feat_is_disabled ICONV
2417 # }}} OPT_ICONV, VAL_ICONV
2419 if feat_yes NET; then
2420 ${cat} > ${tmp2}.c << \!
2421 #include <sys/types.h>
2422 #include <sys/socket.h>
2423 #include <sys/un.h>
2424 # include <errno.h>
2425 int main(void){
2426 struct sockaddr_un soun;
2428 if(socket(AF_UNIX, SOCK_STREAM, 0) == -1 && errno == ENOSYS)
2429 return 1;
2430 if(connect(0, (struct sockaddr*)&soun, 0) == -1 && errno == ENOSYS)
2431 return 1;
2432 if(shutdown(0, SHUT_RD | SHUT_WR | SHUT_RDWR) == -1 && errno == ENOSYS)
2433 return 1;
2434 return 0;
2438 < ${tmp2}.c run_check af_unix 'AF_UNIX sockets' \
2439 '#define mx_HAVE_UNIX_SOCKETS' ||
2440 < ${tmp2}.c run_check af_unix 'AF_UNIX sockets (via -lnsl)' \
2441 '#define mx_HAVE_UNIX_SOCKETS' '-lnsl' ||
2442 < ${tmp2}.c run_check af_unix 'AF_UNIX sockets (via -lsocket -lnsl)' \
2443 '#define mx_HAVE_UNIX_SOCKETS' '-lsocket -lnsl'
2446 if feat_yes NET; then
2447 ${cat} > ${tmp2}.c << \!
2448 #include <sys/types.h>
2449 #include <sys/socket.h>
2450 #include <netinet/in.h>
2451 # include <errno.h>
2452 int main(void){
2453 struct sockaddr s;
2455 if(socket(AF_INET, SOCK_STREAM, 0) == -1 && errno == ENOSYS)
2456 return 1;
2457 if(connect(0, &s, 0) == -1 && errno == ENOSYS)
2458 return 1;
2459 return 0;
2463 < ${tmp2}.c run_check sockets 'sockets' \
2464 '#define mx_HAVE_NET' ||
2465 < ${tmp2}.c run_check sockets 'sockets (via -lnsl)' \
2466 '#define mx_HAVE_NET' '-lnsl' ||
2467 < ${tmp2}.c run_check sockets 'sockets (via -lsocket -lnsl)' \
2468 '#define mx_HAVE_NET' '-lsocket -lnsl' ||
2469 feat_bail_required NET
2470 else
2471 feat_is_disabled NET
2472 fi # feat_yes NET
2474 feat_yes NET &&
2475 link_check sockopt '[gs]etsockopt(2)' '#define mx_HAVE_SOCKOPT' << \!
2476 #include <sys/socket.h>
2477 #include <stdlib.h>
2478 # include <errno.h>
2479 int main(void){
2480 socklen_t sol;
2481 int sockfd = 3, soe;
2483 sol = sizeof soe;
2484 if(getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &soe, &sol) == -1 &&
2485 errno == ENOSYS)
2486 return 1;
2487 if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, NULL, 0) == -1 &&
2488 errno == ENOSYS)
2489 return 1;
2490 return 0;
2494 feat_yes NET &&
2495 link_check nonblocksock 'non-blocking sockets' \
2496 '#define mx_HAVE_NONBLOCKSOCK' << \!
2497 #include <sys/types.h>
2498 #include <sys/select.h>
2499 #include <sys/socket.h>
2500 #include <sys/time.h>
2501 #include <arpa/inet.h>
2502 #include <netinet/in.h>
2503 #include <fcntl.h>
2504 #include <stdlib.h>
2505 #include <string.h> /* FD_ZERO() SunOS 5.9, at least */
2506 #include <unistd.h>
2507 # include <errno.h>
2508 int main(void){
2509 fd_set fdset;
2510 struct timeval tv;
2511 struct sockaddr_in sin;
2512 socklen_t sol;
2513 int sofd, soe;
2515 if((sofd = socket(AF_INET, SOCK_STREAM, 0)) == -1 && errno == ENOSYS)
2516 return 1;
2517 if(fcntl(sofd, F_SETFL, O_NONBLOCK) != 0)
2518 return 1;
2520 sin.sin_family = AF_INET;
2521 sin.sin_addr.s_addr = inet_addr("127.0.0.1");
2522 sin.sin_port = htons(80);
2523 if(connect(sofd, &sin, sizeof sin) == -1 && errno == ENOSYS)
2524 return 1;
2526 FD_ZERO(&fdset);
2527 FD_SET(sofd, &fdset);
2528 tv.tv_sec = 10;
2529 tv.tv_usec = 0;
2530 if((soe = select(sofd + 1, NULL, &fdset, NULL, &tv)) == 1){
2531 sol = sizeof soe;
2532 getsockopt(sofd, SOL_SOCKET, SO_ERROR, &soe, &sol);
2533 if(soe == 0)
2534 return 0;
2535 }else if(soe == -1 && errno == ENOSYS)
2536 return 1;
2538 close(sofd);
2539 return 0;
2543 if feat_yes NET; then
2544 link_check getaddrinfo 'getaddrinfo(3)' \
2545 '#define mx_HAVE_GETADDRINFO' << \!
2546 #include <sys/types.h>
2547 #include <sys/socket.h>
2548 #include <stdio.h>
2549 #include <netdb.h>
2550 int main(void){
2551 struct addrinfo a, *ap;
2552 int lrv;
2554 switch((lrv = getaddrinfo("foo", "0", &a, &ap))){
2555 case EAI_NONAME:
2556 case EAI_SERVICE:
2557 default:
2558 fprintf(stderr, "%s\n", gai_strerror(lrv));
2559 case 0:
2560 break;
2562 return 0;
2567 if feat_yes NET && [ -z "${have_getaddrinfo}" ]; then
2568 compile_check arpa_inet_h '<arpa/inet.h>' \
2569 '#define mx_HAVE_ARPA_INET_H' << \!
2570 #include <sys/types.h>
2571 #include <sys/socket.h>
2572 #include <netdb.h>
2573 #include <netinet/in.h>
2574 #include <arpa/inet.h>
2577 ${cat} > ${tmp2}.c << \!
2578 #include <sys/types.h>
2579 #include <sys/socket.h>
2580 #include <stdio.h>
2581 #include <string.h>
2582 #include <netdb.h>
2583 #include <netinet/in.h>
2584 #ifdef mx_HAVE_ARPA_INET_H
2585 #include <arpa/inet.h>
2586 #endif
2587 int main(void){
2588 struct sockaddr_in servaddr;
2589 unsigned short portno;
2590 struct servent *ep;
2591 struct hostent *hp;
2592 struct in_addr **pptr;
2594 portno = 0;
2595 if((ep = getservbyname("POPPY-PORT", "tcp")) != NULL)
2596 portno = (unsigned short)ep->s_port;
2598 if((hp = gethostbyname("POPPY-HOST")) != NULL){
2599 pptr = (struct in_addr**)hp->h_addr_list;
2600 if(hp->h_addrtype != AF_INET)
2601 fprintf(stderr, "au\n");
2602 }else{
2603 switch(h_errno){
2604 case HOST_NOT_FOUND:
2605 case TRY_AGAIN:
2606 case NO_RECOVERY:
2607 case NO_DATA:
2608 break;
2609 default:
2610 fprintf(stderr, "au\n");
2611 break;
2615 memset(&servaddr, 0, sizeof servaddr);
2616 servaddr.sin_family = AF_INET;
2617 servaddr.sin_port = htons(portno);
2618 memcpy(&servaddr.sin_addr, *pptr, sizeof(struct in_addr));
2619 fprintf(stderr, "Would connect to %s:%d ...\n",
2620 inet_ntoa(**pptr), (int)portno);
2621 return 0;
2625 < ${tmp2}.c link_check gethostbyname 'get(serv|host)byname(3)' ||
2626 < ${tmp2}.c link_check gethostbyname \
2627 'get(serv|host)byname(3) (via -nsl)' '' '-lnsl' ||
2628 < ${tmp2}.c link_check gethostbyname \
2629 'get(serv|host)byname(3) (via -lsocket -nsl)' \
2630 '' '-lsocket -lnsl' ||
2631 feat_bail_required NET
2634 feat_yes NET && [ -n "${have_sockopt}" ] &&
2635 link_check so_xtimeo 'SO_{RCV,SND}TIMEO' '#define mx_HAVE_SO_XTIMEO' << \!
2636 #include <sys/socket.h>
2637 #include <stdlib.h>
2638 int main(void){
2639 struct timeval tv;
2640 int sockfd = 3;
2642 tv.tv_sec = 42;
2643 tv.tv_usec = 21;
2644 setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof tv);
2645 setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv);
2646 return 0;
2650 feat_yes NET && [ -n "${have_sockopt}" ] &&
2651 link_check so_linger 'SO_LINGER' '#define mx_HAVE_SO_LINGER' << \!
2652 #include <sys/socket.h>
2653 #include <stdlib.h>
2654 int main(void){
2655 struct linger li;
2656 int sockfd = 3;
2658 li.l_onoff = 1;
2659 li.l_linger = 42;
2660 setsockopt(sockfd, SOL_SOCKET, SO_LINGER, &li, sizeof li);
2661 return 0;
2665 VAL_TLS_FEATURES=
2666 if feat_yes TLS; then # {{{
2667 # {{{ LibreSSL decided to define OPENSSL_VERSION_NUMBER with a useless value
2668 # instead of keeping it at the one that corresponds to the OpenSSL at fork
2669 # time: we need to test it first in order to get things right
2670 if compile_check _xtls 'TLS (LibreSSL)' \
2671 '#define mx_HAVE_TLS mx_TLS_IMPL_RESSL
2672 #define mx_HAVE_XTLS 0 /* 0 for LibreSSL */' << \!
2673 #include <openssl/opensslv.h>
2674 #ifdef LIBRESSL_VERSION_NUMBER
2675 #else
2676 # error nope
2677 #endif
2678 int nonempty;
2680 then
2681 ossl_v1_1=
2682 VAL_TLS_FEATURES=libressl,-tls-rand-file
2683 # TODO BORINGSSL, generalize this mess!
2684 elif compile_check _xtls 'TLS (OpenSSL >= v3.0.0)' \
2685 '#define mx_HAVE_TLS mx_TLS_IMPL_OPENSSL
2686 #define mx_HAVE_XTLS 0x30000' << \!
2687 #include <openssl/opensslv.h>
2688 #if OPENSSL_VERSION_NUMBER + 0 >= 0x30000000L
2689 #else
2690 # error nope
2691 #endif
2692 int nonempty;
2694 then
2695 ossl_v1_1=1
2696 VAL_TLS_FEATURES=libssl-0x30000,-tls-rand-file
2697 elif compile_check _xtls 'TLS (OpenSSL >= v1.1.1)' \
2698 '#define mx_HAVE_TLS mx_TLS_IMPL_OPENSSL
2699 #define mx_HAVE_XTLS 0x10101' << \!
2700 #include <openssl/opensslv.h>
2701 #if OPENSSL_VERSION_NUMBER + 0 >= 0x1010100fL
2702 #else
2703 # error nope
2704 #endif
2705 int nonempty;
2707 then
2708 ossl_v1_1=1
2709 VAL_TLS_FEATURES=libssl-0x10100,-tls-rand-file
2710 elif compile_check _xtls 'TLS (OpenSSL >= v1.1.0)' \
2711 '#define mx_HAVE_TLS mx_TLS_IMPL_OPENSSL
2712 #define mx_HAVE_XTLS 0x10100
2713 #define mx_XTLS_HAVE_RAND_FILE' << \!
2714 #include <openssl/opensslv.h>
2715 #if OPENSSL_VERSION_NUMBER + 0 >= 0x10100000L
2716 #else
2717 # error nope
2718 #endif
2719 int nonempty;
2721 then
2722 ossl_v1_1=1
2723 VAL_TLS_FEATURES=libssl-0x10100,+tls-rand-file
2724 elif compile_check _xtls 'TLS (OpenSSL)' \
2725 '#define mx_HAVE_TLS mx_TLS_IMPL_OPENSSL
2726 #define mx_HAVE_XTLS 0x10000
2727 #define mx_XTLS_HAVE_RAND_FILE' << \!
2728 #include <openssl/opensslv.h>
2729 #ifdef OPENSSL_VERSION_NUMBER
2730 #else
2731 # error nope
2732 #endif
2733 int nonempty;
2735 then
2736 ossl_v1_1=
2737 VAL_TLS_FEATURES=libssl-0x10000,+tls-rand-file
2738 else
2739 feat_bail_required TLS
2740 fi # }}}
2742 if feat_yes TLS; then # {{{
2743 if [ -n "${ossl_v1_1}" ]; then
2744 without_check 1 xtls 'TLS new style TLS_client_method(3ssl)' \
2745 '#define mx_XTLS_CLIENT_METHOD TLS_client_method' \
2746 '-lssl -lcrypto'
2747 elif link_check xtls 'TLS new style TLS_client_method(3ssl)' \
2748 '#define mx_XTLS_CLIENT_METHOD TLS_client_method' \
2749 '-lssl -lcrypto' << \!
2750 #include <openssl/ssl.h>
2751 #include <openssl/err.h>
2752 #include <openssl/x509v3.h>
2753 #include <openssl/x509.h>
2754 #include <openssl/rand.h>
2755 int main(void){
2756 SSL_CTX *ctx = SSL_CTX_new(TLS_client_method());
2758 SSL_CTX_free(ctx);
2759 PEM_read_PrivateKey(0, 0, 0, 0);
2760 return 0;
2763 then
2765 elif link_check xtls 'TLS old style SSLv23_client_method(3ssl)' \
2766 '#define mx_XTLS_CLIENT_METHOD SSLv23_client_method' \
2767 '-lssl -lcrypto' << \!
2768 #include <openssl/ssl.h>
2769 #include <openssl/err.h>
2770 #include <openssl/x509v3.h>
2771 #include <openssl/x509.h>
2772 #include <openssl/rand.h>
2773 int main(void){
2774 SSL_CTX *ctx = SSL_CTX_new(SSLv23_client_method());
2776 SSL_CTX_free(ctx);
2777 PEM_read_PrivateKey(0, 0, 0, 0);
2778 return 0;
2781 then
2783 else
2784 feat_bail_required TLS
2786 fi # }}}
2788 if feat_yes TLS; then # {{{
2789 if [ -n "${ossl_v1_1}" ]; then
2790 without_check 1 xtls_stack_of '*SSL STACK_OF()' \
2791 '#define mx_XTLS_HAVE_STACK_OF'
2792 elif compile_check xtls_stack_of '*SSL STACK_OF()' \
2793 '#define mx_XTLS_HAVE_STACK_OF' << \!
2794 #include <stdio.h> /* For C89 NULL */
2795 #include <openssl/ssl.h>
2796 #include <openssl/err.h>
2797 #include <openssl/x509v3.h>
2798 #include <openssl/x509.h>
2799 #include <openssl/rand.h>
2800 int main(void){
2801 STACK_OF(GENERAL_NAME) *gens = NULL;
2803 printf("%p", gens); /* to use it */
2804 return 0;
2807 then
2811 if [ -n "${ossl_v1_1}" ]; then
2812 without_check 1 xtls_conf 'TLS OpenSSL_modules_load_file(3ssl)' \
2813 '#define mx_XTLS_HAVE_CONFIG'
2814 VAL_TLS_FEATURES="${VAL_TLS_FEATURES},+modules-load-file"
2815 elif link_check xtls_conf \
2816 'TLS OpenSSL_modules_load_file(3ssl) support' \
2817 '#define mx_XTLS_HAVE_CONFIG' << \!
2818 #include <stdio.h> /* For C89 NULL */
2819 #include <openssl/conf.h>
2820 int main(void){
2821 CONF_modules_load_file(NULL, NULL, CONF_MFLAGS_IGNORE_MISSING_FILE);
2822 #if mx_HAVE_XTLS < 0x10100
2823 CONF_modules_free();
2824 #endif
2825 return 0;
2828 then
2829 VAL_TLS_FEATURES="${VAL_TLS_FEATURES},+modules-load-file"
2830 else
2831 VAL_TLS_FEATURES="${VAL_TLS_FEATURES},-modules-load-file"
2834 if [ -n "${ossl_v1_1}" ]; then
2835 without_check 1 xtls_conf_ctx 'TLS SSL_CONF_CTX support' \
2836 '#define mx_XTLS_HAVE_CONF_CTX'
2837 VAL_TLS_FEATURES="${VAL_TLS_FEATURES},+conf-ctx"
2838 elif link_check xtls_conf_ctx 'TLS SSL_CONF_CTX support' \
2839 '#define mx_XTLS_HAVE_CONF_CTX' << \!
2840 #include <openssl/ssl.h>
2841 #include <openssl/err.h>
2842 int main(void){
2843 SSL_CTX *ctx = SSL_CTX_new(mx_XTLS_CLIENT_METHOD());
2844 SSL_CONF_CTX *cctx = SSL_CONF_CTX_new();
2846 SSL_CONF_CTX_set_flags(cctx,
2847 SSL_CONF_FLAG_FILE | SSL_CONF_FLAG_CLIENT |
2848 SSL_CONF_FLAG_CERTIFICATE | SSL_CONF_FLAG_SHOW_ERRORS);
2849 SSL_CONF_CTX_set_ssl_ctx(cctx, ctx);
2850 SSL_CONF_cmd(cctx, "Protocol", "ALL");
2851 SSL_CONF_CTX_finish(cctx);
2852 SSL_CONF_CTX_free(cctx);
2853 SSL_CTX_free(ctx);
2854 return 0;
2857 then
2858 VAL_TLS_FEATURES="${VAL_TLS_FEATURES},+conf-ctx"
2859 else
2860 VAL_TLS_FEATURES="${VAL_TLS_FEATURES},-conf-ctx"
2863 if [ -n "${ossl_v1_1}" ]; then
2864 without_check 1 xtls_ctx_config 'TLS SSL_CTX_config(3ssl)' \
2865 '#define mx_XTLS_HAVE_CTX_CONFIG'
2866 VAL_TLS_FEATURES="${VAL_TLS_FEATURES},+ctx-config"
2867 elif [ -n "${have_xtls_conf}" ] && [ -n "${have_xtls_conf_ctx}" ] &&
2868 link_check xtls_ctx_config 'TLS SSL_CTX_config(3ssl)' \
2869 '#define mx_XTLS_HAVE_CTX_CONFIG' << \!
2870 #include <stdio.h> /* For C89 NULL */
2871 #include <openssl/ssl.h>
2872 int main(void){
2873 SSL_CTX_config(NULL, "SOMEVAL");
2874 return 0;
2877 then
2878 VAL_TLS_FEATURES="${VAL_TLS_FEATURES},+ctx-config"
2879 else
2880 VAL_TLS_FEATURES="${VAL_TLS_FEATURES},-ctx-config"
2883 if [ -n "${ossl_v1_1}" ] && [ -n "${have_xtls_conf_ctx}" ]; then
2884 without_check 1 xtls_set_maxmin_proto \
2885 'TLS SSL_CTX_set_min_proto_version(3ssl)' \
2886 '#define mx_XTLS_HAVE_SET_MIN_PROTO_VERSION'
2887 VAL_TLS_FEATURES="${VAL_TLS_FEATURES},+ctx-set-maxmin-proto"
2888 elif link_check xtls_set_maxmin_proto \
2889 'TLS SSL_CTX_set_min_proto_version(3ssl)' \
2890 '#define mx_XTLS_HAVE_SET_MIN_PROTO_VERSION' << \!
2891 #include <stdio.h> /* For C89 NULL */
2892 #include <openssl/ssl.h>
2893 int main(void){
2894 SSL_CTX_set_min_proto_version(NULL, 0);
2895 SSL_CTX_set_max_proto_version(NULL, 10);
2896 return 0;
2899 then
2900 VAL_TLS_FEATURES="${VAL_TLS_FEATURES},+ctx-set-maxmin-proto"
2901 else
2902 VAL_TLS_FEATURES="${VAL_TLS_FEATURES},-ctx-set-maxmin-proto"
2905 if [ -n "${ossl_v1_1}" ] && [ -n "${have_xtls_conf_ctx}" ]; then
2906 without_check 1 xtls_set_ciphersuites \
2907 'TLSv1.3 SSL_CTX_set_ciphersuites(3ssl)' \
2908 '#define mx_XTLS_HAVE_SET_CIPHERSUITES'
2909 VAL_TLS_FEATURES="${VAL_TLS_FEATURES},+ctx-set-ciphersuites"
2910 elif link_check xtls_set_ciphersuites \
2911 'TLSv1.3 SSL_CTX_set_ciphersuites(3ssl)' \
2912 '#define mx_XTLS_HAVE_SET_CIPHERSUITES' << \!
2913 #include <stdio.h> /* For C89 NULL */
2914 #include <openssl/ssl.h>
2915 int main(void){
2916 SSL_CTX_set_ciphersuites(NULL, NULL);
2917 return 0;
2920 then
2921 VAL_TLS_FEATURES="${VAL_TLS_FEATURES},+ctx-set-ciphersuites"
2922 else
2923 VAL_TLS_FEATURES="${VAL_TLS_FEATURES},-ctx-set-ciphersuites"
2925 fi # feat_yes TLS }}}
2927 if feat_yes TLS; then # digest etc algorithms {{{
2928 if feat_yes TLS_ALL_ALGORITHMS; then
2929 if [ -n "${ossl_v1_1}" ]; then
2930 without_check 1 tls_all_algo 'TLS_ALL_ALGORITHMS support' \
2931 '#define mx_HAVE_TLS_ALL_ALGORITHMS'
2932 elif link_check tls_all_algo 'TLS all-algorithms support' \
2933 '#define mx_HAVE_TLS_ALL_ALGORITHMS' << \!
2934 #include <openssl/evp.h>
2935 int main(void){
2936 OpenSSL_add_all_algorithms();
2937 EVP_get_cipherbyname("two cents i never exist");
2938 #if mx_HAVE_XTLS < 0x10100
2939 EVP_cleanup();
2940 #endif
2941 return 0;
2944 then
2946 else
2947 feat_bail_required TLS_ALL_ALGORITHMS
2949 elif [ -n "${ossl_v1_1}" ]; then
2950 without_check 1 tls_all_algo \
2951 'TLS all-algorithms (always available in v1.1.0+)' \
2952 '#define mx_HAVE_TLS_ALL_ALGORITHMS'
2955 # Blake
2956 link_check tls_blake2 'TLS: BLAKE2 digests' \
2957 '#define mx_XTLS_HAVE_BLAKE2' << \!
2958 #include <openssl/evp.h>
2959 int main(void){
2960 EVP_blake2b512();
2961 EVP_blake2s256();
2962 return 0;
2966 # SHA-3
2967 link_check tls_sha3 'TLS: SHA-3 digests' \
2968 '#define mx_XTLS_HAVE_SHA3' << \!
2969 #include <openssl/evp.h>
2970 int main(void){
2971 EVP_sha3_512();
2972 EVP_sha3_384();
2973 EVP_sha3_256();
2974 EVP_sha3_224();
2975 return 0;
2979 if feat_yes MD5 && feat_no NOEXTMD5; then
2980 run_check tls_md5 'TLS: MD5 digest' '#define mx_XTLS_HAVE_MD5' << \!
2981 #include <stdlib.h>
2982 #include <string.h>
2983 #include <openssl/md5.h>
2984 int main(void){
2985 char const dat[] = "abrakadabrafidibus";
2986 char dig[16], hex[16 * 2];
2987 MD5_CTX ctx;
2988 size_t i, j;
2990 memset(dig, 0, sizeof(dig));
2991 memset(hex, 0, sizeof(hex));
2992 MD5_Init(&ctx);
2993 MD5_Update(&ctx, dat, sizeof(dat) - 1);
2994 MD5_Final(dig, &ctx);
2996 #define su_cs_is_xdigit(n) ((n) > 9 ? (n) - 10 + 'a' : (n) + '0')
2997 for(i = 0; i < sizeof(hex) / 2; i++){
2998 j = i << 1;
2999 hex[j] = su_cs_is_xdigit((dig[i] & 0xf0) >> 4);
3000 hex[++j] = su_cs_is_xdigit(dig[i] & 0x0f);
3002 return !!memcmp("6d7d0a3d949da2e96f2aa010f65d8326", hex, sizeof(hex));
3006 else
3007 feat_bail_required TLS_ALL_ALGORITHMS # feat_is_disabled?
3008 fi # }}}
3009 else
3010 feat_is_disabled TLS
3011 feat_is_disabled TLS_ALL_ALGORITHMS
3012 fi # }}} feat_yes TLS
3013 printf '#ifdef mx_SOURCE\n' >> ${h}
3014 printf '#define VAL_TLS_FEATURES ",'"${VAL_TLS_FEATURES}"',"\n' >> ${h}
3015 printf '#endif /* mx_SOURCE */\n' >> ${h}
3017 if [ "${have_xtls}" = yes ]; then
3018 OPT_SMIME=1
3019 else
3020 OPT_SMIME=0
3023 # VAL_RANDOM {{{
3024 if val_allof VAL_RANDOM \
3025 "arc4,tls,libgetrandom,sysgetrandom,getentropy,urandom,builtin,error"; \
3026 then
3028 else
3029 msg 'ERROR: VAL_RANDOM with invalid entries: %s' "${VAL_RANDOM}"
3030 config_exit 1
3033 # Random implementations which completely replace our builtin machine
3035 val_random_arc4() {
3036 link_check arc4random 'VAL_RANDOM: arc4random(3)' \
3037 '#define mx_HAVE_RANDOM mx_RANDOM_IMPL_ARC4' << \!
3038 #include <stdlib.h>
3039 int main(void){
3040 arc4random();
3041 return 0;
3046 val_random_tls() {
3047 if feat_yes TLS; then
3048 msg ' . VAL_RANDOM: tls ... yes'
3049 echo '#define mx_HAVE_RANDOM mx_RANDOM_IMPL_TLS' >> ${h}
3050 # Avoid reseeding, all we need is a streamy random producer
3051 link_check xtls_rand_drbg_set_reseed_defaults \
3052 'RAND_DRBG_set_reseed_defaults(3ssl)' \
3053 '#define mx_XTLS_HAVE_SET_RESEED_DEFAULTS' << \!
3054 #include <openssl/rand_drbg.h>
3055 int main(void){
3056 return (RAND_DRBG_set_reseed_defaults(0, 0, 0, 0) != 0);
3059 return 0
3060 else
3061 msg ' . VAL_RANDOM: tls ... no'
3062 return 1
3066 # The remaining random implementation are only used to seed our builtin
3067 # machine; we are prepared to handle failures of those, meaning that we have
3068 # a homebrew seeder; that tries to yield the time slice once, via
3069 # sched_yield(2) if available, nanosleep({0,0},) otherwise
3070 val__random_yield_ok=
3071 val__random_check_yield() {
3072 [ -n "${val__random_yield_ok}" ] && return
3073 val__random_yield_ok=1
3074 link_check sched_yield 'sched_yield(2)' '#define mx_HAVE_SCHED_YIELD' << \!
3075 #include <sched.h>
3076 int main(void){
3077 sched_yield();
3078 return 0;
3083 val_random_libgetrandom() {
3084 val__random_check_yield
3085 link_check getrandom 'VAL_RANDOM: getrandom(3) (in sys/random.h)' \
3086 '#define mx_HAVE_RANDOM mx_RANDOM_IMPL_GETRANDOM
3087 #define mx_RANDOM_GETRANDOM_FUN(B,S) getrandom(B, S, 0)
3088 #define mx_RANDOM_GETRANDOM_H <sys/random.h>' <<\!
3089 #include <sys/random.h>
3090 int main(void){
3091 char buf[256];
3092 getrandom(buf, sizeof buf, 0);
3093 return 0;
3098 val_random_sysgetrandom() {
3099 val__random_check_yield
3100 link_check getrandom 'VAL_RANDOM: getrandom(2) (via syscall(2))' \
3101 '#define mx_HAVE_RANDOM mx_RANDOM_IMPL_GETRANDOM
3102 #define mx_RANDOM_GETRANDOM_FUN(B,S) syscall(SYS_getrandom, B, S, 0)
3103 #define mx_RANDOM_GETRANDOM_H <sys/syscall.h>' <<\!
3104 #include <sys/syscall.h>
3105 int main(void){
3106 char buf[256];
3107 syscall(SYS_getrandom, buf, sizeof buf, 0);
3108 return 0;
3113 val_random_getentropy() {
3114 val__random_check_yield
3115 link_check getentropy 'VAL_RANDOM: getentropy(3)' \
3116 '#define mx_HAVE_RANDOM mx_RANDOM_IMPL_GETENTROPY' <<\!
3117 # include <errno.h>
3118 #include <limits.h>
3119 #include <unistd.h>
3120 # ifndef GETENTROPY_MAX
3121 # define GETENTROPY_MAX 256
3122 # endif
3123 int main(void){
3124 typedef char cta[GETENTROPY_MAX >= 256 ? 1 : -1];
3125 char buf[GETENTROPY_MAX];
3127 if(!getentropy(buf, sizeof buf) || errno != ENOSYS)
3128 return 0;
3129 return 1;
3134 val_random_urandom() {
3135 val__random_check_yield
3136 msg_nonl ' . VAL_RANDOM: /dev/urandom ... '
3137 if feat_yes CROSS_BUILD; then
3138 msg 'yes (unchecked)'
3139 echo '#define mx_HAVE_RANDOM mx_RANDOM_IMPL_URANDOM' >> ${h}
3140 elif [ -f /dev/urandom ]; then
3141 msg yes
3142 echo '#define mx_HAVE_RANDOM mx_RANDOM_IMPL_URANDOM' >> ${h}
3143 else
3144 msg no
3145 return 1
3147 return 0
3150 val_random_builtin() {
3151 val__random_check_yield
3152 msg_nonl ' . VAL_RANDOM: builtin ... '
3153 if [ -n "${have_no_subsecond_time}" ]; then
3154 msg 'no\nERROR: %s %s' 'without a specialized PRG ' \
3155 'one of clock_gettime(2) and gettimeofday(2) is required.'
3156 config_exit 1
3157 else
3158 msg yes
3159 echo '#define mx_HAVE_RANDOM mx_RANDOM_IMPL_BUILTIN' >> ${h}
3163 val_random_error() {
3164 msg 'ERROR: VAL_RANDOM search reached "error" entry'
3165 config_exit 42
3168 oifs=${IFS}
3169 IFS=", "
3170 VAL_RANDOM="${VAL_RANDOM},error"
3171 set -- ${VAL_RANDOM}
3172 IFS=${oifs}
3173 for randfun
3175 eval val_random_$randfun && break
3176 done
3177 # }}} VAL_RANDOM
3179 if feat_yes GSSAPI; then # {{{
3180 ${cat} > ${tmp2}.c << \!
3181 #include <gssapi/gssapi.h>
3182 int main(void){
3183 gss_import_name(0, 0, GSS_C_NT_HOSTBASED_SERVICE, 0);
3184 gss_init_sec_context(0,0,0,0,0,0,0,0,0,0,0,0,0);
3185 return 0;
3188 ${sed} -e '1s/gssapi\///' < ${tmp2}.c > ${tmp3}.c
3190 if acmd_set i krb5-config; then
3191 GSS_LIBS="`CFLAGS= ${i} --libs gssapi`"
3192 GSS_INCS="`CFLAGS= ${i} --cflags`"
3193 i='GSS-API via krb5-config(1)'
3194 else
3195 GSS_LIBS='-lgssapi'
3196 GSS_INCS=
3197 i='GSS-API in gssapi/gssapi.h, libgssapi'
3199 if < ${tmp2}.c link_check gss \
3200 "${i}" '#define mx_HAVE_GSSAPI' "${GSS_LIBS}" "${GSS_INCS}" ||\
3201 < ${tmp3}.c link_check gss \
3202 'GSS-API in gssapi.h, libgssapi' \
3203 '#define mx_HAVE_GSSAPI
3204 #define GSSAPI_REG_INCLUDE' \
3205 '-lgssapi' ||\
3206 < ${tmp2}.c link_check gss 'GSS-API in libgssapi_krb5' \
3207 '#define mx_HAVE_GSSAPI' \
3208 '-lgssapi_krb5' ||\
3209 < ${tmp3}.c link_check gss \
3210 'GSS-API in libgssapi, OpenBSD-style (pre 5.3)' \
3211 '#define mx_HAVE_GSSAPI
3212 #define GSS_REG_INCLUDE' \
3213 '-lgssapi -lkrb5 -lcrypto' \
3214 '-I/usr/include/kerberosV' ||\
3215 < ${tmp2}.c link_check gss 'GSS-API in libgss' \
3216 '#define mx_HAVE_GSSAPI' \
3217 '-lgss' ||\
3218 link_check gss 'GSS-API in libgssapi_krb5, old-style' \
3219 '#define mx_HAVE_GSSAPI
3220 #define GSSAPI_OLD_STYLE' \
3221 '-lgssapi_krb5' << \!
3222 #include <gssapi/gssapi.h>
3223 #include <gssapi/gssapi_generic.h>
3224 int main(void){
3225 gss_import_name(0, 0, gss_nt_service_name, 0);
3226 gss_init_sec_context(0,0,0,0,0,0,0,0,0,0,0,0,0);
3227 return 0;
3230 then
3232 else
3233 feat_bail_required GSSAPI
3235 else
3236 feat_is_disabled GSSAPI
3237 fi # feat_yes GSSAPI }}}
3239 if feat_yes IDNA; then # {{{
3240 if val_allof VAL_IDNA "idnkit,idn2,idn"; then
3242 else
3243 msg 'ERROR: VAL_IDNA with invalid entries: %s' "${VAL_IDNA}"
3244 config_exit 1
3247 val_idna_idn2() {
3248 link_check idna 'OPT_IDNA->VAL_IDNA: GNU Libidn2' \
3249 '#define mx_HAVE_IDNA n_IDNA_IMPL_LIBIDN2' '-lidn2' << \!
3250 #include <idn2.h>
3251 int main(void){
3252 char *idna_utf8, *idna_lc;
3254 if(idn2_to_ascii_8z("does.this.work", &idna_utf8,
3255 IDN2_NONTRANSITIONAL | IDN2_TRANSITIONAL) != IDN2_OK)
3256 return 1;
3257 if(idn2_to_unicode_8zlz(idna_utf8, &idna_lc, 0) != IDN2_OK)
3258 return 1;
3259 idn2_free(idna_lc);
3260 idn2_free(idna_utf8);
3261 return 0;
3266 val_idna_idn() {
3267 link_check idna 'OPT_IDNA->VAL_IDNA: GNU Libidn' \
3268 '#define mx_HAVE_IDNA n_IDNA_IMPL_LIBIDN' '-lidn' << \!
3269 #include <idna.h>
3270 #include <idn-free.h>
3271 #include <stringprep.h> /* XXX we actually use our own iconv instead */
3272 int main(void){
3273 char *utf8, *idna_ascii, *idna_utf8;
3275 utf8 = stringprep_locale_to_utf8("does.this.work");
3276 if (idna_to_ascii_8z(utf8, &idna_ascii, IDNA_USE_STD3_ASCII_RULES)
3277 != IDNA_SUCCESS)
3278 return 1;
3279 idn_free(idna_ascii);
3280 /* (Rather link check only here) */
3281 idna_utf8 = stringprep_convert(idna_ascii, "UTF-8", "de_DE");
3282 return 0;
3287 val_idna_idnkit() {
3288 link_check idna 'OPT_IDNA->VAL_IDNA: idnkit' \
3289 '#define mx_HAVE_IDNA n_IDNA_IMPL_IDNKIT' '-lidnkit' << \!
3290 #include <stdio.h>
3291 #include <idn/api.h>
3292 #include <idn/result.h>
3293 int main(void){
3294 idn_result_t r;
3295 char ace_name[256];
3296 char local_name[256];
3298 r = idn_encodename(IDN_ENCODE_APP, "does.this.work", ace_name,
3299 sizeof(ace_name));
3300 if (r != idn_success) {
3301 fprintf(stderr, "idn_encodename failed: %s\n", idn_result_tostring(r));
3302 return 1;
3304 r = idn_decodename(IDN_DECODE_APP, ace_name, local_name,sizeof(local_name));
3305 if (r != idn_success) {
3306 fprintf(stderr, "idn_decodename failed: %s\n", idn_result_tostring(r));
3307 return 1;
3309 return 0;
3314 val_idna_bye() {
3315 feat_bail_required IDNA
3318 oifs=${IFS}
3319 IFS=", "
3320 VAL_IDNA="${VAL_IDNA},bye"
3321 set -- ${VAL_IDNA}
3322 IFS=${oifs}
3323 for randfun
3325 eval val_idna_$randfun && break
3326 done
3327 else
3328 feat_is_disabled IDNA
3329 fi # }}} IDNA
3331 if feat_yes REGEX; then
3332 if link_check regex 'regular expressions' '#define mx_HAVE_REGEX' << \!
3333 #include <regex.h>
3334 #include <stdlib.h>
3335 int main(void){
3336 size_t xret;
3337 int status;
3338 regex_t re;
3340 status = regcomp(&re, ".*bsd", REG_EXTENDED | REG_ICASE | REG_NOSUB);
3341 xret = regerror(status, &re, NULL, 0);
3342 status = regexec(&re, "plan9", 0,NULL, 0);
3343 regfree(&re);
3344 return !(status == REG_NOMATCH);
3347 then
3349 else
3350 feat_bail_required REGEX
3352 else
3353 feat_is_disabled REGEX
3356 if feat_yes MLE; then
3357 if [ -n "${have_c90amend1}" ]; then
3358 have_mle=1
3359 echo '#define mx_HAVE_MLE' >> ${h}
3360 else
3361 feat_bail_required MLE
3363 else
3364 feat_is_disabled MLE
3367 if feat_yes HISTORY; then
3368 if [ -n "${have_mle}" ]; then
3369 echo '#define mx_HAVE_HISTORY' >> ${h}
3370 else
3371 feat_is_unsupported HISTORY
3373 else
3374 feat_is_disabled HISTORY
3377 if feat_yes KEY_BINDINGS; then
3378 if [ -n "${have_mle}" ]; then
3379 echo '#define mx_HAVE_KEY_BINDINGS' >> ${h}
3380 else
3381 feat_is_unsupported KEY_BINDINGS
3383 else
3384 feat_is_disabled KEY_BINDINGS
3387 if feat_yes TERMCAP; then # {{{
3388 ADDINC=
3389 __termcaplib() {
3390 link_check termcap "termcap(5) (via ${4}${ADDINC})" \
3391 "#define mx_HAVE_TERMCAP${3}" "${1}" "${ADDINC}" << _EOT
3392 #include <stdio.h>
3393 #include <stdlib.h>
3394 ${2}
3395 #include <term.h>
3396 #define UNCONST(P) ((void*)(unsigned long)(void const*)(P))
3397 static int my_putc(int c){return putchar(c);}
3398 int main(void){
3399 char buf[1024+512], cmdbuf[2048], *cpb, *r1;
3400 int r2 = OK, r3 = ERR;
3402 tgetent(buf, getenv("TERM"));
3403 cpb = cmdbuf;
3404 r1 = tgetstr(UNCONST("cm"), &cpb);
3405 tgoto(r1, 1, 1);
3406 r2 = tgetnum(UNCONST("Co"));
3407 r3 = tgetflag(UNCONST("ut"));
3408 tputs("cr", 1, &my_putc);
3409 return (r1 == NULL || r2 == -1 || r3 == 0);
3411 _EOT
3414 __terminfolib() {
3415 link_check terminfo "terminfo(5) (via ${2}${ADDINC})" \
3416 '#define mx_HAVE_TERMCAP
3417 #define mx_HAVE_TERMCAP_CURSES
3418 #define mx_HAVE_TERMINFO' "${1}" "${ADDINC}" << _EOT
3419 #include <stdio.h>
3420 #include <curses.h>
3421 #include <term.h>
3422 #define UNCONST(P) ((void*)(unsigned long)(void const*)(P))
3423 static int my_putc(int c){return putchar(c);}
3424 int main(void){
3425 int er, r0, r1, r2;
3426 char *r3, *tp;
3428 er = OK;
3429 r0 = setupterm(NULL, 1, &er);
3430 r1 = tigetflag(UNCONST("bce"));
3431 r2 = tigetnum(UNCONST("colors"));
3432 r3 = tigetstr(UNCONST("cr"));
3433 tp = tparm(r3, NULL, NULL, 0,0,0,0,0,0,0);
3434 tputs(tp, 1, &my_putc);
3435 return (r0 == ERR || r1 == -1 || r2 == -2 || r2 == -1 ||
3436 r3 == (char*)-1 || r3 == NULL);
3438 _EOT
3441 if feat_yes TERMCAP_VIA_TERMINFO; then
3442 ADDINC=
3443 do_me() {
3444 xbail=
3445 __terminfolib -ltinfo -ltinfo ||
3446 __terminfolib -lcurses -lcurses ||
3447 __terminfolib -lcursesw -lcursesw ||
3448 xbail=y
3450 do_me
3451 if [ -n "${xbail}" ] && [ -d /usr/local/include/ncurses ]; then
3452 ADDINC=' -I/usr/local/include/ncurses'
3453 do_me
3455 if [ -n "${xbail}" ] && [ -d /usr/include/ncurses ]; then
3456 ADDINC=' -I/usr/include/ncurses'
3457 do_me
3459 [ -n "${xbail}" ] && feat_bail_required TERMCAP_VIA_TERMINFO
3462 if [ -z "${have_terminfo}" ]; then
3463 ADDINC=
3464 do_me() {
3465 xbail=
3466 __termcaplib -ltermcap '' '' '-ltermcap' ||
3467 __termcaplib -ltermcap '#include <curses.h>' '
3468 #define mx_HAVE_TERMCAP_CURSES' \
3469 'curses.h / -ltermcap' ||
3470 __termcaplib -lcurses '#include <curses.h>' '
3471 #define mx_HAVE_TERMCAP_CURSES' \
3472 'curses.h / -lcurses' ||
3473 __termcaplib -lcursesw '#include <curses.h>' '
3474 #define mx_HAVE_TERMCAP_CURSES' \
3475 'curses.h / -lcursesw' ||
3476 xbail=y
3478 do_me
3479 if [ -n "${xbail}" ] && [ -d /usr/local/include/ncurses ]; then
3480 ADDINC=' -I/usr/local/include/ncurses'
3481 do_me
3483 if [ -n "${xbail}" ] && [ -d /usr/include/ncurses ]; then
3484 ADDINC=' -I/usr/include/ncurses'
3485 do_me
3487 [ -n "${xbail}" ] && feat_bail_required TERMCAP
3489 if [ -n "${have_termcap}" ]; then
3490 run_check tgetent_null \
3491 "tgetent(3) of termcap(5) takes NULL buffer" \
3492 "#define mx_HAVE_TGETENT_NULL_BUF" << _EOT
3493 #include <stdio.h> /* For C89 NULL */
3494 #include <stdlib.h>
3495 #ifdef mx_HAVE_TERMCAP_CURSES
3496 # include <curses.h>
3497 #endif
3498 #include <term.h>
3499 int main(void){
3500 tgetent(NULL, getenv("TERM"));
3501 return 0;
3503 _EOT
3506 unset ADDINC
3507 else # }}}
3508 feat_is_disabled TERMCAP
3509 feat_is_disabled TERMCAP_VIA_TERMINFO
3513 ## Final feat_def's XXX should be loop over OPTIONs
3516 feat_def ALWAYS_UNICODE_LOCALE
3517 feat_def AMALGAMATION 0
3518 if feat_def CMD_CSOP; then
3519 feat_def CMD_VEXPR # v15compat: VEXPR needs CSOP for byte string ops YET
3520 else
3521 feat_bail_required CMD_VEXPR
3523 feat_def COLOUR
3524 feat_def CROSS_BUILD
3525 feat_def DOTLOCK
3526 feat_def FILTER_HTML_TAGSOUP
3527 if feat_yes FILTER_QUOTE_FOLD; then
3528 if [ -n "${have_c90amend1}" ] && [ -n "${have_wcwidth}" ]; then
3529 echo '#define mx_HAVE_FILTER_QUOTE_FOLD' >> ${h}
3530 else
3531 feat_bail_required FILTER_QUOTE_FOLD
3533 else
3534 feat_is_disabled FILTER_QUOTE_FOLD
3536 feat_def DOCSTRINGS
3537 feat_def ERRORS
3538 feat_def IMAP
3539 feat_def IMAP_SEARCH
3540 feat_def MAILCAP
3541 feat_def MAILDIR
3542 feat_def MD5 # XXX only sockets
3543 feat_def MTA_ALIASES
3544 feat_def NETRC
3545 feat_def POP3
3546 feat_def SMIME
3547 feat_def SMTP
3548 feat_def SPAM_FILTER
3549 if feat_def SPAM_SPAMC; then
3550 if acmd_set i spamc; then
3551 echo "#define SPAM_SPAMC_PATH \"${i}\"" >> ${h}
3554 if feat_yes SPAM_SPAMC || feat_yes SPAM_FILTER; then
3555 echo '#define mx_HAVE_SPAM' >> ${h}
3556 else
3557 echo '/* mx_HAVE_SPAM */' >> ${h}
3559 feat_def UISTRINGS
3560 feat_def USE_PKGSYS
3562 feat_def ASAN_ADDRESS 0
3563 feat_def ASAN_MEMORY 0
3564 feat_def USAN 0
3565 feat_def DEBUG 0
3566 feat_def DEVEL 0
3567 feat_def NOMEMDBG 0
3570 ## Summarizing
3573 INCS=`squeeze_ws "${INCS}"`
3574 LIBS=`squeeze_ws "${LIBS}"`
3576 MX_CFLAGS=${CFLAGS}
3577 MX_INCS=${INCS}
3578 MX_LDFLAGS=${LDFLAGS}
3579 MX_LIBS=${LIBS}
3580 SU_CFLAGS=${BASE_CFLAGS}
3581 SU_CXXFLAGS=
3582 SU_INCS=${BASE_INCS}
3583 SU_LDFLAGS=${BASE_LDFLAGS}
3584 SU_LIBS=${BASE_LIBS}
3585 PS_DOTLOCK_CFLAGS=${BASE_CFLAGS}
3586 PS_DOTLOCK_INCS=${BASE_INCS}
3587 PS_DOTLOCK_LDFLAGS=${BASE_LDFLAGS}
3588 PS_DOTLOCK_LIBS=${BASE_LIBS}
3590 for i in \
3591 CC \
3592 MX_CFLAGS MX_INCS MX_LDFLAGS MX_LIBS \
3593 PS_DOTLOCK_CFLAGS PS_DOTLOCK_INCS PS_DOTLOCK_LDFLAGS PS_DOTLOCK_LIBS \
3594 SU_CFLAGS SU_CXXFLAGS SU_INCS SU_LDFLAGS SU_LIBS \
3595 ; do
3596 eval j=\$${i}
3597 printf -- "${i} = ${j}\n" >> ${mk}
3598 done
3600 echo >> ${mk}
3602 # mk-config.h (which becomes mx/gen-config.h)
3603 ${mv} ${h} ${tmp}
3604 printf '#ifndef mx_GEN_CONFIG_H\n# define mx_GEN_CONFIG_H 1\n' > ${h}
3605 ${cat} ${tmp} >> ${h}
3606 printf '\n#ifdef mx_SOURCE\n' >> ${h}
3608 # Also need these for correct "second stage configuration changed" detection */
3610 if (${CC} --version) >/dev/null 2>&1; then
3611 i=`${CC} --version 2>&1 | ${awk} '
3612 BEGIN{l=""}
3613 {if(length($0)) {if(l) l = l "\\\\n"; l = l "@" $0}}
3614 END{gsub(/"/, "", l); print "\\\\n" l}
3616 elif (${CC} -v) >/dev/null 2>&1; then
3617 i=`${CC} -v 2>&1 | ${awk} '
3618 BEGIN{l=""}
3619 {if(length($0)) {if(l) l = l "\\\\n"; l = l "@" $0}}
3620 END{gsub(/"/, "", l); print "\\\\n" l}
3624 CC=`squeeze_ws "${CC}"`
3625 CFLAGS=`squeeze_ws "${CFLAGS}"`
3626 LDLAGS=`squeeze_ws "${LDFLAGS}"`
3627 LIBS=`squeeze_ws "${LIBS}"`
3628 # $MAKEFLAGS often contain job-related things which hinders reproduceability.
3629 # For at least GNU make(1) we can separate those and our regular configuration
3630 # options by searching for the -- terminator
3631 COMMLINE=`printf '%s\n' "${COMMLINE}" | ${sed} -e 's/.*--\(.*\)/\1/'`
3632 COMMLINE=`squeeze_ws "${COMMLINE}"`
3634 i=`printf '%s %s %s\n' "${CC}" "${CFLAGS}" "${i}"`
3635 printf '#define VAL_BUILD_CC "%s"\n' "$i" >> ${h}
3636 i=`string_to_char_array "${i}"`
3637 printf '#define VAL_BUILD_CC_ARRAY %s\n' "$i" >> ${h}
3638 i=`printf '%s %s %s\n' "${CC}" "${LDFLAGS}" "${LIBS}"`
3639 printf '#define VAL_BUILD_LD "%s"\n' "$i" >> ${h}
3640 i=`string_to_char_array "${i}"`
3641 printf '#define VAL_BUILD_LD_ARRAY %s\n' "$i" >> ${h}
3642 i=${COMMLINE}
3643 printf '#define VAL_BUILD_REST "%s"\n' "$i" >> ${h}
3644 i=`string_to_char_array "${i}"`
3645 printf '#define VAL_BUILD_REST_ARRAY %s\n' "$i" >> ${h}
3647 # Throw away all temporaries
3648 ${rm} -rf ${tmp0}.* ${tmp0}*
3650 # Create the string that is used by *features* and the version command.
3651 # Take this nice opportunity and generate a visual listing of included and
3652 # non-included features for the person who runs the configuration
3653 echo 'The following features are included (+) or not (-):' > ${tmp}
3654 set -- ${OPTIONS_DETECT} ${OPTIONS} ${OPTIONS_XTRA}
3655 printf '/* The "feature string" */\n' >> ${h}
3656 # Prefix sth. to avoid that + is expanded by *folder* (echo $features)
3657 printf '#define VAL_FEATURES_CNT '${#}'\n#define VAL_FEATURES ",' >> ${h}
3658 sep=
3659 for opt
3661 sdoc=`option_doc_of ${opt}`
3662 [ -z "${sdoc}" ] && continue
3663 sopt="`echo ${opt} | ${tr} '[A-Z]_' '[a-z]-'`"
3664 feat_yes ${opt} && sign=+ || sign=-
3665 printf -- "${sep}${sign}${sopt}" >> ${h}
3666 sep=','
3667 printf ' %s %s: %s\n' ${sign} ${sopt} "${sdoc}" >> ${tmp}
3668 done
3669 # TODO instead of using sh+tr+awk+printf, use awk, drop option_doc_of, inc here
3670 #exec 5>&1 >>${h}
3671 #${awk} -v opts="${OPTIONS_DETECT} ${OPTIONS} ${OPTIONS_XTRA}" \
3672 # -v xopts="${XOPTIONS_DETECT} ${XOPTIONS} ${XOPTIONS_XTRA}" \
3673 printf ',"\n' >> ${h}
3675 # Create the real mk-config.mk
3676 # Note we cannot use explicit ./ filename prefix for source and object
3677 # pathnames because of a bug in bmake(1)
3678 msg 'Creating object make rules'
3680 if feat_yes DOTLOCK; then
3681 printf "OPTIONAL_PS_DOTLOCK = \$(VAL_PS_DOTLOCK)\n" >> ${mk}
3682 (cd "${SRCDIR}"; ${SHELL} ../mk/make-rules.sh ps-dotlock/*.c) >> ${mk}
3683 else
3684 printf "OPTIONAL_PS_DOTLOCK =\n" >> ${mk}
3687 # Not those SU sources with su_USECASE_MX_DISABLED
3688 su_sources=`(
3689 cd "${SRCDIR}"
3690 for f in su/*.c; do
3691 ${grep} su_USECASE_MX_DISABLED "${f}" >/dev/null >&1 && continue
3692 echo ${f}
3693 done
3696 mx_obj= su_obj=
3697 if feat_no AMALGAMATION; then
3698 (cd "${SRCDIR}"; ${SHELL} ../mk/make-rules.sh ${su_sources}) >> ${mk}
3699 (cd "${SRCDIR}"; ${SHELL} ../mk/make-rules.sh mx/*.c) >> ${mk}
3700 mx_obj='$(MX_C_OBJ)' su_obj='$(SU_C_OBJ)'
3701 else
3702 (cd "${SRCDIR}"; COUNT_MODE=0 ${SHELL} ../mk/make-rules.sh mx/*.c) >> ${mk}
3703 mx_obj=mx-main.o
3704 printf 'mx-main.o: gen-bltin-rc.h gen-mime-types.h' >> ${mk}
3706 printf '\n#endif /* mx_SOURCE */\n' >> ${h}
3707 printf '/* mx_HAVE_AMALGAMATION: include sources */\n' >> ${h}
3708 printf '#elif mx_GEN_CONFIG_H + 0 == 1\n' >> ${h}
3709 printf '# undef mx_GEN_CONFIG_H\n' >> ${h}
3710 printf '# define mx_GEN_CONFIG_H 2\n#ifdef mx_SOURCE\n' >> ${h}
3712 for i in `printf '%s\n' ${su_sources} | ${sort}`; do
3713 printf '# include "%s%s"\n' "${SRCDIR}" "${i}" >> ${h}
3714 done
3715 echo >> ${mk}
3717 for i in `printf '%s\n' "${SRCDIR}"mx/*.c | ${sort}`; do
3718 i=`basename "${i}"`
3719 if [ "${i}" = main.c ]; then
3720 continue
3722 printf '# include "%s%s"\n' "${SRCDIR}mx/" "${i}" >> ${h}
3723 done
3724 echo >> ${mk}
3726 printf 'OBJ = %s\n' "${mx_obj} ${su_obj}" >> "${mk}"
3728 printf '#endif /* mx_SOURCE */\n#endif /* mx_GEN_CONFIG_H */\n' >> ${h}
3730 echo >> ${mk}
3731 ${cat} "${TOPDIR}"mk/make-config.in >> ${mk}
3734 ## Finished!
3737 # We have completed the new configuration header. Check whether *really*
3738 # Do the "second stage configuration changed" detection, exit if nothing to do
3739 if [ -f ${oldh} ]; then
3740 if ${cmp} ${h} ${oldh} >/dev/null 2>&1; then
3741 ${mv} -f ${oldh} ${h}
3742 msg 'Effective configuration is up-to-date'
3743 exit 0
3745 config_updated=1
3746 ${rm} -f ${oldh}
3747 msg 'Effective configuration has been updated..'
3750 if [ -n "${config_updated}" ]; then
3751 msg 'Wiping away old objects and such..'
3752 ( cd "${OBJDIR}"; oldmk=`${basename} ${oldmk}`; ${MAKE} -f ${oldmk} clean )
3755 # Ensure user edits in mx-config.h are incorporated, and that our generated
3756 # mk-config.h becomes the new public mx/gen-config.h.
3757 ${cp} -f "${CWDDIR}"mx-config.h "${CWDDIR}"include/mx/config.h
3758 ${cp} -f ${h} "${CWDDIR}"include/mx/gen-config.h
3760 msg ''
3761 while read l; do msg "${l}"; done < ${tmp}
3763 msg 'Setup:'
3764 msg ' . System-wide resource file: %s/%s' \
3765 "${VAL_SYSCONFDIR}" "${VAL_SYSCONFRC}"
3766 msg ' . bindir: %s' "${VAL_BINDIR}"
3767 if feat_yes DOTLOCK; then
3768 msg ' . libexecdir: %s' "${VAL_LIBEXECDIR}"
3770 msg ' . mandir: %s' "${VAL_MANDIR}"
3771 msg ' . M(ail)T(ransfer)A(gent): %s (argv0: %s)' \
3772 "${VAL_MTA}" "${VAL_MTA_ARGV0}"
3773 msg ' . $MAIL spool directory: %s' "${VAL_MAIL}"
3774 if feat_yes MAILCAP; then
3775 msg ' . Built-in $MAILCAPS path search: %s' "${VAL_MAILCAPS}"
3778 msg ''
3779 if [ -n "${have_fnmatch}" ] && [ -n "${have_fchdir}" ]; then
3780 exit 0
3782 msg 'Remarks:'
3783 if [ -z "${have_fnmatch}" ]; then
3784 msg ' . The function fnmatch(3) could not be found.'
3785 msg ' Filename patterns like wildcard are not supported on your system'
3787 if [ -z "${have_fchdir}" ]; then
3788 msg ' . The function fchdir(2) could not be found.'
3789 msg ' We will use chdir(2) instead.'
3790 msg ' This is a problem only if the current working directory is changed'
3791 msg ' while this program is inside of it'
3793 msg ''
3795 # s-it-mode