]> git.draconx.ca Git - dxcommon.git/commitdiff
Add a configure test for C99-ish "for" declarations.
authorNick Bowler <nbowler@draconx.ca>
Thu, 30 Nov 2023 01:33:29 +0000 (20:33 -0500)
committerNick Bowler <nbowler@draconx.ca>
Thu, 30 Nov 2023 01:53:07 +0000 (20:53 -0500)
Several C89-era compilers support for loop declarations (although
I'm not sure if they implement C99 block scoping rules exactly and
this new macro doesn't check for that).

It is generally easy to simply not use this feature, so conditional
compilation based on its presence is of limited utility.  But it can
sometimes be handy to know when (optionally) including third-party
code that depends on this syntax.

The test is short-circuited based on Autoconf's C version probes, which
requires an annoying amount of complexity because Autoconf 2.70 has
totally broken C99 detection and Autoconf 2.71 includes incompatible
changes to previously-documented behaviour.

m4/fordecl.m4 [new file with mode: 0644]
tests/macros.at

diff --git a/m4/fordecl.m4 b/m4/fordecl.m4
new file mode 100644 (file)
index 0000000..c36527d
--- /dev/null
@@ -0,0 +1,38 @@
+# Copyright © 2023 Nick Bowler
+#
+# License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+# This is free software: you are free to do what the fuck you want to.
+# There is NO WARRANTY, to the extent permitted by law.
+
+# DX_C_FOR_DECLARATIONS
+#
+# Probe whether for-loop declarations are accepted by the C compiler,
+# as some pre-C99 implementations do have them.  If supported, the cache
+# variable dx_cv_have_for_decls is set to "yes" and the HAVE_FOR_DECLS
+# macro is defined to 1.
+#
+# We skip the test (and define the macro unconditionally) if Autoconf
+# has previously determined that the C compiler supports C99 or a newer
+# standard, since the C99 test program checks this.  However, autoconf-2.70
+# has a broken check which indicates C99 compatibility for C89 compilers,
+# so on this version we still do the check if C99 support is indicated.
+#
+# Annoyingly, autoconf-2.71 removed the assignment of ac_cv_prog_cc_c99,
+# even though this was actual documented behaviour...
+AC_DEFUN([DX_C_FOR_DECLARATIONS],
+[AS_CASE([${ac_cv_prog_cc_c99-no}/${ac_prog_cc_stdc-no}],
+  [m4_do([no/no|*/c89],
+    [_DX_IF_AC270_C99_BUG([|*/c99])])],
+  [AC_CACHE_CHECK([if $CC supports for-loop declarations],
+    [dx_cv_have_for_decls],
+    [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [for (int i; i = 1;) return i;])],
+    [dx_cv_have_for_decls=yes], [dx_cv_have_for_decls=no])])],
+  [dx_cv_have_for_decls=yes])
+AS_CASE([$dx_cv_have_for_decls],
+  [yes], [AC_DEFINE([HAVE_FOR_DECLS], [1],
+    [Define to 1 if the C compiler supports for-loop declarations.])])])
+
+m4_define([_DX_IF_AC270_C99_BUG], [m4_ifdef([_AC_PROG_CC_C99],
+  [m4_bmatch(m4_defn([_AC_PROG_CC_C99]),
+    [_AC_C_STD_TRY.\[c99\], *\[ac_c_conftest_c89_program\]],
+    [$1])])])
index a085ad6ab50aeb2ff39ca7c300b5f17f60d0b9f9..9aadd038faca7ea15e06601776d22dcca3cf6dac 100644 (file)
@@ -1,4 +1,4 @@
-dnl Copyright © 2014-2015, 2018-2019, 2021-2022 Nick Bowler
+dnl Copyright © 2014-2015, 2018-2019, 2021-2023 Nick Bowler
 dnl
 dnl License WTFPL2: Do What The Fuck You Want To Public License, version 2.
 dnl This is free software: you are free to do what the fuck you want to.
@@ -597,3 +597,80 @@ done
 exit 1])
 
 AT_CLEANUP
