1#! /bin/sh 2 3# Extract macro arguments from autotools input with GNU M4. 4# Written by Gary V. Vaughan, 2010 5# 6# This is free software. There is NO warranty; not even for 7# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 8# 9# Copyright (C) 2010-2019 Bootstrap Authors 10# 11# This file is dual licensed under the terms of the MIT license 12# <https://opensource.org/license/MIT>, and GPL version 3 or later 13# <http://www.gnu.org/licenses/gpl-2.0.html>. You must apply one of 14# these licenses when using or redistributing this software or any of 15# the files within it. See the URLs above, or the file `LICENSE` 16# included in the Bootstrap distribution for the full license texts. 17 18# Please report bugs or propose patches to: 19# <https://github.com/gnulib-modules/bootstrap/issues> 20 21# Make sure we've evaluated scripts we depend on. 22test -z "$progpath" && . `echo "$0" |${SED-sed} 's|[^/]*$||'`/funclib.sh 23test extract-trace = "$progname" && . `echo "$0" |${SED-sed} 's|[^/]*$||'`/options-parser 24 25# Set a version string. 26scriptversion=2019-02-19.15; # UTC 27 28 29## ------ ## 30## Usage. ## 31## ------ ## 32 33# Run './extract-trace --help' for help with using this script from the 34# command line. 35# 36# Or source first 'options-parser' and then this file into your own 37# scripts in order to make use of the function and variable framework 38# they define, and also to avoid the overhead of forking to run this 39# script in its own process on every call. 40 41 42 43## ----------------- ## 44## Helper functions. ## 45## ----------------- ## 46 47# This section contains the helper functions used by the rest of 48# 'extract-trace'. 49 50 51# func_autoconf_configure MAYBE-CONFIGURE-FILE 52# -------------------------------------------- 53# Ensure that MAYBE-CONFIGURE-FILE is the name of a file in the current 54# directory that contains an uncommented call to AC_INIT. 55func_autoconf_configure () 56{ 57 $debug_cmd 58 59 _G_sed_no_comment=' 60 s|#.*$|| 61 s|^dnl .*$|| 62 s| dnl .*$||' 63 _G_ac_init= 64 65 # If we were passed a genuine file, make sure it calls AC_INIT. 66 test -f "$1" \ 67 && _G_ac_init=`$SED "$_G_sed_no_comment" "$1" |$GREP AC_INIT` 68 69 # Otherwise it is not a genuine Autoconf input file. 70 test -n "$_G_ac_init" 71 _G_status=$? 72 73 test 0 -ne "$_G_status" \ 74 && func_verbose "'$1' not using Autoconf" 75 76 (exit $_G_status) 77} 78 79 80# func_tool_version_output CMD [FATAL-ERROR-MSG] 81# ---------------------------------------------- 82# Attempt to run 'CMD --version', discarding errors. The output can be 83# ignored by redirecting stdout, and this function used simply to test 84# whether the command exists and exits normally when passed a 85# '--version' argument. 86# When FATAL-ERROR-MSG is given, then this function will display the 87# message and exit if running 'CMD --version' returns a non-zero exit 88# status. 89func_tool_version_output () 90{ 91 $debug_cmd 92 93 _G_cmd=$1 94 _G_fatal_error_msg=$2 95 96 # Some tools, like 'git2cl' produce thousands of lines of output 97 # unless stdin is /dev/null - in that case we want to return 98 # successfully without saving all of that output. Other tools, 99 # such as 'help2man' exit with a non-zero status when stdin comes 100 # from /dev/null, so we re-execute without /dev/null if that 101 # happens. This means that occasionally, the output from both calls 102 # ends up in the result, but the alternative would be to discard the 103 # output from one call, and hope the other produces something useful. 104 { $_G_cmd --version </dev/null || $_G_cmd --version; } 2>/dev/null 105 _G_status=$? 106 107 test 0 -ne "$_G_status" && test -n "$_G_fatal_error_msg" \ 108 && func_fatal_error "$_G_fatal_error_msg" 109 110 (exit $_G_status) 111} 112 113 114# func_tool_version_number CMD [FATAL-ERROR-MSG] 115# ---------------------------------------------- 116# Pass arguments to func_tool_version_output, but set 117# $func_tool_version_number_result to the last dot delimited digit string 118# on the first line of output. 119func_tool_version_number () 120{ 121 $debug_cmd 122 123 _G_verout=`func_tool_version_output "$@"` 124 _G_status=$? 125 126 # A version number starts with a digit following a space on the first 127 # line of output from `--version`. 128 _G_verout=`echo "$_G_verout" |sed 1q` 129 if test -n "$_G_verout"; then 130 _G_vernum=`expr "$_G_verout" : '.* \([0-9][^ ]*\)'` 131 fi 132 133 if test -n "$_G_vernum"; then 134 printf '%s\n' "$_G_vernum" 135 else 136 printf '%s\n' "$_G_verout" 137 fi 138 139 (exit $_G_status) 140} 141 142 143# func_find_tool ENVVAR NAMES... 144# ------------------------------ 145# Search for a required program. Use the value of ENVVAR, if set, 146# otherwise find the first of the NAMES that can be run (i.e., 147# supports --version). If found, set ENVVAR to the program name, 148# die otherwise. 149func_find_tool () 150{ 151 $debug_cmd 152 153 _G_find_tool_envvar=$1 154 shift 155 _G_find_tool_names=$@ 156 eval "_G_find_tool_res=\$$_G_find_tool_envvar" 157 if test -n "$_G_find_tool_res"; then 158 _G_find_tool_error_prefix="\$$find_tool_envvar: " 159 else 160 _G_find_tool_res= 161 _G_bestver= 162 for _G_prog 163 do 164 _G_find_tool_save_IFS=$IFS 165 IFS=${PATH_SEPARATOR-:} 166 for _G_dir in $PATH; do 167 IFS=$_G_find_tool_save_IFS 168 _G_progpath=$_G_dir/$_G_prog 169 test -r "$_G_progpath" && { 170 _G_curver=`func_tool_version_number $_G_progpath` 171 case $_G_bestver,$_G_curver in 172 ,) 173 # first non--version responsive prog sticks! 174 test -n "$_G_progpath" || _G_find_tool_res=$_G_progpath 175 ;; 176 ,*) 177 # first --version responsive prog beats non--version responsive! 178 _G_find_tool_res=$_G_progpath 179 _G_bestver=$_G_curver 180 ;; 181 *,*) 182 # another --version responsive prog must be newer to beat previous one! 183 test "x$_G_curver" = "x$_G_bestver" \ 184 || func_lt_ver "$_G_curver" "$_G_bestver" \ 185 || { 186 _G_find_tool_res=$_G_progpath 187 _G_bestver=$_G_curver 188 } 189 ;; 190 esac 191 } 192 done 193 IFS=$_G_find_tool_save_IFS 194 done 195 fi 196 if test -n "$_G_find_tool_res"; then 197 func_tool_version_number >/dev/null $_G_find_tool_res "\ 198${_G_find_tool_error_prefix}Cannot run '$_G_find_tool_res --version'" 199 200 # Make sure the result is exported to the environment for children 201 # to use. 202 eval "$_G_find_tool_envvar=\$_G_find_tool_res" 203 eval "export $_G_find_tool_envvar" 204 else 205 func_error "\ 206One of these is required: 207 $_G_find_tool_names" 208 fi 209} 210 211 212 213## -------------------- ## 214## Resource management. ## 215## -------------------- ## 216 217# This section contains definitions for functions that each ensure a 218# particular resource (a file, or a non-empty configuration variable for 219# example) is available, and if appropriate to extract default values 220# from pertinent package files. Where a variable already has a non- 221# empty value (as set by the package's 'bootstrap.conf'), that value is 222# used in preference to deriving the default. Call them using their 223# associated 'require_*' variable to ensure that they are executed, at 224# most, once. 225# 226# It's entirely deliberate that calling these functions can set 227# variables that don't obey the namespace limitations obeyed by the rest 228# of this file, in order that that they be as useful as possible to 229# callers. 230 231 232# require_configure_ac 233# -------------------- 234# Ensure that there is a 'configure.ac' or 'configure.in' file in the 235# current directory that contains an uncommented call to AC_INIT, and 236# that '$configure_ac' contains its name. 237require_configure_ac=func_require_configure_ac 238func_require_configure_ac () 239{ 240 $debug_cmd 241 242 test -z "$configure_ac" \ 243 && func_autoconf_configure configure.ac && configure_ac=configure.ac 244 test -z "$configure_ac" \ 245 && func_autoconf_configure configure.in && configure_ac=configure.in 246 test -z "$configure_ac" \ 247 || func_verbose "found '$configure_ac'" 248 249 require_configure_ac=: 250} 251 252 253# require_gnu_m4 254# -------------- 255# Search for GNU M4, and export it in $M4. 256require_gnu_m4=func_require_gnu_m4 257func_require_gnu_m4 () 258{ 259 $debug_cmd 260 261 test -n "$M4" || { 262 # Find the first m4 binary that responds to --version. 263 func_find_tool M4 gm4 gnum4 m4 264 } 265 266 test -n "$M4" || func_fatal_error "\ 267Please install GNU M4, or 'export M4=/path/to/gnu/m4'." 268 269 func_verbose "export M4='$M4'" 270 271 # Make sure the search result is visible to subshells 272 export M4 273 274 require_gnu_m4=: 275} 276 277 278## --------------- ## 279## Core functions. ## 280## --------------- ## 281 282# This section contains the high level functions used when calling this 283# file as a script. 'func_extract_trace' is probably the only one that you 284# won't want to replace if you source this file into your own script. 285 286 287# func_extract_trace MACRO_NAMES [FILENAME]... 288# -------------------------------------------- 289# set '$func_extract_trace_result' to a colon delimited list of arguments 290# to any of the comma separated list of MACRO_NAMES in FILENAME. If no 291# FILENAME is given, then '$configure_ac' is assumed. 292func_extract_trace () 293{ 294 $debug_cmd 295 296 $require_configure_ac 297 $require_gnu_m4 298 299 _G_m4_traces=`$ECHO "--trace=$1" |$SED 's%,% --trace=%g'` 300 _G_re_macros=`$ECHO "($1)" |$SED 's%,%|%g'` 301 _G_macros="$1"; shift 302 test $# -gt 0 || { 303 set dummy $configure_ac 304 shift 305 } 306 307 # Generate an error if the first file is missing 308 <"$1" 309 310 # Sadly, we can't use 'autom4te' tracing to extract macro arguments, 311 # because it complains about things we want to ignore at bootstrap 312 # time - like missing m4_include files; AC_PREREQ being newer than 313 # the installed autoconf; and returns nothing when tracing 314 # 'AM_INIT_AUTOMAKE' when aclocal hasn't been generated yet. 315 # 316 # The following tries to emulate a less persnickety version of (and 317 # due to not having to wait for Perl startup on every invocation, 318 # it's probably faster too): 319 # 320 # autom4te --language=Autoconf --trace=$my_macro:\$% "$@" 321 # 322 # First we give a minimal set of macro declarations to M4 to prime 323 # it for reading Autoconf macros, while still providing some of the 324 # functionality generally used at m4-time to supply dynamic 325 # arguments to Autocof functions, but without following 326 # 'm4_s?include' files. 327 _G_mini=' 328 dnl Initialisation. 329 m4_changequote([,]) 330 m4_define([m4_copy], [m4_define([$2], m4_defn([$1]))]) 331 m4_define([m4_rename], [m4_copy([$1], [$2])m4_undefine([$1])]) 332 333 dnl Replace macros which may abort m4 with a no-op variant. 334 m4_pushdef([m4_assert]) 335 m4_pushdef([m4_exit]) 336 m4_pushdef([m4_fatal]) 337 m4_pushdef([m4_m4exit]) 338 339 dnl Replace macros that might break stderr of m4. 340 m4_pushdef([m4_errprint]) 341 m4_pushdef([m4_errprintn]) 342 m4_pushdef([m4_include]) 343 m4_pushdef([m4_warn]) 344 345 dnl Avoid side-effects of tracing by extract-trace. 346 m4_pushdef([m4_maketemp]) 347 m4_pushdef([m4_mkstemp]) 348 349 dnl TODO: reasons for this 350 m4_pushdef([m4_dnl]) 351 m4_pushdef([m4_m4wrap]) 352 353 dnl Copy and rename macros not handled by "m4 --prefix". 354 m4_define([dnl], [m4_builtin([dnl])]) 355 m4_copy([m4_define], [m4_defun]) 356 m4_rename([m4_ifelse], [m4_if]) 357 m4_rename([m4_patsubst], [m4_bpatsubst]) 358 m4_rename([m4_regexp], [m4_bregexp]) 359 360 dnl "m4sugar.mini" - useful m4-time macros for dynamic arguments. 361 dnl If we discover packages that need more m4 macros defined in 362 dnl order to bootstrap correctly, add them here: 363 m4_define([m4_bmatch], 364 [m4_if([$#], 0, [], [$#], 1, [], [$#], 2, [$2], 365 [m4_if(m4_bregexp([$1], [$2]), -1, 366 [$0([$1], m4_shift3($@))], [$3])])]) 367 m4_define([m4_ifndef], [m4_ifdef([$1], [$3], [$2])]) 368 m4_define([m4_ifset], 369 [m4_ifdef([$1], [m4_ifval(m4_defn([$1]), [$2], [$3])], [$3])]) 370 m4_define([m4_require], [$1]) 371 m4_define([m4_shift3], [m4_shift(m4shift(m4shift($@)))]) 372 373 dnl "autoconf.mini" - things from autoconf macros we care about. 374 m4_copy([m4_defun], [AC_DEFUN]) 375 376 dnl Dummy definitions for the macros we want to trace. 377 dnl AM_INIT_AUTOMAKE at least produces no trace without this. 378 ' 379 380 _G_save=$IFS 381 IFS=, 382 for _G_macro in $_G_macros; do 383 IFS=$_G_save 384 func_append _G_mini "AC_DEFUN([$_G_macro])$nl" 385 done 386 IFS=$_G_save 387 388 # We discard M4's stdout, but the M4 trace output from reading our 389 # "autoconf.mini" followed by any other files passed to this 390 # function is then scanned by sed to transform it into a colon 391 # delimited argument list assigned to a shell variable. 392 _G_transform='s|#.*$||; s|^dnl .*$||; s| dnl .*$||;' 393 394 # Unfortunately, alternation in regexp addresses doesn't work in at 395 # least BSD (and hence Mac OS X) sed, so we have to append a capture 396 # and print block for each traced macro to the sed transform script. 397 _G_save=$IFS 398 IFS=, 399 for _G_macro in $_G_macros; do 400 IFS=$_G_save 401 func_append _G_transform ' 402 /^m4trace: -1- '"$_G_macro"'/ { 403 s|^m4trace: -1- '"$_G_macro"'[([]*|| 404 s|], [[]|:|g 405 s|[])]*$|:| 406 s|\(.\):$|\1| 407 p 408 }' 409 done 410 IFS=$_G_save 411 412 # Save the command pipeline results for further use by callers of 413 # this function. 414 func_extract_trace_result=`$ECHO "$_G_mini" \ 415 |$M4 -daq --prefix $_G_m4_traces - "$@" 2>&1 1>/dev/null \ 416 |$SED -n -e "$_G_transform"` 417} 418 419 420# func_extract_trace_first MACRO_NAMES [FILENAME]... 421# -------------------------------------------------- 422# Exactly like func_extract_trace, except that only the first argument 423# to the first invocation of one of the comma separated MACRO_NAMES is 424# returned in '$func_extract_trace_first_result'. 425func_extract_trace_first () 426{ 427 $debug_cmd 428 429 func_extract_trace ${1+"$@"} 430 func_extract_trace_first_result=`$ECHO "$func_extract_trace_result" \ 431 |$SED -e 's|:.*$||g' -e 1q` 432} 433 434 435# func_main [ARG]... 436# ------------------ 437func_main () 438{ 439 $debug_cmd 440 441 # Configuration. 442 usage='$progname MACRO_NAME FILE [...]' 443 444 long_help_message=' 445The first argument to this program is the name of an autotools macro 446whose arguments you want to extract by examining the files listed in the 447remaining arguments using the same tool that Autoconf and Automake use, 448GNU M4. 449 450The arguments are returned separated by colons, with each traced call 451on a separate line.' 452 453 # Option processing. 454 func_options "$@" 455 eval set dummy "$func_options_result"; shift 456 457 # Validate remaining non-option arguments. 458 test $# -gt 1 \ 459 || func_fatal_help "not enough arguments" 460 461 # Pass non-option arguments to extraction function. 462 func_extract_trace "$@" 463 464 # Display results. 465 test -n "$func_extract_trace_result" \ 466 && $ECHO "$func_extract_trace_result" 467 468 # The End. 469 exit $EXIT_SUCCESS 470} 471 472 473## --------------------------- ## 474## Actually perform the trace. ## 475## --------------------------- ## 476 477# Only call 'func_main' if this script was called directly. 478test extract-trace = "$progname" && func_main "$@" 479 480# Local variables: 481# mode: shell-script 482# sh-indentation: 2 483# eval: (add-hook 'before-save-hook 'time-stamp) 484# time-stamp-pattern: "50/scriptversion=%:y-%02m-%02d.%02H; # UTC" 485# time-stamp-time-zone: "UTC" 486# End: 487