[Top][All Lists]
[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