]> git.draconx.ca Git - dxcommon.git/commitdiff
Add configure tests for C11-ish _Alignof and _Alignas.
authorNick Bowler <nbowler@draconx.ca>
Mon, 19 Feb 2024 04:25:15 +0000 (23:25 -0500)
committerNick Bowler <nbowler@draconx.ca>
Fri, 23 Feb 2024 01:31:58 +0000 (20:31 -0500)
These features are pretty feasible to implement usable macro-based
fallbacks on pre-C11 compilers.  Add some basic configure probes
to check these C11 features and AC_DEFINE reasonable fallbacks
where unsupported.

If Autoconf already detected C11 support, do nothing (as it tests
these features already).  Compilers which support these in C11 mode
usually also support them in other conformance modes, so it is still
useful to probe these specifically.

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

diff --git a/m4/align.m4 b/m4/align.m4
new file mode 100644 (file)
index 0000000..03e18a8
--- /dev/null
@@ -0,0 +1,68 @@
+# Copyright © 2024 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_ALIGNOF
+#
+# Probe whether the C compiler understands _Alignof(T).
+#
+# If not supported, _Alignof(T) is defined as a function-like macro which
+# uses offsetof to guess the alignment of T, which must be a type such that
+# T x; is a valid declaration of x as an object of type T.  It is therefore
+# necessary that the caller includes <stddef.h> before using _Alignof.
+#
+# We skip the test if Autoconf has previously determined that the C compiler
+# supports C11 or a newer standard, since the C11 test program checks this.
+#
+# Annoyingly, autoconf-2.71 removed the assignment of ac_cv_prog_cc_c11,
+# even though this was actual documented behaviour...
+AC_DEFUN([DX_C_ALIGNOF],
+[AS_CASE([${ac_cv_prog_cc_c11-no}/${ac_prog_cc_stdc-no}],
+  [no/no|*/c89|*/c99],
+    [AC_CACHE_CHECK([if $CC supports _Alignof], [dx_cv_have_alignof],
+      [AC_COMPUTE_INT([_dx_tmp], [_Alignof(char)], [@&t@], [_dx_tmp=0])
+AS_CASE([$_dx_tmp], [1], [dx_cv_have_alignof=yes], [dx_cv_have_alignof=no])])],
+  [dx_cv_have_alignof=yes])
+AS_CASE([$dx_cv_have_alignof], [no], [AC_DEFINE([_Alignof(T)],
+  [offsetof(struct { char a; T b; }, b)],
+  [Define _Alignof(T) to a suitable fallback if _Alignof is unsupported.])])])
+
+# DX_C_ALIGNAS
+#
+# Probe whether the C compiler understands _Alignas(X).
+#
+# If not supported, but the compiler supports the GNU __attribute__ or
+# Microsoft __declspec methods to set alignment, _Alignas(X) is defined
+# as a function-like macro which expands to such syntax.  These only
+# work if X is an integer constant (as opposed to a type name).
+#
+# If there is no known method of declaring a variable with increased
+# alignment, then _Alignas(X) is defined as a function-like macro which
+# expands to nothing, which will compile but has no runtime effect.
+#
+# We skip the test if Autoconf has previously determined that the C
+# compiler supports C11 or a newer standard, since the C11 test program
+# checks this.
+AC_DEFUN([DX_C_ALIGNAS],
+[AS_CASE([${ac_cv_prog_cc_c11-no}/${ac_prog_cc_stdc-no}],
+  [no/no|*/c89|*/c99],
+    [AC_CACHE_CHECK([if $CC supports _Alignas], [dx_cv_have_alignas],
+[dx_cv_have_alignas=no
+for _dx_alignas
+in '_Alignas(X)' '__attribute__((__aligned__(X)))' '__declspec(align(X))'
+do
+AC_COMPUTE_INT([_dx_tmp],
+  [sizeof (struct { char a; char ALIGNAS_TEST(4) b; }) >= 8],
+  [#define ALIGNAS_TEST(X) $_dx_alignas
+],[_dx_tmp=0])
+AS_CASE([$_dx_tmp/$_dx_alignas],
+  [1/_Alignas*], [dx_cv_have_alignas=yes; break],
+  [1/*], [dx_cv_have_alignas=$_dx_alignas; break])
+done])],
+  [dx_cv_have_alignas=yes])
+AS_CASE([$dx_cv_have_alignas],
+  [*'(X)'*], [AC_DEFINE_UNQUOTED([_Alignas(X)], [$dx_cv_have_alignas],
+    [Define _Alignas(X) to a suitable fallback if _Alignas is unsupported.])],
+  [no], [AC_DEFINE([_Alignas(X)], [/**/])])])
index 9aadd038faca7ea15e06601776d22dcca3cf6dac..6da14b3867dbd325273d1f1632fa0ab82f22f36b 100644 (file)
@@ -1,4 +1,4 @@
-dnl Copyright © 2014-2015, 2018-2019, 2021-2023 Nick Bowler
+dnl Copyright © 2014-2015, 2018-2019, 2021-2024 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.
@@ -650,8 +650,7 @@ AT_CHECK([grep HAVE_FOR_DECLS config.h], [0],
 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])
@@ -674,3 +673,114 @@ 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
+
+m4_define([TEST_DX_C_ALIGNOF],
+[cat "$srcdir/m4/align.m4" >aclocal.m4
+AT_DATA([config.h.in],
+[[#undef _Alignof
+#undef _Alignas
+]])
+TEST_CONFIGURE_AC([m4_ifnblank([$1], [$1])
+[AC_CONFIG_HEADERS([config.h])
+DX_C_ALIGNOF
+]])
+AT_CHECK([$AUTOCONF], [0], [], [stderr])
+AT_DATA([test.c],
+[[#if __STDC_VERSION__ < 201112
+#error nope
+char nope[-1];
+#endif
+char yup;
+]])
+AT_CHECK([$CC -c -std=gnu11 -pedantic-errors test.c || exit 77],
+  [0], [ignore], [ignore])
+TEST_CONFIGURE([CC="$CC" CFLAGS="-std=gnu89 -pedantic-errors"])
+AT_CHECK([grep _Align config.h], [0],
+[[#define _Alignof(T) offsetof(struct { char a; T b; }, b)
+/* #undef _Alignas */
+]])
+TEST_CONFIGURE([CC="$CC -std=gnu11"])
+AT_CHECK([grep _Align config.h], [0],
+[[/* #undef _Alignof */
+/* #undef _Alignas */
+]])])
+
+AT_SETUP([DX_C_ALIGNOF (<autoconf-2.70)])
+AT_KEYWORDS([DX_C_ALIGNOF 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]])
+AT_CLEANUP
+
+AT_SETUP([DX_C_ALIGNOF (=autoconf-2.70)])
+AT_KEYWORDS([DX_C_ALIGNOF macro])
+TEST_FIND_AUTOCONF([default 2.70],
+  [AS_VERSION_COMPARE(["$acver"], [2.70], [continue], [], [continue])])
+TEST_DX_C_ALIGNOF
+AT_CLEANUP
+
+AT_SETUP([DX_C_ALIGNOF (>autoconf-2.70)])
+AT_KEYWORDS([DX_C_ALIGNOF macro])
+TEST_FIND_AUTOCONF([default 2.71 2.72 2.73 2.74],
+  [AS_VERSION_COMPARE(["$acver"], [2.70], [continue], [continue], [])])
+TEST_DX_C_ALIGNOF([[AC_PROG_CC]])
+AT_CLEANUP
+
+m4_define([TEST_DX_C_ALIGNAS],
+[cat "$srcdir/m4/align.m4" >aclocal.m4
+AT_DATA([config.h.in],
+[[#undef _Alignas
+#undef _Alignof
+]])
+TEST_CONFIGURE_AC([m4_ifnblank([$1], [$1])
+[AC_CONFIG_HEADERS([config.h])
+AC_COMPUTE_INT([dummy], [0], [@&t@], [dummy=0]) # ensure main CC probes finish
+AC_ARG_ENABLE([break-cc], [], [CC=false]) # before we force everything to fail
+DX_C_ALIGNAS
+]])
+AT_CHECK([$AUTOCONF], [0], [], [stderr])
+AT_DATA([test.c],
+[[#if __STDC_VERSION__ < 201112
+#error nope
+char nope[-1];
+#endif
+char yup;
+]])
+AT_CHECK([$CC -c -std=gnu11 -pedantic-errors test.c || exit 77],
+  [0], [ignore], [ignore])
+TEST_CONFIGURE([CC="$CC" CFLAGS="-std=gnu89 -pedantic-errors"])
+AT_CHECK([grep _Align config.h], [0],
+[[#define _Alignas(X) __attribute__((__aligned__(X)))
+/* #undef _Alignof */
+]])
+TEST_CONFIGURE([CC="$CC -std=gnu11"])
+AT_CHECK([grep _Align config.h], [0],
+[[/* #undef _Alignas */
+/* #undef _Alignof */
+]])
+TEST_CONFIGURE([CC="$CC" CFLAGS="-std=gnu89 -pedantic-errors" --enable-break-cc])
+AT_CHECK([grep _Align config.h], [0],
+[[#define _Alignas(X) /**/
+/* #undef _Alignof */
+]])])
+
+AT_SETUP([DX_C_ALIGNAS (<autoconf-2.70)])
+AT_KEYWORDS([DX_C_ALIGNAS macro])
+TEST_FIND_AUTOCONF([default 2.69 2.68],
+  [AS_VERSION_COMPARE(["$acver"], [2.70], [], [continue], [continue])])
+TEST_DX_C_ALIGNAS([[AC_PROG_CC]])
+AT_CLEANUP
+
+AT_SETUP([DX_C_ALIGNAS (=autoconf-2.70)])
+AT_KEYWORDS([DX_C_ALIGNAS macro])
+TEST_FIND_AUTOCONF([default 2.70],
+  [AS_VERSION_COMPARE(["$acver"], [2.70], [continue], [], [continue])])
+TEST_DX_C_ALIGNAS
+AT_CLEANUP
+
+AT_SETUP([DX_C_ALIGNAS (>autoconf-2.70)])
+AT_KEYWORDS([DX_C_ALIGNAS macro])
+TEST_FIND_AUTOCONF([default 2.71 2.72 2.73 2.74],
+  [AS_VERSION_COMPARE(["$acver"], [2.70], [continue], [continue], [])])
+TEST_DX_C_ALIGNAS([[AC_PROG_CC]])
+AT_CLEANUP