autoconf-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

AC_DEFUN_ONCE semantics


From: Eric Blake
Subject: AC_DEFUN_ONCE semantics
Date: Mon, 26 Jan 2009 17:09:28 +0000 (UTC)
User-agent: Loom/3.14 (http://gmane.org/)

After a long thread crossing between gnulib and bug-autoconf, here's the patch 
that I am applying which improves AC_DEFUN_ONCE semantics.  I'm now in the 
process of filtering through the list of macros which turn up during "git grep 
@defmac'[^(]*$' doc", to see which of them should be converted to AC_DEFUN_ONCE.

The new definition of m4_defun_once (which is an alias to AC_DEFUN_ONCE) used 
in this patch exploits internal knowledge of m4sugar primitives for optimal m4 
speed; the version of the patch that I am submitting to gnulib does the same 
thing, but with a bit more overhead, because it only uses public API available 
since at least 2.59.


From: Eric Blake <address@hidden>
Date: Mon, 26 Jan 2009 09:55:57 -0700
Subject: [PATCH] Improve AC_DEFUN_ONCE semantics.

* lib/m4sugar/m4sugar.m4 (m4_defun_once): Rewrite to be no-op,
rather than warning, on second use, and make sure first use never
occurs out of order.
* tests/m4sugar.at (m4@&address@hidden: one-shot initialization):
Enhance test.
* tests/base.at (AC_REQUIRE & AC_DEFUN_ONCE: [Require, expand],
(AC_REQUIRE & AC_DEFUN_ONCE: [Expand, require]): Adjust tests.
* NEWS: Document this.
* doc/autoconf.texi (Macro Definitions) <AC_DEFUN>: Mention
AC_DEFUN_ONCE.
(Prerequisite Macros) <AC_REQUIRE>: Likewise.
(Expanded Before Required): Likewise.
(One-Shot Macros) <AC_DEFUN_ONCE>: Document new semantics.
Reported by Bruno Haible, with suggestion by Paolo Bonzini.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog              |   18 ++++++++++++++++++
 NEWS                   |    6 ++++++
 doc/autoconf.texi      |   31 +++++++++++++++++++++----------
 lib/m4sugar/m4sugar.m4 |   17 ++++++++++-------
 tests/base.at          |   18 +++++++++---------
 tests/m4sugar.at       |   30 +++++++++++++++++++++++++++++-
 6 files changed, 93 insertions(+), 27 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 3881591..e7d833f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+2009-01-26  Eric Blake  <address@hidden>
+
+       Improve AC_DEFUN_ONCE semantics.
+       * lib/m4sugar/m4sugar.m4 (m4_defun_once): Rewrite to be no-op,
+       rather than warning, on second use, and make sure first use never
+       occurs out of order.
+       * tests/m4sugar.at (m4@&address@hidden: one-shot initialization):
+       Enhance test.
+       * tests/base.at (AC_REQUIRE & AC_DEFUN_ONCE: [Require, expand],
+       (AC_REQUIRE & AC_DEFUN_ONCE: [Expand, require]): Adjust tests.
+       * NEWS: Document this.
+       * doc/autoconf.texi (Macro Definitions) <AC_DEFUN>: Mention
+       AC_DEFUN_ONCE.
+       (Prerequisite Macros) <AC_REQUIRE>: Likewise.
+       (Expanded Before Required): Likewise.
+       (One-Shot Macros) <AC_DEFUN_ONCE>: Document new semantics.
+       Reported by Bruno Haible, with suggestion by Paolo Bonzini.
+
 2009-01-24  Eric Blake  <address@hidden>
 
        Fix typos in recent patches.
diff --git a/NEWS b/NEWS
index 5e43abc..d5c7ed2 100644
--- a/NEWS
+++ b/NEWS
@@ -14,6 +14,12 @@ GNU Autoconf NEWS - User visible changes.
    the bug in earlier autoconf versions and avoid increased script
    size in the current version.
 
+** AC_DEFUN_ONCE has improved semantics.  Previously, a macro declared
+   with AC_DEFUN_ONCE warned on a second invocation; and out-of-order
+   expansion was still possible.  Now, dependencies are guaranteed,
+   and subsequent invocations are a silent no-op.  This makes
+   AC_DEFUN_ONCE an ideal macro for silencing AC_REQUIRE warnings.
+
 ** AC_LANG_ERLANG works once again (regression introduced in 2.61a).
 
 ** AC_HEADER_ASSERT is fixed so that './configure --enable-assert' no
diff --git a/doc/autoconf.texi b/doc/autoconf.texi
index 4857eeb..fc7d42b 100644
--- a/doc/autoconf.texi
+++ b/doc/autoconf.texi
@@ -12830,7 +12830,8 @@ Macro Definitions
 which are shorthand for a fixed block of text, and therefore do not take
 arguments.  For this category of macros, directly expanding the macro
 multiple times results in redundant output, so it is more common to use
-the macro as the argument to @code{AC_REQUIRE}.
+the macro as the argument to @code{AC_REQUIRE}, or to declare the macro
+with @code{AC_DEFUN_ONCE} (@pxref{One-Shot Macros}).
 
 Be sure to properly quote both the @var{macro-body} @emph{and} the
 @var{macro-name} to avoid any problems if the macro happens to have
@@ -13171,7 +13172,9 @@ Prerequisite Macros
 
 The bug is not in Autoconf, but in the macro definitions.  If you ever
 pass a particular macro name to @code{AC_REQUIRE}, then you are implying
-that the macro only needs to be expanded once.  But to enforce this, all
+that the macro only needs to be expanded once.  But to enforce this,
+either the macro must be declared with @code{AC_DEFUN_ONCE} (although
+this only helps in Autoconf 2.64 or newer), or all
 uses of that macro should be through @code{AC_REQUIRE}; directly
 expanding the macro defeats the point of using @code{AC_REQUIRE} to
 eliminate redundant expansion.  In the example, this rule of thumb was
@@ -13271,16 +13274,21 @@ One-Shot Macros
 
 @defmac AC_DEFUN_ONCE (@var{macro-name}, @var{macro-body})
 @acindex{DEFUN_ONCE}
-
 Declare macro @var{macro-name} like @code{AC_DEFUN} would (@pxref{Macro
-Definitions}), and emit a warning any time the macro is called more than
-once.
+Definitions}), but add additional logic that guarantees that only the
+first use of the macro (whether by direct expansion or
address@hidden) causes an expansion of @var{macro-body}; the
+expansion will occur before the start of any enclosing macro defined by
address@hidden  Subsequent expansions are silently ignored.
+Generally, it does not make sense for @var{macro-body} to use parameters
+such as @code{$1}.
 @end defmac
 
-Obviously it is not sensible to evaluate a macro defined by
address@hidden in a macro defined by @code{AC_DEFUN}.
-Most of the time you want to use @code{AC_REQUIRE} (@pxref{Prerequisite
-Macros}).
+Prior to Autoconf 2.64, a macro defined by @code{AC_DEFUN_ONCE} would
+emit a warning if it was directly expanded a second time, so for
+portability, it is better to use @code{AC_REQUIRE} than direct
+invocation of @var{macro-name} inside a macro defined by @code{AC_DEFUN}
+(@pxref{Prerequisite Macros}).
 
 @node Obsoleting Macros
 @section Obsoleting Macros
@@ -22867,7 +22875,10 @@ Expanded Before Required
 @noindent
 To avoid this warning, decide what purpose the macro in question serves.
 If it only needs to be expanded once (for example, if it provides
-initialization text used by later macros), then the fix is to change all
+initialization text used by later macros), then the simplest fix is to
+change the macro to be declared with @code{AC_DEFUN_ONCE}
+(@pxref{One-Shot Macros}), although this only works in Autoconf 2.64 and
+newer.  A more portable fix is to change all
 instances of direct calls to instead go through @code{AC_REQUIRE}
 (@pxref{Prerequisite Macros}).  If, instead, the macro is parameterized
 by arguments or by the current definition of other macros in the m4