+
+# TEST_FIND_AUTOCONF_VER([to-check], [test-action])
+#
+# For each whitespace-separated version token in to-check, check if we can
+# run program autoconf-VER.  The special token 'default' also checks the
+# unversioned autoconf (or, if set in the environment, $AUTOCONF).
+#
+# Then test-action is expanded such that the shell variable $ac refers
+# to the autoconf program, and $acver is the actual version reported by
+# $ac --version. The action should do nothing if the version is acceptable,
+# or "continue" if the version is unacceptable.
+#
+# If an acceptable version is found, the AUTOCONF environment variable is
+# set accordingly.  Otherwise, the test group is skipped.
+m4_define([TEST_FIND_AUTOCONF],
+[have_ac=false
+for ac in $1; do
+  AS_CASE([$ac], [default], [ac=${AUTOCONF-autoconf}], [ac=autoconf-$ac])
+  acver=`$ac --version | sed -n '1s/.* //p'`
+  set x $acver; test x"$[#]" = x"2" || continue
+  $2
+  have_ac=:; break
+done
+AT_CHECK([$have_ac || exit 77])
+AUTOCONF=$ac; export AUTOCONF
+AT_CHECK([$AUTOCONF --version], [0], [ignore])
+])
+
+m4_define([TEST_DX_C_FOR_DECLARATIONS],
+[cat "$srcdir/m4/fordecl.m4" >aclocal.m4
+AT_DATA([config.h.in],
+[[#undef HAVE_FOR_DECLS
+]])
+TEST_CONFIGURE_AC([m4_ifnblank([$1], [$1])
+[AC_CONFIG_HEADERS([config.h])
+DX_C_FOR_DECLARATIONS
+]])
+AT_CHECK([$AUTOCONF], [0], [], [stderr])
+AT_DATA([test.c],
+[[#if __STDC_VERSION__ < 199901
+#error nope
+char nope[-1];
+#endif
+char yup;
+]])
+AT_CHECK([$CC -c -std=gnu99 test.c || exit 77], [0], [ignore], [ignore])
+TEST_CONFIGURE([CC="$CC" CFLAGS="-std=gnu89"])
+AT_CHECK([grep HAVE_FOR_DECLS config.h], [0],
+[[/* #undef HAVE_FOR_DECLS */
+]])
+TEST_CONFIGURE([CC="$CC -std=gnu99"])
+AT_CHECK([grep HAVE_FOR_DECLS config.h], [0],
+[[#define HAVE_FOR_DECLS 1
+]])
+])
+
+AT_SETUP([DX_C_FOR_DECLARATIONS (<autoconf-2.70)])
+AT_KEYWORDS([DX_C_FOR_DECLARATIONS macro])
+TEST_FIND_AUTOCONF([default 2.69 2.68],
+  [AS_VERSION_COMPARE(["$acver"], [2.70], [], [continue], [continue])])
+TEST_DX_C_FOR_DECLARATIONS([[AC_PROG_CC]])
+TEST_DX_C_FOR_DECLARATIONS([[AC_PROG_CC_C99]])
+AT_CLEANUP
+
+AT_SETUP([DX_C_FOR_DECLARATIONS (=autoconf-2.70)])
+AT_KEYWORDS([DX_C_FOR_DECLARATIONS macro])
+TEST_FIND_AUTOCONF([default 2.70],
+  [AS_VERSION_COMPARE(["$acver"], [2.70], [continue], [], [continue])])
+TEST_DX_C_FOR_DECLARATIONS
+AT_CLEANUP
+
+AT_SETUP([DX_C_FOR_DECLARATIONS (>autoconf-2.70)])
+AT_KEYWORDS([DX_C_FOR_DECLARATIONS macro])
+TEST_FIND_AUTOCONF([default 2.71 2.72 2.73 2.74],
+  [AS_VERSION_COMPARE(["$acver"], [2.70], [continue], [continue], [])])
+TEST_DX_C_FOR_DECLARATIONS
+AT_CLEANUP