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-2012 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=2012-10-07.10; # 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 which 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_find_tool ENVVAR NAMES... 85# ------------------------------ 86# Search for a required program. Use the value of ENVVAR, if set, 87# otherwise find the first of the NAMES that can be run (i.e., 88# supports --version). If found, set ENVVAR to the program name, 89# die otherwise. 90func_find_tool () 91{ 92 $debug_cmd 93 94 _G_find_tool_envvar=$1 95 shift 96 _G_find_tool_names=$@ 97 eval "_G_find_tool_res=\$$_G_find_tool_envvar" 98 if test -n "$_G_find_tool_res"; then 99 _G_find_tool_error_prefix="\$$find_tool_envvar: " 100 else 101 for _G_prog 102 do 103 if func_tool_version_output $_G_prog >/dev/null; then 104 _G_find_tool_res=$_G_prog 105 break 106 fi 107 done 108 fi 109 if test -n "$_G_find_tool_res"; then 110 func_tool_version_output >/dev/null $_G_find_tool_res "\ 111${_G_find_tool_error_prefix}Cannot run '$_G_find_tool_res --version'" 112 113 # Make sure the result is exported to the environment for children 114 # to use. 115 eval "$_G_find_tool_envvar=\$_G_find_tool_res" 116 eval "export $_G_find_tool_envvar" 117 else 118 func_error "\ 119One of these is required: 120 $_G_find_tool_names" 121 fi 122} 123 124 125# func_tool_version_output CMD [FATAL-ERROR-MSG] 126# ---------------------------------------------- 127# Attempt to run 'CMD --version', discarding errors. The output can be 128# ignored by redirecting stdout, and this function used simply to test 129# whether the command exists and exits normally when passed a 130# '--version' argument. 131# When FATAL-ERROR-MSG is given, then this function will display the 132# message and exit if running 'CMD --version' returns a non-zero exit 133# status. 134func_tool_version_output () 135{ 136 $debug_cmd 137 138 _G_cmd=$1 139 _G_fatal_error_msg=$2 140 141 # Some tools, like 'git2cl' produce thousands of lines of output 142 # unless stdin is /dev/null - in that case we want to return 143 # successfully without saving all of that output. Other tools, 144 # such as 'help2man' exit with a non-zero status when stdin comes 145 # from /dev/null, so we re-execute without /dev/null if that 146 # happens. This means that occasionally, the output from both calls 147 # ends up in the result, but the alternative would be to discard the 148 # output from one call, and hope the other produces something useful. 149 { $_G_cmd --version </dev/null || $_G_cmd --version; } 2>/dev/null 150 _G_status=$? 151 152 test 0 -ne "$_G_status" && test -n "$_G_fatal_error_msg" \ 153 && func_fatal_error "$_G_fatal_error_msg" 154 155 (exit $_G_status) 156} 157 158 159## -------------------- ## 160## Resource management. ## 161## -------------------- ## 162 163# This section contains definitions for functions that each ensure a 164# particular resource (a file, or a non-empty configuration variable for 165# example) is available, and if appropriate to extract default values 166# from pertinent package files. Where a variable already has a non- 167# empty value (as set by the package's 'bootstrap.conf'), that value is 168# used in preference to deriving the default. Call them using their 169# associated 'require_*' variable to ensure that they are executed, at 170# most, once. 171# 172# It's entirely deliberate that calling these functions can set 173# variables that don't obey the namespace limitations obeyed by the rest 174# of this file, in order that that they be as useful as possible to 175# callers. 176 177 178# require_configure_ac 179# -------------------- 180# Ensure that there is a 'configure.ac' or 'configure.in' file in the 181# current directory which contains an uncommented call to AC_INIT, and 182# that '$configure_ac' contains its name. 183require_configure_ac=func_require_configure_ac 184func_require_configure_ac () 185{ 186 $debug_cmd 187 188 test -z "$configure_ac" \ 189 && func_autoconf_configure configure.ac && configure_ac=configure.ac 190 test -z "$configure_ac" \ 191 && func_autoconf_configure configure.in && configure_ac=configure.in 192 test -z "$configure_ac" \ 193 || func_verbose "found '$configure_ac'" 194 195 require_configure_ac=: 196} 197 198 199# require_gnu_m4 200# -------------- 201# Search for GNU M4, and export it in $M4. 202require_gnu_m4=func_require_gnu_m4 203func_require_gnu_m4 () 204{ 205 $debug_cmd 206 207 test -n "$M4" || { 208 # Find the first m4 binary that responds to --version. 209 func_find_tool M4 gm4 gnum4 m4 210 } 211 212 test -n "$M4" || func_fatal_error "\ 213Please install GNU M4, or 'export M4=/path/to/gnu/m4'." 214 215 func_verbose "export M4='$M4'" 216 217 # Make sure the search result is visible to subshells 218 export M4 219 220 require_gnu_m4=: 221} 222 223 224## --------------- ## 225## Core functions. ## 226## --------------- ## 227 228# This section contains the high level functions used when calling this 229# file as a script. 'func_extract_trace' is probably the only one that you 230# won't want to replace if you source this file into your own script. 231 232 233# func_extract_trace MACRO_NAMES [FILENAME]... 234# -------------------------------------------- 235# set '$func_extract_trace_result' to a colon delimited list of arguments 236# to any of the comma separated list of MACRO_NAMES in FILENAME. If no 237# FILENAME is given, then '$configure_ac' is assumed. 238func_extract_trace () 239{ 240 $debug_cmd 241 242 $require_configure_ac 243 $require_gnu_m4 244 245 _G_m4_traces=`$bs_echo "--trace=$1" |$SED 's%,% --trace=%g'` 246 _G_re_macros=`$bs_echo "($1)" |$SED 's%,%|%g'` 247 _G_macros="$1"; shift 248 test $# -gt 0 || { 249 set dummy $configure_ac 250 shift 251 } 252 253 # Generate an error if the first file is missing 254 <"$1" 255 256 # Sadly, we can't use 'autom4te' tracing to extract macro arguments, 257 # because it complains about things we want to ignore at bootstrap 258 # time - like missing m4_include files; AC_PREREQ being newer than 259 # the installed autoconf; and returns nothing when tracing 260 # 'AM_INIT_AUTOMAKE' when aclocal hasn't been generated yet. 261 # 262 # The following tries to emulate a less persnickety version of (and 263 # due to not having to wait for Perl startup on every invocation, 264 # it's probably faster too): 265 # 266 # autom4te --language=Autoconf --trace=$my_macro:\$% "$@" 267 # 268 # First we give a minimal set of macro declarations to M4 to prime 269 # it for reading Autoconf macros, while still providing some of the 270 # functionality generally used at m4-time to supply dynamic 271 # arguments to Autocof functions, but without following 272 # 'm4_s?include' files. 273 _G_mini=' 274 # Initialisation. 275 m4_changequote([,]) 276 m4_define([m4_copy], [m4_define([$2], m4_defn([$1]))]) 277 m4_define([m4_rename], [m4_copy([$1], [$2])m4_undefine([$1])]) 278 279 # Disable these macros. 280 m4_undefine([m4_dnl]) 281 m4_undefine([m4_include]) 282 m4_undefine([m4_m4exit]) 283 m4_undefine([m4_m4wrap]) 284 m4_undefine([m4_maketemp]) 285 286 # Copy and rename macros not handled by "m4 --prefix". 287 m4_define([dnl], [m4_builtin([dnl])]) 288 m4_copy([m4_define], [m4_defun]) 289 m4_rename([m4_ifelse], [m4_if]) 290 m4_ifdef([m4_mkstemp], [m4_undefine([m4_mkstemp])]) 291 m4_rename([m4_patsubst], [m4_bpatsubst]) 292 m4_rename([m4_regexp], [m4_bregexp]) 293 294 # "m4sugar.mini" - useful m4-time macros for dynamic arguments. 295 # If we discover packages that need more m4 macros defined in 296 # order to bootstrap correctly, add them here: 297 m4_define([m4_bmatch], 298 [m4_if([$#], 0, [], [$#], 1, [], [$#], 2, [$2], 299 [m4_if(m4_bregexp([$1], [$2]), -1, 300 [$0([$1], m4_shift3($@))], [$3])])]) 301 m4_define([m4_ifndef], [m4_ifdef([$1], [$3], [$2])]) 302 m4_define([m4_ifset], 303 [m4_ifdef([$1], [m4_ifval(m4_defn([$1]), [$2], [$3])], [$3])]) 304 m4_define([m4_require], [$1]) 305 m4_define([m4_shift3], [m4_shift(m4shift(m4shift($@)))]) 306 307 # "autoconf.mini" - things from autoconf macros we care about. 308 m4_copy([m4_defun], [AC_DEFUN]) 309 310 # Dummy definitions for the macros we want to trace. 311 # AM_INIT_AUTOMAKE at least produces no trace without this. 312 ' 313 314 _G_save=$IFS 315 IFS=, 316 for _G_macro in $_G_macros; do 317 IFS=$_G_save 318 func_append _G_mini "AC_DEFUN([$_G_macro])$nl" 319 done 320 IFS=$_G_save 321 322 # We discard M4's stdout, but the M4 trace output from reading our 323 # "autoconf.mini" followed by any other files passed to this 324 # function is then scanned by sed to transform it into a colon 325 # delimited argument list assigned to a shell variable. 326 _G_transform='s|#.*$||; s|^dnl .*$||; s| dnl .*$||;' 327 328 # Unfortunately, alternation in regexp addresses doesn't work in at 329 # least BSD (and hence Mac OS X) sed, so we have to append a capture 330 # and print block for each traced macro to the sed transform script. 331 _G_save=$IFS 332 IFS=, 333 for _G_macro in $_G_macros; do 334 IFS=$_G_save 335 func_append _G_transform ' 336 /^m4trace: -1- '"$_G_macro"'/ { 337 s|^m4trace: -1- '"$_G_macro"'[([]*|| 338 s|], [[]|:|g 339 s|[])]*$|:| 340 s|\(.\):$|\1| 341 p 342 }' 343 done 344 IFS=$_G_save 345 346 # Save the command pipeline results for further use by callers of 347 # this function. 348 func_extract_trace_result=`$bs_echo "$_G_mini" \ 349 |$M4 -daq --prefix $_G_m4_traces - "$@" 2>&1 1>/dev/null \ 350 |$SED -n -e "$_G_transform"` 351} 352 353 354# func_extract_trace_first MACRO_NAMES [FILENAME]... 355# -------------------------------------------------- 356# Exactly like func_extract_trace, except that only the first argument 357# to the first invocation of one of the comma separated MACRO_NAMES is 358# returned in '$func_extract_trace_first_result'. 359func_extract_trace_first () 360{ 361 $debug_cmd 362 363 func_extract_trace ${1+"$@"} 364 func_extract_trace_first_result=`$bs_echo "$func_extract_trace_result" \ 365 |$SED -e 's|:.*$||g' -e 1q` 366} 367 368 369# func_main [ARG]... 370# ------------------ 371func_main () 372{ 373 $debug_cmd 374 375 # Configuration. 376 usage='$progname MACRO_NAME FILE [...]' 377 378 long_help_message=' 379The first argument to this program is the name of an autotools macro 380whose arguments you want to extract by examining the files listed in the 381remaining arguments using the same tool that Autoconf and Automake use, 382GNU M4. 383 384The arguments are returned separated by colons, with each traced call 385on a separate line.' 386 387 # Option processing. 388 func_options "$@" 389 eval set dummy "$func_options_result"; shift 390 391 # Validate remaining non-option arguments. 392 test $# -gt 1 \ 393 || func_fatal_help "not enough arguments" 394 395 # Pass non-option arguments to extraction function. 396 func_extract_trace "$@" 397 398 # Display results. 399 test -n "$func_extract_trace_result" \ 400 && $bs_echo "$func_extract_trace_result" 401 402 # The End. 403 exit $EXIT_SUCCESS 404} 405 406 407## --------------------------- ## 408## Actually perform the trace. ## 409## --------------------------- ## 410 411# Only call 'func_main' if this script was called directly. 412test extract-trace = "$progname" && func_main "$@" 413 414# Local variables: 415# mode: shell-script 416# sh-indentation: 2 417# eval: (add-hook 'write-file-hooks 'time-stamp) 418# time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC" 419# time-stamp-time-zone: "UTC" 420# End: 421