Document AS_VAR interfaces.

* doc/autoconf.texi (Programming in M4sh): M4sh is now prime-time.
(Polymorphic Variables): New node.
* NEWS: Update accordingly.

Signed-off-by: Eric Blake <ebb9@byu.net>
This commit is contained in:
Eric Blake 2008-10-17 10:36:18 -06:00
parent c7f3d4ef19
commit c8cfd385c2
3 changed files with 160 additions and 9 deletions

View File

@ -1,5 +1,10 @@
2008-10-17 Eric Blake <ebb9@byu.net>
Document AS_VAR interfaces.
* doc/autoconf.texi (Programming in M4sh): M4sh is now prime-time.
(Polymorphic Variables): New node.
* NEWS: Update accordingly.
Test AS_VAR interfaces.
* tests/m4sh.at (AS@&t@_VAR): New test.
* lib/m4sugar/m4sh.m4 (AS_VAR_PUSHDEF): Force expansion of

8
NEWS
View File

@ -16,13 +16,11 @@ GNU Autoconf NEWS - User visible changes.
m4_default_quoted
** The following documented m4sh macros are new:
AS_LINENO_PREPARE
AS_ME_PREPARE
AS_LINENO_PREPARE AS_ME_PREPARE AS_VAR_COPY
** The following m4sh macros are documented now:
AS_ECHO
AS_ECHO_N
AS_UNSET
AS_ECHO AS_ECHO_N AS_LITERAL_IF AS_UNSET AS_VAR_IF AS_VAR_POPDEF
AS_VAR_PUSHDEF AS_VAR_SET AS_VAR_SET_IF AS_VAR_TEST_SET
AS_VERSION_COMPARE

View File