diff --git a/lib/m4sugar/m4sugar.m4 b/lib/m4sugar/m4sugar.m4
index df051a6..2ea42d8 100644
--- a/lib/m4sugar/m4sugar.m4
+++ b/lib/m4sugar/m4sugar.m4
@@ -1914,14 +1914,17 @@ m4_define([m4_defun_init],
 
 # m4_defun_once(NAME, EXPANSION)
 # ------------------------------
-# Like m4_defun, but issues the EXPANSION only once, and warns if used
-# several times.
+# Like m4_defun, but guarantee that EXPANSION only happens once
+# (thereafter, using NAME is a no-op).
+#
+# If _m4_divert_dump is empty, we are called at the top level;
+# otherwise, we must ensure that we are required in front of the
+# current defun'd macro.
 m4_define([m4_defun_once],
-[m4_define([m4_location($1)], m4_location)dnl
-m4_define([$1],
-         [m4_provide_if([$1],
-                        [m4_warn([syntax], [$1 invoked multiple times])],
-                        [_m4_defun_pro([$1])$2[]_m4_defun_epi([$1])])])])
+[m4_define([m4_location($1)], m4_location)]dnl
+[m4_define([$1], [m4_pushdef([$1])m4_if(_m4_divert_dump, [],
+  [_m4_defun_pro([$1])$2[]_m4_defun_epi([$1])],
+  [_m4_require_call([$1], [$2[]m4_provide([$1])], _m4_divert_dump)])])])
 
 
 # m4_pattern_forbid(ERE, [WHY])
