Quantcast

[PATCH v2 0/3] limit number of cat and sed forks

classic Classic list List threaded Threaded
11 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[PATCH v2 0/3] limit number of cat and sed forks

Paolo Bonzini-2
These three patches speed up libvirt's configure script by roughly 3%,
by avoiding repeated calls to sed (for AS_TR_SH and AS_TR_CPP, patches 1-2)
and cat (for _AC_DEFINE_UNQUOTED, patch 3).  The AS_TR_SH and AS_TR_CPP
computations are moved to autoconf time.  cat is replaced by printf.

Thanks,

Paolo

Paolo Bonzini (3):
  autoconf: prefer an unrolled loop for trivial AC_CHECK_FUNCS
  autoconf: prefer an unrolled loop for trivial AC_CHECK_HEADERS
  autoconf: refine quadrigraph test in _AC_DEFINE_UNQUOTED

 lib/autoconf/functions.m4 | 25 +++++++++++--------------
 lib/autoconf/general.m4   |  6 ++++--
 lib/autoconf/headers.m4   | 30 +++++++++++++-----------------
 3 files changed, 28 insertions(+), 33 deletions(-)

--
2.7.4


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[PATCH v2 2/3] autoconf: prefer an unrolled loop for trivial AC_CHECK_HEADERS

Paolo Bonzini-2
An unrolled loop avoids the cost of spawning sed in AS_TR_SH and
AS_TR_CPP.  Prefer it if there is nothing in the second and third
argument of AC_CHECK_HEADERS and the first argument is a literal.
Modify AC_CHECK_HEADERS_ONCE to avoid the variable indirection too.

* lib/autoconf/headers.m4 (AC_CHECK_HEADERS): Unroll loop if safe.
(_AC_CHECK_HEADERS): Move basic implementation here.
(_AC_CHECK_HEADER_ONCE): Expand AC_CHECK_HEADERS here...
(_AC_HEADERS_EXPANSION): ... and not here, so remove.
(AC_CHECK_INCLUDES_DEFAULT): Remove unnecessary arguments after the first.

Signed-off-by: Paolo Bonzini <[hidden email]>
---
 lib/autoconf/headers.m4 | 30 +++++++++++++-----------------
 1 file changed, 13 insertions(+), 17 deletions(-)

