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