chiark / gitweb /
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 ])