autoconf-patches
[Top][All Lists]
Advanced

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

[PATCH] use m4_require to implement AS_REQUIRE


From: Paolo Bonzini
Subject: [PATCH] use m4_require to implement AS_REQUIRE
Date: Sun, 12 Oct 2008 18:20:53 +0200

Hi, I know I should be writing testcases for AS_ME_PREPARE. :-) But
while I was looking at adding shell functions to Autoconf proper, I
decided that the current basic implementation of AS_REQUIRE is not
scalable.

In particular, AC_CHECK_FUNC will need its own shell function, plus
the one for AC_LINK_IFELSE.  If AC_LINK_IFELSE has not been expanded yet,
then something like this comes out of m4:

  ac_c_check_func() {
    if test $ac_cv...; then
      ...
    else
      ac_c_link_ifelse() {
      }
    fi
  }

which does not work of course.  Another problem happens if AC_LANG(C)
is expanded in M4SH-INIT-FN, like

  ac_c_try_link () {
  }
  ac_ext=c
  ac_c_check_func () {
  }
  ...

The implementation is easy, though I had to try several times before
getting it right.  Anyway, the attached patch works and adds a testcase
for the first behavior.  The second bug is already tested by the existing
AS_REQUIRE_SHELL_FN test, which however needs to be modified in order
to really test this behavior.

I chose not to add a third argument to m4_require, as I did for
AS_REQUIRE, because m4_require is on an expensive path.  Should
m4_divert_require be documented?

I have not run the entire testsuite (I will before committing) but I
have run the m4sugar and m4sh testsuites, as well as tests related to
the shell functions I already added.  While testing, I noticed the effect
of the speedups introduced after 2.61; on GNU Smalltalk I have:

   ver      usertime   size
   2.61     18.154s    1037578
   2.63     13.192s    1055693

So many kudos for this!

Anyway, adding functions for AC_{PREPROC,COMPILE,LINK}_IFELSE adds more
m4_require on a frequently expanded and otherwise inexpensive path.
It cuts down the size a lot, but slows down over 5%.  However, adding
more functions for AC_CHECK_FUNC and AC_CHECK_HEADER removes 20% of the
expansions of AC_*_IFELSE, and actually starts saving time (overall 10%)
because AC_CHECK_* macros _are_ expansive to expand.  And the space
savings are 25%:

   +funcs1  13.907s    886574
   +funcs2  11.467s    780238

and it could be even more by transitioning more AC_CHECK_*.

In the meanwhile, ok to apply after proper testing?

Paolo

2008-10-12  Paolo Bonzini  <address@hidden>

        * lib/m4sugar/m4sugar.m4 (_m4_require_call): Accept a third argument.
        (m4_require): Pass it.
        (m4_divert_require): New.
        * lib/m4sugar/m4sh.m4 (AS_REQUIRE): Rewrite using m4_divert_require.
        Remove comment about differences with m4_require.
        * tests/m4sh.at (AS_REQUIRE_SHELL_FN and m4_require): Update to test
        the expected behavior.
        (Nested AS_REQUIRE_SHELL_FN): New test.
---
 lib/m4sugar/m4sh.m4    |   45 +++++++--------------------------------------
 lib/m4sugar/m4sugar.m4 |   25 ++++++++++++++++++++-----
 tests/m4sh.at          |   36 ++++++++++++++++++++++++++++++++++--
 3 files changed, 61 insertions(+), 45 deletions(-)

diff --git a/lib/m4sugar/m4sh.m4 b/lib/m4sugar/m4sh.m4
index ef3d93b..43314a9 100644
--- a/lib/m4sugar/m4sh.m4
+++ b/lib/m4sugar/m4sh.m4
@@ -298,45 +298,14 @@ AS_REQUIRE([_AS_TR_SH_PREPARE])
 #            [DIVERSION = M4SH-INIT])
 # -----------------------------------------------------------
 # BODY-TO-EXPAND is some initialization which must be expanded in the
-# given diversion when expanded (required or not).  This is very
-# different from m4_require.  For instance:
+# given diversion when expanded (required or not).  The expansion
+# goes in the named diversion or an earlier one.
 #
-#      m4_defun([_FOO_PREPARE], [foo=foo])
-#      m4_defun([FOO],
-#      [m4_require([_FOO_PREPARE])dnl
-#      echo $foo])
-#
-#      m4_defun([_BAR_PREPARE], [bar=bar])
-#      m4_defun([BAR],
-#      [AS_REQUIRE([_BAR_PREPARE])dnl
-#      echo $bar])
-#
-#      AS_INIT
-#      foo1=`FOO`
-#      foo2=`FOO`
-#      bar1=`BAR`
-#      bar2=`BAR`
-#
-# gives
-#
-#      #! /bin/sh
-#      bar=bar
-#
-#      foo1=`foo=foo
-#      echo $foo`
-#      foo2=`echo $foo`
-#      bar1=`echo $bar`
-#      bar2=`echo $bar`
-#
-# Due to the simple implementation, all the AS_REQUIRE calls have to be at
-# the very beginning of the macro body, or the AS_REQUIREs may not be nested.
-# More exactly, if a macro doesn't have all AS_REQUIREs at its beginning,
-# it may not be AS_REQUIREd.
-#
-m4_define([AS_REQUIRE],
-[m4_provide_if([$1], [],
-              [m4_divert_text(m4_default_quoted([$3], [M4SH-INIT]),
-                              [m4_default([$2], [$1])])])])
+m4_defun([AS_REQUIRE],
+[m4_define([_m4_divert_desired], m4_default_quoted([$3], [M4SH-INIT]))dnl
+m4_if(m4_eval(_m4_divert(_m4_divert_dump) <= _m4_divert(_m4_divert_desired)), 
1,
+      [m4_require([$1], [$2])],
+      [m4_divert_require([_m4_divert_desired], [$1], [$2])])])
 
 
 # AS_REQUIRE_SHELL_FN(NAME-TO-CHECK, BODY-TO-EXPAND,