@ -433,6 +433,7 @@ Programming in M4
Programming in M4sh
* Common Shell Constructs:: Portability layer for common shell constructs
* Polymorphic Variables:: Support for indirect variable names
* Initialization Macros:: Macros to establish a sane shell environment
* File Descriptor Macros:: File descriptor macros for input and output
@ -11797,9 +11798,6 @@ A mess; trouble. [Obs.] --Beau.@: & Fl.
@end enumerate
@end quotation
For the time being, it is not mature enough to be widely used.
M4sh reserves the M4 macro namespace @samp{^_AS_} for internal use, and
the namespace @samp{^AS_} for M4sh macros. It also reserves the shell
and environment variable namespace @samp{^as_}, and the here-doc
@ -11809,6 +11807,7 @@ namespaces.
@menu
* Common Shell Constructs:: Portability layer for common shell constructs
* Polymorphic Variables:: Support for indirect variable names
* Initialization Macros:: Macros to establish a sane shell environment
* File Descriptor Macros:: File descriptor macros for input and output
@end menu
@ -11932,7 +11931,8 @@ optimizing the common cases (@var{dir} or @var{file} is @samp{.},
@defmac AS_UNSET (@var{var})
@asindex{UNSET}
Unsets the shell variable @var{var}, working around bugs in older
shells (@pxref{Limitations of Builtins, , Limitations of Shell Builtins}).
shells (@pxref{Limitations of Builtins, , Limitations of Shell
Builtins}). @var{var} can be a literal or indirect variable name.
@end defmac
@defmac AS_VERSION_COMPARE (@var{version-1}, @var{version-2}, @
@ -11947,6 +11947,154 @@ glibc (@pxref{String/Array Comparison, , String/Array Comparison, libc,
The @acronym{GNU} C Library}).
@end defmac
@node Polymorphic Variables
@section Support for indirect variable names
@cindex variable name indirection
@cindex polymorphic variable name
@cindex indirection, variable name
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. These macros are often followed with @code{dnl},
to avoid excess newlines in the output.
@defmac AS_LITERAL_IF (@var{expression}, @ovar{if-literal}, @ovar{if-not})
@asindex{LITERAL_IF}
If the expansion of @var{expression} is definitely a shell literal,
expand @var{if-literal}. If the expansion of @var{expression} looks
like it might contain shell indirections (such as @code{$var} or
@code{`expr`}), then @var{if-not} is expanded. In order to reduce the
time spent deciding whether an expression is literal, the implementation
is somewhat conservative (for example, @samp{'[$]'} is a single-quoted
shell literal, but causes @var{if-not} to be expanded). While this
macro is often used for recognizing shell variable names, it can also be
used in other contexts.
@example
AC_DEFUN([MY_ACTION],
[AS_LITERAL_IF([$1],
[echo "$1"],
[AS_VAR_COPY([tmp], [$1])
echo "$tmp"])])
@end example
@end defmac
@defmac AS_VAR_COPY (@var{dest}, @var{source})
@asindex{VAR_COPY}
Emit shell code to assign the contents of the polymorphic shell variable
@var{source} to the polymorphic shell variable @var{dest}. For example,
executing this m4sh snippet will output @samp{bar hi}:
@example
foo=bar bar=hi
AS_VAR_COPY([a], [foo])
AS_VAR_COPY([b], [$foo])
echo "$a $b"
@end example
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.
@smallexample
for header in stdint_h inttypes_h ; do
AS_VAR_COPY([var], [ac_cv_header_$header])
echo "$header detected: $var"
done
@end smallexample
@end defmac
@comment AS_VAR_GET is intentionally undocumented; it can't handle
@comment trailing newlines uniformly, and forks too much.
@defmac AS_VAR_IF (@var{var}, @ovar{value}, @ovar{if-equal}, @
@ovar{if-not-equal})
@asindex{VAR_IF}
Output a shell conditional statement. If the contents of the
polymorphic shell variable @var{var} match the string @var{value},
execute @var{if-equal}; otherwise execute @var{if-not-equal}. Avoids
shell bugs if an interrupt signal arrives while a command substitution
in @var{var} is being expanded.
@end defmac
@defmac AS_VAR_PUSHDEF (@var{m4-name}, @var{value})
@defmacx AS_VAR_POPDEF (@var{m4-name})
@asindex{VAR_PUSHDEF}
@asindex{VAR_POPDEF}
@cindex composing variable names
@cindex variable names, composing
A common m4sh idiom involves composing shell variable names from an m4
argument (for example, writing a macro that uses a cache variable).
@var{value} can be an arbitrary string, which will be transliterated
into a valid shell name by @code{AS_TR_SH}. In order to access the
composed variable name based on @var{value}, it is easier to declare a
temporary m4 macro @var{m4-name} with @code{AS_VAR_PUSHDEF}, then use
that macro as the argument to subsequent @code{AS_VAR} macros as a
polymorphic variable name, and finally free the temporary macro with
@code{AS_VAR_POPDEF}.
Here is an involved example, that shows the power of writing macros that
can handle composed shell variable names:
@example
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])
done
@end example
@noindent
In the above example, @code{MY_CHECK_HEADER} can operate on polymorphic
variable names. In the first invocation, the m4 argument is
@code{stdint.h}, which transliterates into a literal @code{stdint_h}.
As a result, the temporary macro @code{my_Header} expands to the literal
shell name @samp{ac_cv_header_stdint_h}. In the second invocation, the
m4 argument to @code{MY_CHECK_HEADER} is @code{$header}, and the
temporary macro @code{my_Header} expands to the indirect shell name
@samp{$as_my_Header}. During the shell execution of the for loop, when
@samp{$header} contains @samp{inttypes.h}, then @samp{$as_my_Header}
contains @samp{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:
@smallexample
header stdint.h detected
header inttypes.h detected
header stdlib.h detected
@end smallexample
@end defmac
@defmac AS_VAR_SET (@var{var}, @ovar{value})
@asindex{VAR_SET}
Emit shell code to assign the contents of the polymorphic shell variable
@var{var} to the shell expansion of @var{value}.
@end defmac
@defmac AS_VAR_SET_IF (@var{var}, @ovar{if-set}, @ovar{if-undef})
@asindex{VAR_SET_IF}
Emit a shell conditional statement, which executes @var{if-set} if the
polymorphic shell variable @code{var} is set to any value, and
@var{if-undef} otherwise.
@end defmac
@defmac AS_VAR_TEST_SET (@var{var})
@asindex{VAR_TEST_SET}
Emit a shell statement that results in a successful exit status only if
the polymorphic shell variable @code{var} is set.
@end defmac
@node Initialization Macros
@section Initialization Macros