Often, it is convenient to write a macro that will emit shell code operating on a shell variable. The simplest case is when the variable name is known. But a more powerful idiom is writing shell code that can work through an indirection, where another variable or command substitution produces the name of the variable to actually manipulate. M4sh supports the notion of polymorphic shell variables, making it easy to write a macro that can deal with either literal or indirect variable names and output shell code appropriate for both use cases. Behavior is undefined if expansion of an indirect variable does not result in a literal variable name.
If the expansion of expression is definitely a shell literal, expand if-literal. If the expansion of expression looks like it might contain shell indirections (such as
$var
or`expr`
), then if-not is expanded. In order to reduce the time spent deciding whether an expression is literal, the implementation is somewhat conservative (for example, ‘'[$]'’ is a single-quoted shell literal, but causes if-not to be expanded). While this macro is often used for recognizing shell variable names, it can also be used in other contexts.AC_DEFUN([MY_ACTION], [AS_LITERAL_IF([$1], [echo "$1"], [AS_VAR_COPY([tmp], [$1]) echo "$tmp"])])
Emit shell code to append the shell expansion of text to the end of the current contents of the polymorphic shell variable var, taking advantage of shells that provide the ‘+=’ extension for more efficient scaling.
For situations where the final contents of var are relatively short (less than 256 bytes), it is more efficient to use the simpler code sequence of var
=${
var}
text (or its polymorphic equivalent ofAS_VAR_COPY([tmp], [
var])
andAS_VAR_SET([
var], ["$tmp"
text])
). But in the case when the script will be repeatedly appending text intovar
, issues of scaling start to become apparent. A naive implementation requires execution time linear to the length of the current contents of var as well as the length of text for a single append, for an overall quadratic scaling with multiple appends. This macro takes advantage of shells which provide the extension var+=
text, which can provide amortized constant time for a single append, for an overall linear scaling with multiple appends. Note that unlikeAS_VAR_SET
, this macro requires that text be quoted properly to avoid field splitting and file name expansion.
Emit shell code to compute the arithmetic expansion of expression, assigning the result as the contents of the polymorphic shell variable var. The code takes advantage of shells that provide ‘$(())’ for fewer forks, but uses expr as a fallback. Therefore, the syntax for a valid expression is rather limited: all operators must occur as separate shell arguments and with proper quoting, there is no portable equality operator, all variables containing numeric values must be expanded prior to the computation, all numeric values must be provided in decimal without leading zeroes, and the first shell argument should not be a negative number. In the following example, this snippet will print ‘(2+3)*4 == 20’.
bar=3 AS_VAR_ARITH([foo], [\( 2 + $bar \) \* 4]) echo "(2+$bar)*4 == $foo"
Emit shell code to assign the contents of the polymorphic shell variable source to the polymorphic shell variable dest. For example, executing this M4sh snippet will output ‘bar hi’:
foo=bar bar=hi AS_VAR_COPY([a], [foo]) AS_VAR_COPY([b], [$foo]) echo "$a $b"When it is necessary to access the contents of an indirect variable inside a shell double-quoted context, the recommended idiom is to first copy the contents into a temporary literal shell variable.
for header in stdint_h inttypes_h ; do AS_VAR_COPY([var], [ac_cv_header_$header]) echo "$header detected: $var" done
Output a shell conditional statement. If the contents of the polymorphic shell variable var match the string value, execute if-equal; otherwise execute if-not-equal. Avoids shell bugs if an interrupt signal arrives while a command substitution in var is being expanded.
A common M4sh idiom involves composing shell variable names from an m4 argument (for example, writing a macro that uses a cache variable). value can be an arbitrary string, which will be transliterated into a valid shell name by
AS_TR_SH
. In order to access the composed variable name based on value, it is easier to declare a temporary m4 macro m4-name withAS_VAR_PUSHDEF
, then use that macro as the argument to subsequentAS_VAR
macros as a polymorphic variable name, and finally free the temporary macro withAS_VAR_POPDEF
. These macros are often followed withdnl
, to avoid excess newlines in the output.Here is an involved example, that shows the power of writing macros that can handle composed shell variable names:
m4_define([MY_CHECK_HEADER], [AS_VAR_PUSHDEF([my_Header], [ac_cv_header_$1])dnl AS_VAR_IF([my_Header], [yes], [echo "header $1 available"])dnl AS_VAR_POPDEF([my_Header])dnl ]) MY_CHECK_HEADER([stdint.h]) for header in inttypes.h stdlib.h ; do MY_CHECK_HEADER([$header]) doneIn the above example,
MY_CHECK_HEADER
can operate on polymorphic variable names. In the first invocation, the m4 argument isstdint.h
, which transliterates into a literalstdint_h
. As a result, the temporary macromy_Header
expands to the literal shell name ‘ac_cv_header_stdint_h’. In the second invocation, the m4 argument toMY_CHECK_HEADER
is$header
, and the temporary macromy_Header
expands to the indirect shell name ‘$as_my_Header’. During the shell execution of the for loop, when ‘$header’ contains ‘inttypes.h’, then ‘$as_my_Header’ contains ‘ac_cv_header_inttypes_h’. If this script is then run on a platform where all three headers have been previously detected, the output of the script will include:header stdint.h detected header inttypes.h detected header stdlib.h detected
Emit shell code to assign the contents of the polymorphic shell variable var to the shell expansion of value. value is not subject to field splitting or file name expansion, so if command substitution is used, it may be done with ‘`""`’ rather than using an intermediate variable (see Shell Substitutions). However, value does undergo rescanning for additional macro names; behavior is unspecified if late expansion results in any shell meta-characters.