diff --git a/lib/m4sugar/m4sugar.m4 b/lib/m4sugar/m4sugar.m4
index 04a41e3..f5664a5 100644
--- a/lib/m4sugar/m4sugar.m4
+++ b/lib/m4sugar/m4sugar.m4
@@ -1583,6 +1583,20 @@ m4_define([_m4_defun_epi_outer],
 [_m4_undefine([_m4_divert_dump])m4_divert_pop([GROW])m4_undivert([GROW])])
 
 
+# m4_divert_require(DIVERSION, NAME-TO-CHECK, [BODY-TO-EXPAND])
+# --------------------------------------------------------------
+# Same as m4_require, but BODY-TO-EXPAND goes into the named diversion;
+# requirements still go in the current diversion though.
+#
+m4_define([m4_divert_require],
+m4_do([[m4_ifdef([_m4_expanding($2)],
+                [m4_fatal([$0: circular dependency of $2])])]],
+      [[m4_ifdef([_m4_divert_dump], [],
+                [m4_fatal([$0($2): cannot be used outside of an m4_defun'd 
macro])])]],
+      [[m4_provide_if([$2],
+                     [],
+                     [_m4_require_call([$2], [$3], [$1])])]]))
+
 # m4_defun(NAME, EXPANSION)
 # -------------------------
 # Define a macro which automatically provides itself.  Add machinery
@@ -1681,12 +1695,13 @@ m4_do([[m4_ifdef([_m4_expanding($1)],
 m4_bmatch([$0], [^AC_], [[AC_DEFUN]], [[m4_defun]])['d macro])])]],
       [[m4_provide_if([$1],
                      [],
-                     [_m4_require_call([$1], [$2])])]]))
+                     [_m4_require_call([$1], [$2], 
[_m4_defn([_m4_divert_dump])])])]]))
 
 
-# _m4_require_call(NAME-TO-CHECK, [BODY-TO-EXPAND = NAME-TO-CHECK])
-# -----------------------------------------------------------------
-# If m4_require decides to expand the body, it calls this macro.
+# _m4_require_call(NAME-TO-CHECK, [BODY-TO-EXPAND = NAME-TO-CHECK], DIVERSION)
+# ----------------------------------------------------------------------------
+# If m4_require decides to expand the body, it calls this macro.  The
+# expansion is placed in DIVERSION.
 #
 # This is called frequently, so minimize the number of macro invocations
 # by avoiding dnl and other overhead on the common path.
@@ -1698,7 +1713,7 @@ m4_provide_if([$1],
              [],
              [m4_warn([syntax],
                       [$1 is m4_require'd but not m4_defun'd])])]],
-      [[m4_divert(_m4_defn([_m4_divert_dump]))]],
+      [[m4_divert($3)]],
       [[m4_undivert(_m4_divert_grow)]],
       [[m4_divert_pop(_m4_divert_grow)]],
       [[m4_define([_m4_divert_grow], m4_incr(_m4_divert_grow))]]))
diff --git a/tests/m4sh.at b/tests/m4sh.at
index d2c62e7..4ba8a78 100644
--- a/tests/m4sh.at
+++ b/tests/m4sh.at
@@ -454,12 +454,44 @@ AT_CHECK([./script])
 AT_CLEANUP
 
 
+## --------------------------- ##
+## Nested AS_REQUIRE_SHELL_FN ##
+## --------------------------- ##
+
+# Hypothesis: M4sh expands nested AS_REQUIRE_SHELL_FN
+# separately.
+
+AT_SETUP([Nested AS@&address@hidden)
+AT_KEYWORDS([m4sh])
+
+AT_DATA_M4SH([script.as], [[dnl
+AS_INIT
+
+m4_defun([TEST_FUNC2_BODY], [
+:
+])
+
+m4_defun([TEST_FUNC1_BODY], [
+AS_REQUIRE_SHELL_FN([test_func2], [TEST_FUNC2_BODY])
+:
+])
+
+AS_REQUIRE_SHELL_FN([test_func1], [TEST_FUNC1_BODY])
+test_func2
+]])
+
+AT_CHECK_M4SH
+AT_CHECK([./script])
+
+AT_CLEANUP
+
+
 ## ------------------------------------ ##
 ## AS_REQUIRE_SHELL_FN and m4_require.  ##
 ## ------------------------------------ ##
 
 # Hypothesis: M4sh expands the requirements of AS_REQUIRE_SHELL_FN
-# in the main diversion, and not in M4SH-INIT.
+# in M4SH-INIT-FN.  This changed after Autoconf 2.63.
 
 AT_SETUP([AS@&address@hidden and m4@&address@hidden)
 AT_KEYWORDS([m4sh])
@@ -483,7 +515,7 @@ m4_require([error_if_emitted_in_m4sh_init])
 
 
 m4_defun([test_init], [
-AS_REQUIRE([in_m4_sh_init])
+AS_REQUIRE([in_m4_sh_init], , [M4SH-INIT-FN])
 AS_REQUIRE_SHELL_FN([test_func], [TEST_FUNC_BODY])
 AS_REQUIRE([not_in_m4_sh_init])
 ])
-- 
1.5.5





reply via email to

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