Nick Bowler
2013-01-24 04:16:38 UTC
Hello Autoconfers,
I recently ran into an issue where the actions I had configured with
AC_CONFIG_COMMANDS_PRE from a macro were not actually being output to
the configure script. When I investigated, I noticed that the macro in
question was itself invoked inside an AC_CONFIG_COMMANDS_PRE command;
but as there was quite a bit of indirection involved this fact was not
immediately obvious.
Essentially the input looked like this:
% cat >configure.ac <<'EOF'
AC_INIT([test], [0])
dnl FOO uses AC_CONFIG_COMMANDS_PRE as part of its (internal)
dnl implementation.
AC_DEFUN_ONCE([FOO],
[AC_CONFIG_COMMANDS_PRE([m4_fatal([executed!])])])
dnl BAR is designed to be callable from an AC_CONFIG_COMMANDS_PRE block,
dnl but it has a dependency on FOO.
AC_DEFUN_ONCE([BAR], [AC_REQUIRE([FOO])])
dnl Calling BAR as designed ends up breaking FOO's usage of
dnl AC_CONFIG_COMMANDS_PRE.
AC_CONFIG_COMMANDS_PRE([BAR])
AC_OUTPUT
EOF
Currently, Autoconf accepts the above configure script as it does not
execute the m4_fatal call. This happens mainly due to the simplicity
of AC_CONFIG_COMMANDS_PRE: each invocation appends the argument to one
big macro which is then expanded once near the end. Any calls to
AC_CONFIG_COMMANDS_PRE that occur during this expansion still append
to that macro, but since it has already been expanded at this point
those don't go anywhere useful.
There doesn't seem to be an obvious way for FOO to test whether it has
been invoked indirectly from an AC_CONFIG_COMMANDS_PRE block and adapt
its behaviour accordingly, and I'd kind of like the scenario to work.
One possibility that comes to mind is that AC_CONFIG_COMMANDS_PRE
could be redefined to expand to its arguments verbatim just before
expanding AC_OUTPUT_COMMANDS_PRE. While this would work in my case,
I don't really like this option. I think it's reasonable to expect
that AC_CONFIG_COMMANDS_PRE commands are actually executed later
(specifically, that they are expanded sometime *after* the body of a
macro calling AC_CONFIG_COMMANDS_PRE).
A more complicated option would be a sort of "recursive" expansion of
AC_OUTPUT_COMMANDS_PRE, such that invocations of AC_CONFIG_COMMANDS_PRE
during the expansion are collected as usual, then *those* commands are
expanded after the current expansion of AC_OUTPUT_COMMANDS_PRE, and so
on until there are no more commands. I modified lib/autoconf/status.m4
to do just that, by defining the following helper macro:
# AC_OUTPUT_COMMANDS_REC(MACRO)
# -----------------------------
# Until the definition of MACRO is empty, repeatedly expand MACRO
# in a context where it has been redefined to the empty string.
m4_define([AC_OUTPUT_COMMANDS_REC], [m4_ifnblank(m4_defn([$1]),
[m4_define([$1], [m4_define([$1])]m4_defn([$1]))
m4_indir([$1])dnl
AC_OUTPUT_COMMANDS_REC([$1])])])
and replacing the call to AC_OUTPUT_COMMANDS_PRE() with
AC_OUTPUT_COMMANDS_REC([AC_OUTPUT_COMMANDS_PRE]). The same change could
be done for AC_CONFIG_COMMANDS_POST. This seems to work just fine,
although we could imagine some (crazy!) configure scripts for which this
change makes them non-terminating...
Any thoughts?
Thanks,
Nick
I recently ran into an issue where the actions I had configured with
AC_CONFIG_COMMANDS_PRE from a macro were not actually being output to
the configure script. When I investigated, I noticed that the macro in
question was itself invoked inside an AC_CONFIG_COMMANDS_PRE command;
but as there was quite a bit of indirection involved this fact was not
immediately obvious.
Essentially the input looked like this:
% cat >configure.ac <<'EOF'
AC_INIT([test], [0])
dnl FOO uses AC_CONFIG_COMMANDS_PRE as part of its (internal)
dnl implementation.
AC_DEFUN_ONCE([FOO],
[AC_CONFIG_COMMANDS_PRE([m4_fatal([executed!])])])
dnl BAR is designed to be callable from an AC_CONFIG_COMMANDS_PRE block,
dnl but it has a dependency on FOO.
AC_DEFUN_ONCE([BAR], [AC_REQUIRE([FOO])])
dnl Calling BAR as designed ends up breaking FOO's usage of
dnl AC_CONFIG_COMMANDS_PRE.
AC_CONFIG_COMMANDS_PRE([BAR])
AC_OUTPUT
EOF
Currently, Autoconf accepts the above configure script as it does not
execute the m4_fatal call. This happens mainly due to the simplicity
of AC_CONFIG_COMMANDS_PRE: each invocation appends the argument to one
big macro which is then expanded once near the end. Any calls to
AC_CONFIG_COMMANDS_PRE that occur during this expansion still append
to that macro, but since it has already been expanded at this point
those don't go anywhere useful.
There doesn't seem to be an obvious way for FOO to test whether it has
been invoked indirectly from an AC_CONFIG_COMMANDS_PRE block and adapt
its behaviour accordingly, and I'd kind of like the scenario to work.
One possibility that comes to mind is that AC_CONFIG_COMMANDS_PRE
could be redefined to expand to its arguments verbatim just before
expanding AC_OUTPUT_COMMANDS_PRE. While this would work in my case,
I don't really like this option. I think it's reasonable to expect
that AC_CONFIG_COMMANDS_PRE commands are actually executed later
(specifically, that they are expanded sometime *after* the body of a
macro calling AC_CONFIG_COMMANDS_PRE).
A more complicated option would be a sort of "recursive" expansion of
AC_OUTPUT_COMMANDS_PRE, such that invocations of AC_CONFIG_COMMANDS_PRE
during the expansion are collected as usual, then *those* commands are
expanded after the current expansion of AC_OUTPUT_COMMANDS_PRE, and so
on until there are no more commands. I modified lib/autoconf/status.m4
to do just that, by defining the following helper macro:
# AC_OUTPUT_COMMANDS_REC(MACRO)
# -----------------------------
# Until the definition of MACRO is empty, repeatedly expand MACRO
# in a context where it has been redefined to the empty string.
m4_define([AC_OUTPUT_COMMANDS_REC], [m4_ifnblank(m4_defn([$1]),
[m4_define([$1], [m4_define([$1])]m4_defn([$1]))
m4_indir([$1])dnl
AC_OUTPUT_COMMANDS_REC([$1])])])
and replacing the call to AC_OUTPUT_COMMANDS_PRE() with
AC_OUTPUT_COMMANDS_REC([AC_OUTPUT_COMMANDS_PRE]). The same change could
be done for AC_CONFIG_COMMANDS_POST. This seems to work just fine,
although we could imagine some (crazy!) configure scripts for which this
change makes them non-terminating...
Any thoughts?
Thanks,
Nick