dnl -*-autoconf-*- ### SYNOPSIS ### ### FINALLY([IF-SUCCEEDED], [IF-FAILED]) ### ### DESCRIPTION ### ### Probe at the C compiler to determine how, if at all, to implement the ### `FINALLY' macro, which arranges to run some code when control leaves a ### given scope. This isn't at all a standard C feature, so we need to use ### compiler-specific hacks, and this is the main machinery for deciding ### which hacks to deploy. ### ### On exit, the shell variable `finally_flavour' is set to an uppercase ### word naming the chosen implementation strategy: it will be `NIL' if the ### macro failed and no strategy could be found. The preprocessor define ### `FINALLY_CONFIG_FLAVOUR' is set to `FINALLY_CONFIG_FLAVOUR_...' ### followed by the same word: this is the main input to the selection ### machinery in `finally.h'. ### ### The substitution variables `FINALLY_CFLAGS' and `FINALLY_LIBS' are set ### to any additional compiler flags or libraries needed to support the ### `FINALLY' macro. They can be set per-target in the `Makefile', or ### stuffed into the global variables by the `configure' script. ### ### If the macro managed to find a workable strategy, then the shell ### fragment IF-SUCCEEDED is run; otherwise, (if `finally_flavour' is ### `NIL'), the shell fragment IF-FAILED is run. ### ### LICENSE ### ### Copyright (c) 2023 Mark Wooding ### ### This program is free software: you can redistribute it and/or modify it ### under the terms of the GNU General Public License as published by the ### Free Software Foundation, either version 2 of the License, or (at your ### option) any later version. ### ### This program is distributed in the hope that it will be useful, but ### WITHOUT ANY WARRANTY; without even the implied warranty of ### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ### General Public License for more details. ### ### You should have received a copy of the GNU General Public License along ### with this program. If not, see . ### ### In particular, no exception to the GPL is granted regarding generated ### `configure' scripts which are the output of Autoconf. AC_DEFUN([FINALLY_GCC_NESTED_FUNCTIONS_TEST_PROGRAM], [AC_LANG_PROGRAM([], [ __extension__ __inline__ void nested(void) { ; } nested(); ])]) AC_DEFUN([FINALLY_GCC_ATTRIBUTE_CLEANUP_TEST_PROGRAM], [AC_LANG_PROGRAM([ extern void cleanup_fn(const int *x); extern void bamboozle(int *x_inout); ], [ __attribute__((cleanup(cleanup_fn))) int x = 0; bamboozle(&x); ])]) dnl Decide whether we can define a plausible `FINALLY' macro. AC_DEFUN([FINALLY_CHECK], [finally_flavour=undecided finally_result="not supported" dnl We're going to want to test C code. AC_LANG_PUSH([C]) case $finally_flavour,$GCC in undecided,yes) dnl Our GCC-ish strategies have a common factor: they depend on dnl `__attribute__((cleanup(...)))' working. So let's check for that. AC_CACHE_CHECK([whether the alleged GNU C compiler supports \`__attribute__((cleanup(...)))'], [finally_cv_gcc_attribute_cleanup_p], [ AC_COMPILE_IFELSE([FINALLY_GCC_ATTRIBUTE_CLEANUP_TEST_PROGRAM], [finally_cv_gcc_attribute_cleanup_p=yes], [finally_cv_gcc_attribute_cleanup_p=no])]) case $finally_cv_gcc_attribute_cleanup_p in no) finally_flavour=NIL ;; esac ;; esac case $finally_flavour,$GCC in undecided,yes) dnl Autoconf has decided that the compiler smells a bit like GCC, and it dnl certainly seems to support a GCC extension. But many compilers dnl impersonate GCC, in more or less convincing ways. Our GCC-flavoured dnl `FINALLY' code depends on nested functions, which GCC has supported dnl pretty much forever, but other compilers don't even though they lie dnl about being compatible. AC_CACHE_CHECK([whether the alleged GNU C compiler supports nested functions], [finally_cv_gcc_nested_functions_p], [ AC_COMPILE_IFELSE([FINALLY_GCC_NESTED_FUNCTIONS_TEST_PROGRAM], [finally_cv_gcc_nested_functions_p=yes], [finally_cv_gcc_nested_functions_p=no])]) case $finally_cv_gcc_nested_functions_p in yes) finally_flavour=GCC_NESTED_FUNCTIONS finally_result="GCC nested functions" ;; esac ;; esac case $finally_flavour in undecided) dnl We've got this far and we've drawn a blank. Give up. finally_flavour=NIL ;; esac AC_LANG_POP([C]) dnl Pass the results on to the implementation machinery. AC_MSG_CHECKING([how to implement deferred cleanup code]) AC_DEFINE_UNQUOTED([FINALLY_CONFIG_FLAVOUR], [$finally_flavour], [Select one of the implementation strategies for the `FINALLY' macro.]) AC_SUBST(FINALLY_CFLAGS) AC_SUBST(FINALLY_LIBS) AC_MSG_RESULT([$finally_result]) dnl Invoke the caller's shell fragments according to our findings. case $finally_flavour in nil) $2 ;; *) $1 ;; esac ])