diff --git a/lib/autoconf/headers.m4 b/lib/autoconf/headers.m4
index 72262c1..42f373f 100644
--- a/lib/autoconf/headers.m4
+++ b/lib/autoconf/headers.m4
@@ -182,22 +182,25 @@ m4_define([AH_CHECK_HEADERS],
 # header.  Either ACTION may include `break' to stop the search.
 AC_DEFUN([AC_CHECK_HEADERS],
 [m4_map_args_w([$1], [_AH_CHECK_HEADER(], [)])]dnl
-[AS_FOR([AC_header], [ac_header], [$1],
-[AC_CHECK_HEADER(AC_header,
- [AC_DEFINE_UNQUOTED(AS_TR_CPP([HAVE_]AC_header)) $2],
- [$3], [$4])dnl])
+[m4_if([$2$3]AS_LITERAL_IF([$1], [[yes]], [[no]]), [yes],
+       [m4_map_args_w([$1], [_$0(], [, [], [], [$4])])],
+       [AS_FOR([AC_header], [ac_header], [$1], [_$0(AC_header, [$2], [$3], [$4])])])
 ])# AC_CHECK_HEADERS
 
+m4_define([_AC_CHECK_HEADERS],
+[AC_CHECK_HEADER([$1],
+ [AC_DEFINE_UNQUOTED(AS_TR_CPP([HAVE_]$1)) $2],
+ [$3], [$4])
+])
+
 
 # _AC_CHECK_HEADER_ONCE(HEADER-FILE)
 # ----------------------------------
 # Check for a single HEADER-FILE once.
 m4_define([_AC_CHECK_HEADER_ONCE],
-[_AH_CHECK_HEADER([$1])AC_DEFUN([_AC_Header_]m4_translit([[$1]],
-    [./-], [___]),
-  [m4_divert_text([INIT_PREPARE], [AS_VAR_APPEND([ac_header_list], [" $1"])])
-_AC_HEADERS_EXPANSION])AC_REQUIRE([_AC_Header_]m4_translit([[$1]],
-    [./-], [___]))])
+[AC_DEFUN([_AC_Header_]m4_translit([[$1]], [./-], [___]),
+          [AC_CHECK_HEADERS([$1], [], [], [$ac_includes_default])])
+AC_REQUIRE([_AC_Header_]m4_translit([[$1]], [./-], [___]))])
 
 
 # AC_CHECK_HEADERS_ONCE(HEADER-FILE...)
@@ -213,12 +216,6 @@ AC_DEFUN([AC_CHECK_HEADERS_ONCE],
 AC_DEFUN([_AC_CHECK_HEADERS_ONCE],
   [m4_map_args_w([$1], [_AC_CHECK_HEADER_ONCE(], [)])])
 
-m4_define([_AC_HEADERS_EXPANSION],
-  [m4_divert_text([DEFAULTS], [ac_header_list=])]dnl
-  [AC_CHECK_HEADERS([$ac_header_list], [], [], [$ac_includes_default])]dnl
-  [m4_define([_AC_HEADERS_EXPANSION], [])])
-
-
 
 
 ## --------------------- ##
@@ -261,8 +258,7 @@ ac_includes_default="\
 #endif"
 ])]dnl
 [_AC_CHECK_HEADERS_ONCE(
-  [sys/types.h sys/stat.h strings.h inttypes.h stdint.h unistd.h],
-  [], [], [$ac_includes_default])]dnl
+  [sys/types.h sys/stat.h strings.h inttypes.h stdint.h unistd.h])]dnl
 dnl For backward compatibility, provide unconditional AC_DEFINEs of
 dnl HAVE_STDLIB_H, HAVE_STRING_H, and STDC_HEADERS.
 [AC_DEFINE([HAVE_STDLIB_H], [1],
--
2.7.4



Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[PATCH v2 1/3] autoconf: prefer an unrolled loop for trivial AC_CHECK_FUNCS

Paolo Bonzini-2
In reply to this post by Paolo Bonzini-2
An unrolled loop avoids the cost of spawning sed in AS_TR_SH and
AS_TR_CPP.  Prefer it if there is nothing in the second and third
argument of AC_CHECK_FUNCS and the first argument is a literal.
Modify AC_CHECK_FUNCS_ONCE to avoid the variable indirection too.

* lib/autoconf/functions.m4 (AC_CHECK_FUNCS): Unroll loop if safe.
(_AC_CHECK_FUNCS): Move basic implementation here.
(_AC_CHECK_FUNC_ONCE): Expand AC_CHECK_FUNCS here...
(_AC_FUNCS_EXPANSION): ... and not here, so remove.

Signed-off-by: Paolo Bonzini <[hidden email]>
---
 lib/autoconf/functions.m4 | 25 +++++++++++--------------
 1 file changed, 11 insertions(+), 14 deletions(-)

diff --git a/lib/autoconf/functions.m4 b/lib/autoconf/functions.m4
index 66abe29..ccfb053 100644
--- a/lib/autoconf/functions.m4
+++ b/lib/autoconf/functions.m4
@@ -85,20 +85,24 @@ m4_define([_AH_CHECK_FUNC],
 # `break' to stop the search.
 AC_DEFUN([AC_CHECK_FUNCS],
 [m4_map_args_w([$1], [_AH_CHECK_FUNC(], [)])]dnl
-[AS_FOR([AC_func], [ac_func], [$1],
-[AC_CHECK_FUNC(AC_func,
-       [AC_DEFINE_UNQUOTED(AS_TR_CPP([HAVE_]AC_func)) $2],
-       [$3])dnl])
+[m4_if([$2$3]AS_LITERAL_IF([$1], [[yes]], [[no]]), [yes],
+       [m4_map_args_w([$1], [_$0(], [)])],
+       [AS_FOR([AC_func], [ac_func], [$1], [_$0(AC_func, [$2], [$3])])])
 ])# AC_CHECK_FUNCS
 
+m4_define([_AC_CHECK_FUNCS],
+[AC_CHECK_FUNC([$1],
+       [AC_DEFINE_UNQUOTED(AS_TR_CPP([HAVE_]$1)) $2],
+       [$3])
+])
+
 
 # _AC_CHECK_FUNC_ONCE(FUNCTION)
 # -----------------------------
 # Check for a single FUNCTION once.
 m4_define([_AC_CHECK_FUNC_ONCE],
-[_AH_CHECK_FUNC([$1])AC_DEFUN([_AC_Func_$1],
-  [m4_divert_text([INIT_PREPARE], [AS_VAR_APPEND([ac_func_list], [" $1"])])
-_AC_FUNCS_EXPANSION])AC_REQUIRE([_AC_Func_$1])])
+[AC_DEFUN([_AC_Func_$1], [AC_CHECK_FUNCS([$1])])
+AC_REQUIRE([_AC_Func_$1])])
 
 # AC_CHECK_FUNCS_ONCE(FUNCTION...)
 # --------------------------------
@@ -107,13 +111,6 @@ _AC_FUNCS_EXPANSION])AC_REQUIRE([_AC_Func_$1])])
 AC_DEFUN([AC_CHECK_FUNCS_ONCE],
 [m4_map_args_w([$1], [_AC_CHECK_FUNC_ONCE(], [)])])
 