diff --git a/tests/base.at b/tests/base.at
index 1ed8e1c..b5ee30f 100644
--- a/tests/base.at
+++ b/tests/base.at
@@ -2,8 +2,8 @@
 
 AT_BANNER([Autoconf base layer.])
 
-# Copyright (C) 2000, 2001, 2003, 2005, 2006, 2007, 2008 Free Software
-# Foundation, Inc.
+# Copyright (C) 2000, 2001, 2003, 2005, 2006, 2007, 2008, 2009 Free
+# Software Foundation, Inc.
 #
 # 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
@@ -28,6 +28,7 @@ AT_BANNER([Autoconf base layer.])
 # Check that dependencies are always properly honored.
 
 AT_SETUP([AC_REQUIRE: topological sort])
+AT_KEYWORDS([m4@&address@hidden)
 
 AT_DATA([configure.ac],
 [[define([REQUIRE_AND_CHECK],
@@ -71,6 +72,7 @@ AT_CLEANUP
 # Check that the message mentions AC_DEFUN, not m4_defun.
 
 AT_SETUP([AC_REQUIRE: error message])
+AT_KEYWORDS([m4@&address@hidden)
 AT_DATA([configure.ac],
 [[AC_REQUIRE([AC_PROG_CC])
 ]])
@@ -88,6 +90,7 @@ AT_CLEANUP
 ## ----------------------------------------------- ##
 
 AT_SETUP([AC_REQUIRE & AC_DEFUN_ONCE: [Require, expand]])
+AT_KEYWORDS([m4@&address@hidden m4@&address@hidden)
 
 AT_DATA([configure.ac],
 [[AC_DEFUN([TEST],
@@ -116,10 +119,7 @@ case $multi_test:$single_test in
 esac
 ]])
 
-AT_CHECK_AUTOCONF([], 0, [],
-[configure.ac:17: warning: SINGLE_TEST invoked multiple times
-configure.ac:18: warning: SINGLE_TEST invoked multiple times
-])
+AT_CHECK_AUTOCONF([], 0, [])
 
 AT_CHECK_CONFIGURE
 
@@ -132,6 +132,7 @@ AT_CLEANUP
 ## ----------------------------------------------- ##
 
 AT_SETUP([AC_REQUIRE & AC_DEFUN_ONCE: [Expand, require]])
+AT_KEYWORDS([m4@&address@hidden m4@&address@hidden)
 
 AT_DATA([configure.ac],
 [[AC_DEFUN([TEST],
@@ -161,9 +162,7 @@ case $multi_test:$single_test in
 esac
 ]])
 
-AT_CHECK_AUTOCONF([], 0, [],
-[configure.ac:16: warning: SINGLE_TEST invoked multiple times
-])
+AT_CHECK_AUTOCONF([], 0, [])
 AT_CHECK_CONFIGURE
 
 AT_CLEANUP
@@ -175,6 +174,7 @@ AT_CLEANUP
 ## ------------------------- ##
 
 AT_SETUP([AC_REQUIRE & AC_PROVIDE])
+AT_KEYWORDS([m4@&address@hidden)
 
 AT_DATA([configure.ac],
 [[AC_DEFUN([TEST],
diff --git a/tests/m4sugar.at b/tests/m4sugar.at
index 22e7a07..99d8eab 100644
--- a/tests/m4sugar.at
+++ b/tests/m4sugar.at
@@ -430,8 +430,9 @@ AT_CLEANUP
 
 AT_SETUP([m4@&address@hidden: one-shot initialization])
 AT_KEYWORDS([m4@&address@hidden)
-AT_KEYWORDS([m4@&address@hidden m4@&address@hidden)
+AT_KEYWORDS([m4@&address@hidden m4@&address@hidden m4@&address@hidden)
 
+dnl check out m4_defun_init, m4_copy, and odd macro names
 AT_CHECK_M4SUGAR_TEXT([[
 m4_defun_init([a], [[init a
 ]], [[common a]])dnl
@@ -455,6 +456,33 @@ hello, world
 goodbye
 hello, again
 ]])
+
+dnl Check m4_defun_once behavior
+AT_CHECK_M4SUGAR_TEXT([[
+m4_defun_once([a], [[a]])dnl
+m4_defun([b], [[b]m4_require([a])])dnl
+m4_defun([c], [[c]
+a[]m4_require([b])])dnl
+c
+a
+m4_defun_once([d], [[d]m4_require([a])])dnl
+d
+m4_defun_once([e], [[e]])dnl
+m4_defun([f], [[f]m4_require([e])e])dnl
+f
+]], [[
+a
+b
+c
+
+
+d
+e
+
+f
+]])
+
+
 AT_CLEANUP
 
 
-- 
1.6.0.4







reply via email to

[Prev in Thread] Current Thread [Next in Thread]