>From c283b8a8e7540b65fd7a7d32fceec6ed42b5b2a7 Mon Sep 17 00:00:00 2001 From: Pavel Raiskup Date: Mon, 5 Oct 2015 13:16:08 +0200 Subject: [PATCH 2/2] libbtool: optimize parse-options calls Its not necessary to re-escape-for-eval in each function in the hook-able function tree -- usually is enough if the leaf function executes func_quote_for_eval() and its caller just re-uses the CALLEE_return value. * gl/build-aux/options-parser (func_run_hooks): Propagate 0 return code down to caller if any $_G_hook succeeded. Don't re-quote the result as that has already been done by the succeeding hook itself. (func_parse_options): Quote only if we changed something and use appropriate return code. (func_validate_options): Likewise. (func_options_prep): Likewise. (func_options_finish): New hook-caller for 'func_options' hooks. (func_options): Propagate return value down to top-level caller, but pay attention we have always set $func_options_result. * build-aux/ltmain.in (libtool_options_prep): Quote only if we changed something and use appropriate return code. (libtool_parse_options): Likewise. * bootstrap: Sync gl/build-aux/with option-parser. --- bootstrap | 128 +++++++++++++++++++++++++++++++++----------- build-aux/ltmain.in | 33 +++++++++--- gl/build-aux/options-parser | 128 +++++++++++++++++++++++++++++++++----------- 3 files changed, 220 insertions(+), 69 deletions(-) diff --git a/bootstrap b/bootstrap index 2649478..c4de711 100755 --- a/bootstrap +++ b/bootstrap @@ -1744,10 +1744,17 @@ func_remove_hook () # than a whitespace-delimited list of legal shell function names, and # no effort is wasted trying to catch shell meta-characters or preserve # whitespace. +# If at least one hook returns 0 (exit success) upon execution, +# func_run_hooks () returns zero too. Otherwise 1 is returned. +# All hooks are expected to correctly return $HOOKNAME_result variable +# upon success exection. The output variable $func_run_hooks_result +# is set to latest (successful) $HOOKNAME_result. func_run_hooks () { $debug_cmd + _G_rc_run_hooks=false + case " $hookable_fns " in *" $1 "*) ;; *) func_fatal_error "'$1' does not support hook funcions.n" ;; @@ -1756,16 +1763,24 @@ func_run_hooks () eval _G_hook_fns=\$$1_hooks; shift for _G_hook in $_G_hook_fns; do - eval $_G_hook '"$@"' + _G_hook_unchanged=${_G_hook}_unchanged + eval $_G_hook_unchanged=false - # store returned options list back into positional - # parameters for next 'cmd' execution. - eval _G_hook_result=\$${_G_hook}_result - eval set dummy "$_G_hook_result"; shift + if eval $_G_hook '"$@"'; then + # store returned options list back into positional + # parameters for next 'cmd' execution. + eval _G_hook_result=\$${_G_hook}_result + eval set dummy "$_G_hook_result"; shift + _G_rc_run_hooks=true + fi done - func_quote_for_eval ${1+"$@"} - func_run_hooks_result=$func_quote_for_eval_result + if $_G_rc_run_hooks; then + # No need to re-quote by func_quoteh + func_run_hooks_result=$_G_hook_result + fi + + $_G_rc_run_hooks } @@ -1839,6 +1854,24 @@ func_run_hooks () # multiple option parsing hooks can be added safely. +# func_options_finish [ARG]... +# ---------------------------- +# All finishing suff required after the option parse loop. This executes +# all 'func_options' hooks. +func_options_finish () +{ + $debug_cmd + + _G_func_options_finish_exit=false + if func_run_hooks func_options ${1+"$@"}; then + func_options_finish_result=$func_run_hooks_result + _G_func_options_finish_exit=: + fi + + $_G_func_options_finish_exit +} + + # func_options [ARG]... # --------------------- # All the functions called inside func_options are hookable. See the @@ -1848,17 +1881,26 @@ func_options () { $debug_cmd - func_options_prep ${1+"$@"} - eval func_parse_options \ - ${func_options_prep_result+"$func_options_prep_result"} - eval func_validate_options \ - ${func_parse_options_result+"$func_parse_options_result"} + _G_rc_options=false - eval func_run_hooks func_options \ - ${func_validate_options_result+"$func_validate_options_result"} + for my_func in options_prep parse_options validate_options options_finish + do + if eval func_$my_func '${1+"$@"}'; then + eval _G_res_var='$'"func_${my_func}_result" + eval set dummy "$_G_res_var" ; shift + _G_rc_options=: + fi + done - # save modified positional parameters for caller - func_options_result=$func_run_hooks_result + if $_G_rc_options; then + func_options_result=$_G_res_var + else + # As a top-level function, we need *always* set the *_result + func_quote_for_eval ${1+"$@"} + func_options_result=$func_quote_for_eval_result + fi + + $_G_rc_options } @@ -1869,7 +1911,9 @@ func_options () # positional parameters. If a hook function modifies that list, and # needs to propogate that back to rest of this script, then the complete # modified list must be put in 'func_run_hooks_result' before -# returning. +# returning and 0 returned. If no changes were done, script might return +# 1 and caller of the hook will not read the 'func_run_hooks_result' +# value. func_hookable func_options_prep func_options_prep () { @@ -1879,10 +1923,14 @@ func_options_prep () opt_verbose=false opt_warning_types= - func_run_hooks func_options_prep ${1+"$@"} + _G_rc_options_prep=false + if func_run_hooks func_options_prep ${1+"$@"}; then + _G_rc_options_prep=: + # save modified positional parameters for caller + func_options_prep_result=$func_run_hooks_result + fi - # save modified positional parameters for caller - func_options_prep_result=$func_run_hooks_result + $_G_rc_options_prep } @@ -1896,18 +1944,21 @@ func_parse_options () func_parse_options_result= + _G_rc_parse_options=false # this just eases exit handling while test $# -gt 0; do # Defer to hook functions for initial option parsing, so they # get priority in the event of reusing an option name. - func_run_hooks func_parse_options ${1+"$@"} - - # Adjust func_parse_options positional parameters to match - eval set dummy "$func_run_hooks_result"; shift + if func_run_hooks func_parse_options ${1+"$@"}; then + # Adjust func_parse_options positional parameters to match + eval set dummy "$func_run_hooks_result"; shift + _G_rc_parse_options=: + fi # Break out of the loop if we already parsed every option. test $# -gt 0 || break + _G_match_parse_options=: _G_opt=$1 shift case $_G_opt in @@ -1977,13 +2028,23 @@ func_parse_options () --) break ;; -*) func_fatal_help "unrecognised option: '$_G_opt'" ;; - *) set dummy "$_G_opt" ${1+"$@"}; shift; break ;; + *) set dummy "$_G_opt" ${1+"$@"} ; shift + _G_match_parse_options=false + break + ;; esac + + $_G_match_parse_options && _G_rc_parse_options=: done - # save modified positional parameters for caller - func_quote_for_eval ${1+"$@"} - func_parse_options_result=$func_quote_for_eval_result + + if $_G_rc_parse_options; then + # save modified positional parameters for caller + func_quote_for_eval ${1+"$@"} + func_parse_options_result=$func_quote_for_eval_result + fi + + $_G_rc_parse_options } @@ -1996,16 +2057,21 @@ func_validate_options () { $debug_cmd + _G_rc_validate_options=false + # Display all warnings if -W was not given. test -n "$opt_warning_types" || opt_warning_types=" $warning_categories" - func_run_hooks func_validate_options ${1+"$@"} + if func_run_hooks func_validate_options ${1+"$@"}; then + # save modified positional parameters for caller + func_validate_options_result=$func_run_hooks_result + _G_rc_validate_options=: + fi # Bail if the options were screwed! $exit_cmd $EXIT_FAILURE - # save modified positional parameters for caller - func_validate_options_result=$func_run_hooks_result + $_G_rc_validate_options } diff --git a/build-aux/ltmain.in b/build-aux/ltmain.in index 24acefd..e57042a 100644 --- a/build-aux/ltmain.in +++ b/build-aux/ltmain.in @@ -358,6 +358,8 @@ libtool_options_prep () nonopt= preserve_args= + _G_rc_libtool_options_prep=: + # Shorthand for --mode=foo, only valid as the first argument case $1 in clean|clea|cle|cl) @@ -381,11 +383,18 @@ libtool_options_prep () uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) shift; set dummy --mode uninstall ${1+"$@"}; shift ;; + *) + _G_rc_libtool_options_prep=false + ;; esac - # Pass back the list of options. - func_quote_for_eval ${1+"$@"} - libtool_options_prep_result=$func_quote_for_eval_result + if $_G_rc_libtool_options_prep; then + # Pass back the list of options. + func_quote_for_eval ${1+"$@"} + libtool_options_prep_result=$func_quote_for_eval_result + fi + + $_G_rc_libtool_options_prep } func_add_hook func_options_prep libtool_options_prep @@ -397,9 +406,12 @@ libtool_parse_options () { $debug_cmd + _G_rc_lt_parse_options=false + # Perform our own loop to consume as many options as possible in # each iteration. while test $# -gt 0; do + _G_match_lt_parse_options=: _G_opt=$1 shift case $_G_opt in @@ -475,14 +487,21 @@ libtool_parse_options () ;; # An option not handled by this hook function: - *) set dummy "$_G_opt" ${1+"$@"}; shift; break ;; + *) set dummy "$_G_opt" ${1+"$@"} ; shift + _G_match_lt_parse_options=false + break + ;; esac + $_G_match_lt_parse_options && _G_rc_lt_parse_options=: done + if $_G_rc_lt_parse_options; then + # save modified positional parameters for caller + func_quote_for_eval ${1+"$@"} + libtool_parse_options_result=$func_quote_for_eval_result + fi - # save modified positional parameters for caller - func_quote_for_eval ${1+"$@"} - libtool_parse_options_result=$func_quote_for_eval_result + $_G_rc_lt_parse_options } func_add_hook func_parse_options libtool_parse_options diff --git a/gl/build-aux/options-parser b/gl/build-aux/options-parser index d651f1d..73db1e3 100644 --- a/gl/build-aux/options-parser +++ b/gl/build-aux/options-parser @@ -157,10 +157,17 @@ func_remove_hook () # than a whitespace-delimited list of legal shell function names, and # no effort is wasted trying to catch shell meta-characters or preserve # whitespace. +# If at least one hook returns 0 (exit success) upon execution, +# func_run_hooks () returns zero too. Otherwise 1 is returned. +# All hooks are expected to correctly return $HOOKNAME_result variable +# upon success exection. The output variable $func_run_hooks_result +# is set to latest (successful) $HOOKNAME_result. func_run_hooks () { $debug_cmd + _G_rc_run_hooks=false + case " $hookable_fns " in *" $1 "*) ;; *) func_fatal_error "'$1' does not support hook funcions.n" ;; @@ -169,16 +176,24 @@ func_run_hooks () eval _G_hook_fns=\$$1_hooks; shift for _G_hook in $_G_hook_fns; do - eval $_G_hook '"$@"' + _G_hook_unchanged=${_G_hook}_unchanged + eval $_G_hook_unchanged=false - # store returned options list back into positional - # parameters for next 'cmd' execution. - eval _G_hook_result=\$${_G_hook}_result - eval set dummy "$_G_hook_result"; shift + if eval $_G_hook '"$@"'; then + # store returned options list back into positional + # parameters for next 'cmd' execution. + eval _G_hook_result=\$${_G_hook}_result + eval set dummy "$_G_hook_result"; shift + _G_rc_run_hooks=true + fi done - func_quote_for_eval ${1+"$@"} - func_run_hooks_result=$func_quote_for_eval_result + if $_G_rc_run_hooks; then + # No need to re-quote by func_quoteh + func_run_hooks_result=$_G_hook_result + fi + + $_G_rc_run_hooks } @@ -252,6 +267,24 @@ func_run_hooks () # multiple option parsing hooks can be added safely. +# func_options_finish [ARG]... +# ---------------------------- +# All finishing suff required after the option parse loop. This executes +# all 'func_options' hooks. +func_options_finish () +{ + $debug_cmd + + _G_func_options_finish_exit=false + if func_run_hooks func_options ${1+"$@"}; then + func_options_finish_result=$func_run_hooks_result + _G_func_options_finish_exit=: + fi + + $_G_func_options_finish_exit +} + + # func_options [ARG]... # --------------------- # All the functions called inside func_options are hookable. See the @@ -261,17 +294,26 @@ func_options () { $debug_cmd - func_options_prep ${1+"$@"} - eval func_parse_options \ - ${func_options_prep_result+"$func_options_prep_result"} - eval func_validate_options \ - ${func_parse_options_result+"$func_parse_options_result"} + _G_rc_options=false - eval func_run_hooks func_options \ - ${func_validate_options_result+"$func_validate_options_result"} + for my_func in options_prep parse_options validate_options options_finish + do + if eval func_$my_func '${1+"$@"}'; then + eval _G_res_var='$'"func_${my_func}_result" + eval set dummy "$_G_res_var" ; shift + _G_rc_options=: + fi + done - # save modified positional parameters for caller - func_options_result=$func_run_hooks_result + if $_G_rc_options; then + func_options_result=$_G_res_var + else + # As a top-level function, we need *always* set the *_result + func_quote_for_eval ${1+"$@"} + func_options_result=$func_quote_for_eval_result + fi + + $_G_rc_options } @@ -282,7 +324,9 @@ func_options () # positional parameters. If a hook function modifies that list, and # needs to propogate that back to rest of this script, then the complete # modified list must be put in 'func_run_hooks_result' before -# returning. +# returning and 0 returned. If no changes were done, script might return +# 1 and caller of the hook will not read the 'func_run_hooks_result' +# value. func_hookable func_options_prep func_options_prep () { @@ -292,10 +336,14 @@ func_options_prep () opt_verbose=false opt_warning_types= - func_run_hooks func_options_prep ${1+"$@"} + _G_rc_options_prep=false + if func_run_hooks func_options_prep ${1+"$@"}; then + _G_rc_options_prep=: + # save modified positional parameters for caller + func_options_prep_result=$func_run_hooks_result + fi - # save modified positional parameters for caller - func_options_prep_result=$func_run_hooks_result + $_G_rc_options_prep } @@ -309,18 +357,21 @@ func_parse_options () func_parse_options_result= + _G_rc_parse_options=false # this just eases exit handling while test $# -gt 0; do # Defer to hook functions for initial option parsing, so they # get priority in the event of reusing an option name. - func_run_hooks func_parse_options ${1+"$@"} - - # Adjust func_parse_options positional parameters to match - eval set dummy "$func_run_hooks_result"; shift + if func_run_hooks func_parse_options ${1+"$@"}; then + # Adjust func_parse_options positional parameters to match + eval set dummy "$func_run_hooks_result"; shift + _G_rc_parse_options=: + fi # Break out of the loop if we already parsed every option. test $# -gt 0 || break + _G_match_parse_options=: _G_opt=$1 shift case $_G_opt in @@ -390,13 +441,23 @@ func_parse_options () --) break ;; -*) func_fatal_help "unrecognised option: '$_G_opt'" ;; - *) set dummy "$_G_opt" ${1+"$@"}; shift; break ;; + *) set dummy "$_G_opt" ${1+"$@"} ; shift + _G_match_parse_options=false + break + ;; esac + + $_G_match_parse_options && _G_rc_parse_options=: done - # save modified positional parameters for caller - func_quote_for_eval ${1+"$@"} - func_parse_options_result=$func_quote_for_eval_result + + if $_G_rc_parse_options; then + # save modified positional parameters for caller + func_quote_for_eval ${1+"$@"} + func_parse_options_result=$func_quote_for_eval_result + fi + + $_G_rc_parse_options } @@ -409,16 +470,21 @@ func_validate_options () { $debug_cmd + _G_rc_validate_options=false + # Display all warnings if -W was not given. test -n "$opt_warning_types" || opt_warning_types=" $warning_categories" - func_run_hooks func_validate_options ${1+"$@"} + if func_run_hooks func_validate_options ${1+"$@"}; then + # save modified positional parameters for caller + func_validate_options_result=$func_run_hooks_result + _G_rc_validate_options=: + fi # Bail if the options were screwed! $exit_cmd $EXIT_FAILURE - # save modified positional parameters for caller - func_validate_options_result=$func_run_hooks_result + $_G_rc_validate_options } -- 2.5.0