-m4_define([_AC_FUNCS_EXPANSION],
-[
-  m4_divert_text([DEFAULTS], [ac_func_list=])
-  AC_CHECK_FUNCS([$ac_func_list])
-  m4_define([_AC_FUNCS_EXPANSION], [])
-])
-
 
 # _AC_REPLACE_FUNC(FUNCTION)
 # --------------------------
--
2.7.4



Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[PATCH v2 3/3] autoconf: refine quadrigraph test in _AC_DEFINE_UNQUOTED

Paolo Bonzini-2
In reply to this post by Paolo Bonzini-2
It is a very common case that a quadrigraph appears in the argument of
_AC_DEFINE_UNQUOTED, because "#define" is expanded through a quadrigraph.
Therefore, restrict the quadrigraph tests to "$" (for "$(" and "${")
and "(" (for "$(").

At the same time, "#" should not be used inside AC_ECHO because it confuses
m4's comment parsing.  This pre-existing latent bug is caught by test 251:

   AC_DEFINE_UNQUOTED([bar], [[%!_!# X]])

Previously the quadrigraph in "@%:@define bar %!_!# X" made Autoconf fall back
to cat anyway.  Now that Autoconf is not fooled by the quadrigraph, the test
catches that "#" is not special-cased.  Kudos to Eric for coming up with it!

* lib/autoconf/general (_AC_DEFINE_UNQUOTED): Do not blindly
use cat on all quadrigraphs.

Signed-off-by: Paolo Bonzini <[hidden email]>
---
 lib/autoconf/general.m4 | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/lib/autoconf/general.m4 b/lib/autoconf/general.m4
index c15fb13..ef6285d 100644
--- a/lib/autoconf/general.m4
+++ b/lib/autoconf/general.m4
@@ -2167,9 +2167,11 @@ m4_define([AC_DEFINE_UNQUOTED], [_AC_DEFINE_Q([_$0], $@)])
 # Append the pre-expanded STRING and a newline to confdefs.h, as if
 # with an unquoted here-doc, but avoiding a fork in the common case of
 # no backslash, no command substitution, no complex variable
-# substitution, and no quadrigraphs.
+# substitution (taking into account quadrigraphs as well).  Also
+# avoid AS_ECHO if "#" is present to avoid confusing m4 with comments,
+# but quadrigraphs are fine in that case.
 m4_define([_AC_DEFINE_UNQUOTED],
-[m4_if(m4_bregexp([$1], [\\\|`\|\$(\|\${\|@]), [-1],
+[m4_if(m4_bregexp([$1], [#\|\\\|`\|\(\$\|@S|@\)\((|{|@{:@\)]), [-1],
        [AS_ECHO(["AS_ESCAPE([$1], [""])"]) >>confdefs.h],
        [cat >>confdefs.h <<_ACEOF
 [$1]
--
2.7.4


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [PATCH v2 0/3] limit number of cat and sed forks

Eric Blake-3
In reply to this post by Paolo Bonzini-2
On 10/31/2016 12:08 PM, Paolo Bonzini wrote:
> These three patches speed up libvirt's configure script by roughly 3%,
> by avoiding repeated calls to sed (for AS_TR_SH and AS_TR_CPP, patches 1-2)
> and cat (for _AC_DEFINE_UNQUOTED, patch 3).  The AS_TR_SH and AS_TR_CPP
> computations are moved to autoconf time.  cat is replaced by printf.
>

I'm still working on testing this (I'm trying to test against coreutils,
to see the impact in configure size - but that turned up a recent
problem in gnulib that I have to resolve first), but will get it in shortly.

--
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


signature.asc (617 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [PATCH v2 1/3] autoconf: prefer an unrolled loop for trivial AC_CHECK_FUNCS

Eric Blake-3
In reply to this post by Paolo Bonzini-2
On 10/31/2016 12:08 PM, Paolo Bonzini wrote:

> An unrolled loop avoids the cost of spawning sed in AS_TR_SH and
> AS_TR_CPP.  Prefer it if there is nothing in the second and third
> argument of AC_CHECK_FUNCS and the first argument is a literal.
> Modify AC_CHECK_FUNCS_ONCE to avoid the variable indirection too.
>
> * lib/autoconf/functions.m4 (AC_CHECK_FUNCS): Unroll loop if safe.
> (_AC_CHECK_FUNCS): Move basic implementation here.
> (_AC_CHECK_FUNC_ONCE): Expand AC_CHECK_FUNCS here...
> (_AC_FUNCS_EXPANSION): ... and not here, so remove.
>
> Signed-off-by: Paolo Bonzini <[hidden email]>
> ---
>  lib/autoconf/functions.m4 | 25 +++++++++++--------------
>  1 file changed, 11 insertions(+), 14 deletions(-)
>
> diff --git a/lib/autoconf/functions.m4 b/lib/autoconf/functions.m4
> index 66abe29..ccfb053 100644
> --- a/lib/autoconf/functions.m4
> +++ b/lib/autoconf/functions.m4
> @@ -85,20 +85,24 @@ m4_define([_AH_CHECK_FUNC],
>  # `break' to stop the search.
>  AC_DEFUN([AC_CHECK_FUNCS],
>  [m4_map_args_w([$1], [_AH_CHECK_FUNC(], [)])]dnl
> -[AS_FOR([AC_func], [ac_func], [$1],
> -[AC_CHECK_FUNC(AC_func,
> -       [AC_DEFINE_UNQUOTED(AS_TR_CPP([HAVE_]AC_func)) $2],
> -       [$3])dnl])
> +[m4_if([$2$3]AS_LITERAL_IF([$1], [[yes]], [[no]]), [yes],
> +       [m4_map_args_w([$1], [_$0(], [)])],
> +       [AS_FOR([AC_func], [ac_func], [$1], [_$0(AC_func, [$2], [$3])])])
Dropping the dnl adds a lot of blank lines to configure scripts, I will
massage that slightly.

>  ])# AC_CHECK_FUNCS
>  
> +m4_define([_AC_CHECK_FUNCS],
> +[AC_CHECK_FUNC([$1],
> +       [AC_DEFINE_UNQUOTED(AS_TR_CPP([HAVE_]$1)) $2],
> +       [$3])
> +])
> +

I tested this with coreutils.  Timing wise, on my system, I was able to
consistently see a reduction of './config.status --recheck' execution
time from around 34.3s pre-patch, to around 33.9s post-patch; a little
better than 1%.  That's not huge, but big enough that I can say it is a
real improvement and not just measurement noise.

Size-wise, this results in about 17k of growth in the size of coreutils'
configure script. There is no longer an ac_func_list (which shaved some
lines up front), but unrolling the loop means you now have a lot of code
additions that look like:

+ac_fn_c_check_func "$LINENO" "btowc" "ac_cv_func_btowc"
+if test "x$ac_cv_func_btowc" = xyes
+then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_BTOWC 1
+_ACEOF
+
+fi
+

(there's that blank line I mentioned earlier)

It makes me wonder if we want a followup patch with some sort of new:

# ac_fn_c_check_func_simple line func cache witness
ac_fn_c_check_func_simple () {
  ac_fn_c_check_func "$1" "$2" "$3"
  if eval test "x\$$3" = xyes; then
    printf "#define $4\n" >>confdefs.h
  fi
}

so that we can compress call current 9-line call sites to a 1-line:

ac_fn_c_check_func_simple "$LINENO" "btowc" "ac_cv_func_btowc" "HAVE_BTWOC"

or maybe it will be easier to maintain via a 2-line approach:

ac_fn_c_check_func "$LINENO" "btowc" "ac_cv_func_btowc"
ac_fn_simple_define "ac_cv_func_btowc" "HAVE_BTOWC"

At any rate, that's food for a later patch (which I'm playing with), so
it shouldn't stop me from committing your patch.

--
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


signature.asc (617 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [PATCH v2 1/3] autoconf: prefer an unrolled loop for trivial AC_CHECK_FUNCS

Paolo Bonzini-2

Il 02/nov/2016 22:27, "Eric Blake" <[hidden email]> ha scritto:
> I tested this with coreutils.  Timing wise, on my system, I was able to
> consistently see a reduction of './config.status --recheck' execution
> time from around 34.3s pre-patch, to around 33.9s post-patch; a little
> better than 1%.  That's not huge, but big enough that I can say it is a
> real improvement and not just measurement noise.

This makes sense, since I got 3% from the while series of three. Your measurements still have the cat(1) fork for AC_DEFINE_UNQUOTED, for example.

Paolo

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [PATCH v2 1/3] autoconf: prefer an unrolled loop for trivial AC_CHECK_FUNCS

Eric Blake-3
In reply to this post by Paolo Bonzini-2
On 10/31/2016 12:08 PM, Paolo Bonzini wrote:

> An unrolled loop avoids the cost of spawning sed in AS_TR_SH and
> AS_TR_CPP.  Prefer it if there is nothing in the second and third
> argument of AC_CHECK_FUNCS and the first argument is a literal.
> Modify AC_CHECK_FUNCS_ONCE to avoid the variable indirection too.
>
> * lib/autoconf/functions.m4 (AC_CHECK_FUNCS): Unroll loop if safe.
> (_AC_CHECK_FUNCS): Move basic implementation here.
> (_AC_CHECK_FUNC_ONCE): Expand AC_CHECK_FUNCS here...
> (_AC_FUNCS_EXPANSION): ... and not here, so remove.
>

>
>  # Check for a single FUNCTION once.
>  m4_define([_AC_CHECK_FUNC_ONCE],
> -[_AH_CHECK_FUNC([$1])AC_DEFUN([_AC_Func_$1],

This one made me do a double-take - you are no longer calling
_AH_CHECK_FUNC(), which can be essential to getting the correct template
into config.h.  But then I realized that in the old code, you were
calling AC_CHECK_FUNC($shell_var), while the new code is calling
AC_CHECK_FUNC(literal); and AC_CHECK_FUNC() also takes care of calling
_AH_CHECK_FUNC (but only for literals).  So removing it is correct.

>  # AC_CHECK_FUNCS_ONCE(FUNCTION...)
>  # --------------------------------
> @@ -107,13 +111,6 @@ _AC_FUNCS_EXPANSION])AC_REQUIRE([_AC_Func_$1])])
>  AC_DEFUN([AC_CHECK_FUNCS_ONCE],
>  [m4_map_args_w([$1], [_AC_CHECK_FUNC_ONCE(], [)])])
>  
> -m4_define([_AC_FUNCS_EXPANSION],
> -[
> -  m4_divert_text([DEFAULTS], [ac_func_list=])
> -  AC_CHECK_FUNCS([$ac_func_list])
> -  m4_define([_AC_FUNCS_EXPANSION], [])
The old code used to check for ALL functions across any
AC_CHECK_FUNC_ONCE() calls in a single loop up front; the new code
scatters the checks into the first place any given func is encountered
in an AC_CHECK_FUNC_ONCE macro.  This is a subtle semantic change, and
the up-front checking is behavior that we documented:

> @defmac AC_CHECK_FUNCS_ONCE (@var{function}@dots{})
> @acindex{CHECK_FUNCS_ONCE}
> @cvindex HAVE_@var{function}
> For each @var{function} enumerated in the blank-or-newline-separated argument
> list, define @code{HAVE_@var{function}} (in all capitals) if it is available.
> This is a once-only variant of @code{AC_CHECK_FUNCS}.  It generates the
> checking code at most once, so that @command{configure} is smaller and
> faster; but the checks cannot be conditionalized and are always done once,
> early during the @command{configure} run.

Our use of AC_REQUIRE hoists the check outside of any AS_IF or similar
code.  However, while I don't think any well-written configure.ac script
will be checking $ac_cv_func_foo prior to calling
AC_CHECK_FUNC_ONCE(foo), I _am_ a bit worried that poorly written
scripts that do:

if condition
  AC_CHECK_FUNC_ONCE(foo)
fi
test $ac_cv_func_foo

instead of

AS_IF([condition], [AC_CHECK_FUNC_ONCE(foo)])
test $ac_cv_func_foo

will now fail when condition fails, because ac_cv_func_foo is no longer
set early and the unrolled version is not encountered, where they used
to succeed regardless of the result of condition.

Potential solution: collect the list of AC_CHECK_FUNC_ONCE functions in
an m4 list, and unroll that list where we used to do the AS_FOR, so that
we aren't changing the semantics of hoisting all the checks up front
early during configure.  I'm playing with the idea now...

--
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


signature.asc (617 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [PATCH v2 1/3] autoconf: prefer an unrolled loop for trivial AC_CHECK_FUNCS

Paolo Bonzini-2


On 02/11/2016 23:14, Eric Blake wrote:

> Our use of AC_REQUIRE hoists the check outside of any AS_IF or similar
> code.  However, while I don't think any well-written configure.ac script
> will be checking $ac_cv_func_foo prior to calling
> AC_CHECK_FUNC_ONCE(foo), I _am_ a bit worried that poorly written
> scripts that do:
>
> if condition
>   AC_CHECK_FUNC_ONCE(foo)
> fi
> test $ac_cv_func_foo

I'm not worried about this.  However, now that I think more about it,
I'm a bit more worried about something that has a deep chain of
AC_REQUIREs, and ultimately ends up expanding AC_CHECK_FUNC_ONCE inside
an "if".

> Potential solution: collect the list of AC_CHECK_FUNC_ONCE functions in
> an m4 list, and unroll that list where we used to do the AS_FOR, so that
> we aren't changing the semantics of hoisting all the checks up front
> early during configure.

How would you do that?  You would have to expand before the first
AC_CHECK_FUNC_ONCE, but you do not have a diversion there (you might
need one per language, in fact).

Perhaps you can put the whole code for the tests in a variable (it's
just a couple lines of shell if you add ac_fn_simple_define) in
INIT_PREPARE or SHELL_FN, and then eval it in _AC_FUNCS_EXPANSION.

That said, what I'm doing now is actually already done by
AC_CHECK_DECLS_ONCE, so we might just document it as a possible
incompatibility.

Paolo

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [PATCH v2 1/3] autoconf: prefer an unrolled loop for trivial AC_CHECK_FUNCS

Eric Blake-3
On 11/02/2016 06:41 PM, Paolo Bonzini wrote:

>
>
> On 02/11/2016 23:14, Eric Blake wrote:
>> Our use of AC_REQUIRE hoists the check outside of any AS_IF or similar
>> code.  However, while I don't think any well-written configure.ac script
>> will be checking $ac_cv_func_foo prior to calling
>> AC_CHECK_FUNC_ONCE(foo), I _am_ a bit worried that poorly written
>> scripts that do:
>>
>> if condition
>>   AC_CHECK_FUNC_ONCE(foo)
>> fi
>> test $ac_cv_func_foo
>
> I'm not worried about this.  However, now that I think more about it,
> I'm a bit more worried about something that has a deep chain of
> AC_REQUIREs, and ultimately ends up expanding AC_CHECK_FUNC_ONCE inside
> an "if".
Hmm. Yeah, I've been thinking over this all afternoon.  The old
_AC_FUNCS_EXPANSION expands once, but at the site of the first
AC_CHECK_FUNC_ONCE() [well, hoisted above AS_IF thanks to AC_REQUIRE],
regardless of what other context might be.

>
>> Potential solution: collect the list of AC_CHECK_FUNC_ONCE functions in
>> an m4 list, and unroll that list where we used to do the AS_FOR, so that
>> we aren't changing the semantics of hoisting all the checks up front
>> early during configure.
>
> How would you do that?  You would have to expand before the first
> AC_CHECK_FUNC_ONCE, but you do not have a diversion there (you might
> need one per language, in fact).

m4_wrap lets us collect the list as we go, then expand code at the end.
But you're right - I have to expand it to some diversion, and creating a
diversion at the place where AC_CHECK_FUNC_ONCE() is first called isn't
likely to be useful.

>
> Perhaps you can put the whole code for the tests in a variable (it's
> just a couple lines of shell if you add ac_fn_simple_define) in
> INIT_PREPARE or SHELL_FN, and then eval it in _AC_FUNCS_EXPANSION.

Or use diversions to craft a function header in SHELL_FN+N, body in
SHELL_FN+N+1, and tail in SHELL_FN+N+2, then have the site where
_AC_FUNCS_EXPANSION does its one-time expansion just call the shell
function.  Each body of the shell function would be a one or two line
check for the next C function being probed.  No need for an eval of a
huge shell string.  Oh, and you're right that N would have to be a
per-language offset.

Or maybe we can take a different approach.  Instead of eval, we can use
the knowledge that my proposal for a one-liner function still ensures
that we have a literal function name, literal cache variable name, and
literal witness name.  Instead of making ac_func_list be a list of
singletons 'func1 func2', it can be a list of triplets 'func1 cv1
witness1 func2 cv2 witness2' where our loop for processing them is no
longer a simple AS_FOR.  [Too bad we don't have python's ability to
easily suck off a tuple at a time from a list, but it can be emulated
easily enough].

>
> That said, what I'm doing now is actually already done by
> AC_CHECK_DECLS_ONCE, so we might just document it as a possible
> incompatibility.

Indeed, that's my fallback approach if I don't come up with an elegant
solution in the next 24 hours.  It's unlikely to affect many real users,
and if it DOES affect someone, it will be a very obscure thing to track
down, but a mention in NEWS (and maybe a slight tweak to the
documentation wording to not promise up-front evaluation) should help if
we end up having to debug a real package that breaks as a result.

--
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


signature.asc (617 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [PATCH v2 1/3] autoconf: prefer an unrolled loop for trivial AC_CHECK_FUNCS

Eric Blake-3
On 11/02/2016 08:28 PM, Eric Blake wrote:

>> How would you do that?  You would have to expand before the first
>> AC_CHECK_FUNC_ONCE, but you do not have a diversion there (you might
>> need one per language, in fact).
>

>   Oh, and you're right that N would have to be a
> per-language offset.

Hmm. As it is, we have a bug if you attempt to use AC_CHECK_FUNCS_ONCE
across multiple languages.  Only the first language actually checks,
because we define only a single one-shot _AC_FUNCS_EXPANSION rather than
one per language.  I'll fix that first, but I guess the fact that no one
has reported it means few people use the macro for anything other than
C, rather than for mixed-language projects.

--
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


signature.asc (617 bytes) Download Attachment
Loading...