Initial sketch.
[finally] / m4 / finally.m4
1 dnl -*-autoconf-*-
2
3 ### SYNOPSIS
4 ###
5 ### FINALLY([IF-SUCCEEDED], [IF-FAILED])
6 ###
7 ### DESCRIPTION
8 ###
9 ### Probe at the C compiler to determine how, if at all, to implement the
10 ### `FINALLY' macro, which arranges to run some code when control leaves a
11 ### given scope. This isn't at all a standard C feature, so we need to use
12 ### compiler-specific hacks, and this is the main machinery for deciding
13 ### which hacks to deploy.
14 ###
15 ### On exit, the shell variable `finally_flavour' is set to an uppercase
16 ### word naming the chosen implementation strategy: it will be `NIL' if the
17 ### macro failed and no strategy could be found. The preprocessor define
18 ### `FINALLY_CONFIG_FLAVOUR' is set to `FINALLY_CONFIG_FLAVOUR_...'
19 ### followed by the same word: this is the main input to the selection
20 ### machinery in `finally.h'.
21 ###
22 ### The substitution variables `FINALLY_CFLAGS' and `FINALLY_LIBS' are set
23 ### to any additional compiler flags or libraries needed to support the
24 ### `FINALLY' macro. They can be set per-target in the `Makefile', or
25 ### stuffed into the global variables by the `configure' script.
26 ###
27 ### If the macro managed to find a workable strategy, then the shell
28 ### fragment IF-SUCCEEDED is run; otherwise, (if `finally_flavour' is
29 ### `NIL'), the shell fragment IF-FAILED is run.
30 ###
31 ### LICENSE
32 ###
33 ### Copyright (c) 2023 Mark Wooding <mdw@distorted.org.uk>
34 ###
35 ### This program is free software: you can redistribute it and/or modify it
36 ### under the terms of the GNU General Public License as published by the
37 ### Free Software Foundation, either version 2 of the License, or (at your
38 ### option) any later version.
39 ###
40 ### This program is distributed in the hope that it will be useful, but
41 ### WITHOUT ANY WARRANTY; without even the implied warranty of
42 ### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
43 ### General Public License for more details.
44 ###
45 ### You should have received a copy of the GNU General Public License along
46 ### with this program. If not, see <http://www.gnu.org/licenses/>.
47 ###
48 ### In particular, no exception to the GPL is granted regarding generated
49 ### `configure' scripts which are the output of Autoconf.
50
51 AC_DEFUN([FINALLY_GCC_NESTED_FUNCTIONS_TEST_PROGRAM], [AC_LANG_PROGRAM([], [
52 __extension__ __inline__ void nested(void) { ; }
53 nested();
54 ])])
55 AC_DEFUN([FINALLY_GCC_ATTRIBUTE_CLEANUP_TEST_PROGRAM], [AC_LANG_PROGRAM([
56 extern void cleanup_fn(const int *x);
57 extern void bamboozle(int *x_inout);
58 ], [
59 __attribute__((cleanup(cleanup_fn))) int x = 0;
60 bamboozle(&x);
61 ])])
62
63 dnl Decide whether we can define a plausible `FINALLY' macro.
64 AC_DEFUN([FINALLY_CHECK],
65 [finally_flavour=undecided finally_result="not supported"
66
67 dnl We're going to want to test C code.
68 AC_LANG_PUSH([C])
69
70 case $finally_flavour,$GCC in
71 undecided,yes)
72 dnl Our GCC-ish strategies have a common factor: they depend on
73 dnl `__attribute__((cleanup(...)))' working. So let's check for that.
74
75 AC_CACHE_CHECK([whether the alleged GNU C compiler supports \`__attribute__((cleanup(...)))'],
76 [finally_cv_gcc_attribute_cleanup_p], [
77 AC_COMPILE_IFELSE([FINALLY_GCC_ATTRIBUTE_CLEANUP_TEST_PROGRAM],
78 [finally_cv_gcc_attribute_cleanup_p=yes],
79 [finally_cv_gcc_attribute_cleanup_p=no])])
80 case $finally_cv_gcc_attribute_cleanup_p in
81 no) finally_flavour=NIL ;;
82 esac
83 ;;
84 esac
85
86 case $finally_flavour,$GCC in
87 undecided,yes)
88 dnl Autoconf has decided that the compiler smells a bit like GCC, and it
89 dnl certainly seems to support a GCC extension. But many compilers
90 dnl impersonate GCC, in more or less convincing ways. Our GCC-flavoured
91 dnl `FINALLY' code depends on nested functions, which GCC has supported
92 dnl pretty much forever, but other compilers don't even though they lie
93 dnl about being compatible.
94
95 AC_CACHE_CHECK([whether the alleged GNU C compiler supports nested functions],
96 [finally_cv_gcc_nested_functions_p], [
97 AC_COMPILE_IFELSE([FINALLY_GCC_NESTED_FUNCTIONS_TEST_PROGRAM],
98 [finally_cv_gcc_nested_functions_p=yes],
99 [finally_cv_gcc_nested_functions_p=no])])
100 case $finally_cv_gcc_nested_functions_p in
101 yes)
102 finally_flavour=GCC_NESTED_FUNCTIONS
103 finally_result="GCC nested functions"
104 ;;
105 esac
106 ;;
107 esac
108
109 case $finally_flavour in
110 undecided)
111 dnl We've got this far and we've drawn a blank. Give up.
112 finally_flavour=NIL
113 ;;
114 esac
115
116 AC_LANG_POP([C])
117
118 dnl Pass the results on to the implementation machinery.
119 AC_MSG_CHECKING([how to implement deferred cleanup code])
120 AC_DEFINE_UNQUOTED([FINALLY_CONFIG_FLAVOUR],
121 [$finally_flavour],
122 [Select one of the implementation strategies for the `FINALLY' macro.])
123 AC_SUBST(FINALLY_CFLAGS) AC_SUBST(FINALLY_LIBS)
124 AC_MSG_RESULT([$finally_result])
125
126 dnl Invoke the caller's shell fragments according to our findings.
127 case $finally_flavour in
128 nil)
129 $2
130 ;;
131 *)
132 $1
133 ;;
134 esac
135 ])