Re: Conditional AC_CHECK_HEADER

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




> On 6 Feb 2023, at 06:00, Paul Eggert <eggert@xxxxxxxxxxx> wrote:
> 
> On 2023-02-04 09:26, Russ Allbery wrote:
>> The principle that one should always use an AS_* construct if one exists
>> rather than regular shell constructs could probably be documented more
>> aggressively.
> 
> I gave that a shot by installing the attached.
From 84e4582f534d5e1ded05547c54ca518e31604b1e Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@xxxxxxxxxxx>
Date: Sun, 5 Feb 2023 21:48:15 -0800
Subject: [PATCH] doc: improve AS_IF doc

* doc/autoconf.texi: Improve documentation of AS_IF, AS_CASE, etc.
Clarify the advice about when AS_IF is needed, and follow that
advice in examples.
---
 doc/autoconf.texi | 239 ++++++++++++++++++++++++++--------------------
 1 file changed, 137 insertions(+), 102 deletions(-)

diff --git a/doc/autoconf.texi b/doc/autoconf.texi
index cb03b6ca..c92c87e0 100644
--- a/doc/autoconf.texi
+++ b/doc/autoconf.texi
@@ -2352,8 +2352,8 @@ You are encouraged to use literals as @var{tags}.  In particular, you
 should avoid
 
 @example
-@dots{} && my_foos="$my_foos fooo"
-@dots{} && my_foos="$my_foos foooo"
+AS_IF([@dots{}], [my_foos="$my_foos fooo"])
+AS_IF([@dots{}], [my_foos="$my_foos foooo"])
 AC_CONFIG_@var{ITEMS}([$my_foos])
 @end example
 
@@ -2361,8 +2361,8 @@ AC_CONFIG_@var{ITEMS}([$my_foos])
 and use this instead:
 
 @example
-@dots{} && AC_CONFIG_@var{ITEMS}([fooo])
-@dots{} && AC_CONFIG_@var{ITEMS}([foooo])
+AS_IF([@dots{}], [AC_CONFIG_@var{ITEMS}([fooo])])
+AS_IF([@dots{}], [AC_CONFIG_@var{ITEMS}([foooo])])
 @end example
 
 The macros @code{AC_CONFIG_FILES} and @code{AC_CONFIG_HEADERS} use
@@ -3844,20 +3844,22 @@ displaying the options of the package @code{foo}.  Instead, you should
 write:
 
 @example
-if test "x$package_foo_enabled" = xyes; then
-  AC_CONFIG_SUBDIRS([foo])
-fi
+AS_IF([test "x$package_foo_enabled" = xyes],
+  [AC_CONFIG_SUBDIRS([foo])])
 @end example
 
 If a given @var{dir} is not found at @command{configure} run time, a
 warning is reported; if the subdirectory is optional, write:
 
 @example
-if test -d "$srcdir/foo"; then
-  AC_CONFIG_SUBDIRS([foo])
-fi
+AS_IF([test -d "$srcdir/foo"],
+  [AC_CONFIG_SUBDIRS([foo])])
 @end example
 
+These examples use @code{AS_IF} instead of ordinary shell @code{if} to
+avoid problems that Autoconf has with macro calls in shell conditionals
+outside macro definitions.  @xref{Common Shell Constructs}.
+
 If a given @var{dir} contains @command{configure.gnu}, it is run instead
 of @command{configure}.  This is for packages that might use a
 non-Autoconf script @command{Configure}, which can't be called through a
@@ -4384,11 +4386,10 @@ historical Lex:
 
 @example
 AC_PROG_LEX
-if test "x$LEX" != xflex; then
-  LEX="$SHELL $missing_dir/missing flex"
-  AC_SUBST([LEX_OUTPUT_ROOT], [lex.yy])
-  AC_SUBST([LEXLIB], [''])
-fi
+AS_IF([test "x$LEX" != xflex],
+  [LEX="$SHELL $missing_dir/missing flex"
+   AC_SUBST([LEX_OUTPUT_ROOT], [lex.yy])
+   AC_SUBST([LEXLIB], [''])])
 @end example
 
 The shell script @command{missing} can be found in the Automake
@@ -10093,24 +10094,25 @@ AC_MSG_CHECKING([how to get file system type])
 fstype=no
 # The order of these tests is important.
 AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/statvfs.h>
-#include <sys/fstyp.h>]])],
-                  [AC_DEFINE([FSTYPE_STATVFS], [1],
-                     [Define if statvfs exists.])
-                   fstype=SVR4])
-if test $fstype = no; then
-  AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/statfs.h>
-#include <sys/fstyp.h>]])],
-                  [AC_DEFINE([FSTYPE_USG_STATFS], [1],
-                     [Define if USG statfs.])
-                   fstype=SVR3])
-fi
-if test $fstype = no; then
-  AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/statfs.h>
-#include <sys/vmount.h>]])]),
-                  [AC_DEFINE([FSTYPE_AIX_STATFS], [1],
-                     [Define if AIX statfs.])
-                   fstype=AIX])
-fi
+                                     #include <sys/fstyp.h>
+                                   ]])],
+  [AC_DEFINE([FSTYPE_STATVFS], [1],
+     [Define if statvfs exists.])
+   fstype=SVR4])
+AS_IF([test $fstype = no],
+  [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/statfs.h>
+                                        #include <sys/fstyp.h>
+                                      ]])],
+     [AC_DEFINE([FSTYPE_USG_STATFS], [1],
+        [Define if USG statfs.])
+      fstype=SVR3])])
+AS_IF([test $fstype = no],
+  [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/statfs.h>
+                                        #include <sys/vmount.h>
+                                      ]])],
+     [AC_DEFINE([FSTYPE_AIX_STATFS], [1],
+        [Define if AIX statfs.])
+      fstype=AIX])])
 # (more cases omitted here)
 AC_MSG_RESULT([$fstype])
 @end group
@@ -10151,12 +10153,13 @@ already defined a certain C preprocessor symbol, test the value of the
 appropriate cache variable, as in this example:
 
 @example
-AC_CHECK_FUNC([vprintf], [AC_DEFINE([HAVE_VPRINTF], [1],
-                          [Define if vprintf exists.])])
-if test "x$ac_cv_func_vprintf" != xyes; then
-  AC_CHECK_FUNC([_doprnt], [AC_DEFINE([HAVE_DOPRNT], [1],
-                            [Define if _doprnt exists.])])
-fi
+AC_CHECK_FUNC([vprintf],
+  [AC_DEFINE([HAVE_VPRINTF], [1],
+     [Define if vprintf exists.])])
+AS_IF([test "x$ac_cv_func_vprintf" != xyes],
+  [AC_CHECK_FUNC([_doprnt],
+     [AC_DEFINE([HAVE_DOPRNT], [1],
+        [Define if _doprnt exists.])])])
 @end example
 
 If @code{AC_CONFIG_HEADERS} has been called, then instead of creating
@@ -11351,7 +11354,8 @@ expansion of @code{my_case} results in expanding @code{AS_IF} with a
 truncated parameter, and the expansion is syntactically invalid:
 
 @example
-if :; then
+if :
+then :
   case $file_name in
   *.c
 fi echo "C source code";;
@@ -15002,7 +15006,6 @@ test "$body_temperature_in_Celsius" -gt 38 &&
   dance_floor=occupied
 test "x$hair_style" = xcurly &&
   dance_floor=occupied
-fi
 if test "x`date +%A`" = xSaturday; then
 
 
@@ -15802,20 +15805,19 @@ a single statement contains many here-documents.  For instance if your
 
 @example
 @group
-if <cross_compiling>; then
-  assume this and that
-else
-  check this
-  check that
-  check something else
-  @dots{}
-  on and on forever
-  @dots{}
-fi
+AS_IF([<cross_compiling>],
+  [assume this and that],
+  [check this
+   check that
+   check something else
+   @dots{}
+   on and on forever
+   @dots{}])
 @end group
 @end example
 
-A shell parses the whole @code{if}/@code{fi} construct, creating
+A shell parses the whole @code{if}/@code{fi} construct generated by
+@code{AS_IF}, creating
 temporary files for each here-document in it.  Some shells create links
 for such here-documents on every @code{fork}, so that the clean-up code
 they had installed correctly removes them.  It is creating the links
@@ -17754,6 +17756,7 @@ $ @kbd{zsh -c '. ./syntax; echo $?'}
 0
 @end example
 
+@anchor{!}
 @item @command{!}
 @c --------------
 @prindex @command{!}
@@ -17792,12 +17795,50 @@ cmp file1 file2 >/dev/null 2>&1 ||
   echo files differ or trouble
 @end example
 
+In M4sh, the @code{AS_IF} macro provides an easy way to write these kinds
+of conditionals:
+
+@example
+AS_IF([cmp -s file file.new], [],
+  [echo files differ or trouble])
+@end example
+
+This kind of rewriting is needed in code outside macro definitions that
+calls other macros.  @xref{Common Shell Constructs}.  It is also useful
+inside macro definitions, where the @dfn{then} and @dfn{else} branches
+might contain macro arguments.
+
 More generally, one can always rewrite @samp{! @var{command}} as:
 
 @example
-if @var{command}; then (exit 1); else :; fi
+AS_IF([@var{command}], [(exit 1)])
+@end example
+
+@item @command{&&} and @command{||}
+@c --------------------------------
+@prindex @command{&&}
+@prindex @command{||}
+If an AND-OR list is not inside @code{AC_DEFUN}, and it contains
+calls to Autoconf macros, it should be rewritten using @code{AS_IF}.
+@xref{Common Shell Constructs}.  The operators @code{&&} and @code{||}
+have equal precedence and are left associative, so instead of:
+
+@example
+# This is dangerous outside AC_DEFUN.
+cmp a b >/dev/null 2>&1 &&
+  AS_ECHO([files are same]) >$tmpfile ||
+    AC_MSG_NOTICE([files differ, or echo failed])
 @end example
 
+you can use:
+
+@example
+# This is OK outside AC_DEFUN.
+AS_IF([AS_IF([cmp a b >/dev/null 2>&1],
+         [AS_ECHO([files are same]) >$tmpfile],
+         [false])],
+  [AC_MSG_NOTICE([files differ, or echo failed])])
+@end example
 
 @item @command{@{...@}}
 @c --------------------
@@ -17851,6 +17892,26 @@ The use of @samp{break 2} etc.@: is safe.
 @item @command{case}
 @c -----------------
 @prindex @command{case}
+If a @code{case} command is not inside @code{AC_DEFUN}, and it contains
+calls to Autoconf macros, it should be rewritten using @code{AS_CASE}.
+@xref{Common Shell Constructs}.  Instead of:
+
+@example
+# This is dangerous outside AC_DEFUN.
+case $filename in
+  *.[ch]) AC_MSG_NOTICE([C source file])
+esac
+@end example
+
+@noindent
+use:
+
+@example
+# This is OK outside AC_DEFUN.
+AS_CASE([$filename],
+  [[*.[ch]]], [AC_MSG_NOTICE([C source file])])
+@end example
+
 You don't need to quote the argument; no splitting is performed.
 
 You don't need the final @samp{;;}, but you should use it.
@@ -18357,34 +18418,11 @@ c=d
 @item @command{if}
 @c ---------------
 @prindex @command{if}
-Using @samp{!} is not portable.  Instead of:
-
-@example
-if ! cmp -s file file.new; then
-  mv file.new file
-fi
-@end example
+If an @code{if} command is not inside @code{AC_DEFUN}, and it contains
+calls to Autoconf macros, it should be rewritten using @code{AS_IF}.
+@xref{Common Shell Constructs}.
 
-@noindent
-use:
-
-@example
-if cmp -s file file.new; then :; else
-  mv file.new file
-fi
-@end example
-
-@noindent
-Or, especially if the @dfn{else} branch is short, you can use @code{||}.
-In M4sh, the @code{AS_IF} macro provides an easy way to write these kinds
-of conditionals:
-
-@example
-AS_IF([cmp -s file file.new], [], [mv file.new file])
-@end example
-
-This is especially useful in other M4 macros, where the @dfn{then} and
-@dfn{else} branches might be macro arguments.
+Using @code{if ! @dots{}} is not portable.  @xref{!,,@command{!} notes}.
 
 Some very old shells did not reset the exit status from an @command{if}
 with no @command{else}:
@@ -18395,9 +18433,9 @@ $ @kbd{if (exit 42); then true; fi; echo $?}
 @end example
 
 @noindent
-whereas a proper shell should have printed @samp{0}.  But this is no
-longer a portability problem; any shell that supports functions gets it
-correct.  However, it explains why some makefiles have lengthy
+whereas a proper shell should have printed @samp{0}.  Although this is no
+longer a portability problem, as any shell that supports functions gets it
+correct, it explains why some makefiles have lengthy
 constructs:
 
 @example
@@ -18628,8 +18666,8 @@ $ @kbd{sh -c 'set -e; trap '\''echo $?'\'' 0; false'}
 
 @noindent
 Thus, when writing a script in M4sh, rather than trying to rely on
-@samp{set -e}, it is better to append @samp{|| AS_EXIT} to any
-statement where it is desirable to abort on failure.
+@samp{set -e}, it is better to use @samp{AS_EXIT}
+where it is desirable to abort on failure.
 
 @cindex @command{set -b}
 @cindex @command{set -m}
@@ -18812,9 +18850,8 @@ to take an action when a token matches a given pattern.  Such constructs
 should be avoided by using:
 
 @example
-case $ac_feature in
-  *[!-a-zA-Z0-9_]*) @var{action};;
-esac
+AS_CASE([$ac_feature],
+  [[*[!-a-zA-Z0-9_]*]], [@var{action}])
 @end example
 
 If the pattern is a complicated regular expression that cannot be
@@ -22517,8 +22554,7 @@ program or library.
 AS_CASE([$host],
   [alpha*-*-*], [CYCLE_OBJ=rpcc.o],
   [i?86-*-*],   [CYCLE_OBJ=rdtsc.o],
-  [CYCLE_OBJ=""]
-)
+  [CYCLE_OBJ=""])
 AC_SUBST([CYCLE_OBJ])
 @end example
 
@@ -22528,11 +22564,10 @@ CPUs.  The configured CPU type doesn't always indicate exact CPU types,
 so some runtime capability checks may be necessary too.
 
 @example
-case $host in
-  alpha*-*-*)   AC_CONFIG_LINKS([dither.c:alpha/dither.c]) ;;
-  powerpc*-*-*) AC_CONFIG_LINKS([dither.c:powerpc/dither.c]) ;;
-  *-*-*)        AC_CONFIG_LINKS([dither.c:generic/dither.c]) ;;
-esac
+AS_CASE([$host],
+  [alpha*-*-*],   [AC_CONFIG_LINKS([dither.c:alpha/dither.c])],
+  [powerpc*-*-*], [AC_CONFIG_LINKS([dither.c:powerpc/dither.c])],
+  [AC_CONFIG_LINKS([dither.c:generic/dither.c])])
 @end example
 
 The host system type can also be used to find cross-compilation tools
@@ -24902,13 +24937,13 @@ Here is a way to write it for version 2:
 
 @example
 AC_CHECK_FUNCS([syslog])
-if test "x$ac_cv_func_syslog" = xno; then
-  # syslog is not in the default libraries.  See if it's in some other.
-  for lib in bsd socket inet; do
-    AC_CHECK_LIB([$lib], [syslog], [AC_DEFINE([HAVE_SYSLOG])
-      LIBS="-l$lib $LIBS"; break])
-  done
-fi
+AS_IF([test "x$ac_cv_func_syslog" = xno],
+  [# syslog is not in the default libraries.  See if it's in some other.
+   for lib in bsd socket inet; do
+     AC_CHECK_LIB([$lib], [syslog],
+       [AC_DEFINE([HAVE_SYSLOG])
+        LIBS="-l$lib $LIBS"; break])
+   done])
 @end example
 
 If you were working around bugs in @code{AC_DEFINE_UNQUOTED} by adding
-- 
2.37.2

Thanks, this is helpful. We've had no end of bugs caused by the wrong primitives
being used.

Attachment: signature.asc
Description: Message signed with OpenPGP


[Index of Archives]     [GCC Help]     [Kernel Discussion]     [RPM Discussion]     [Red Hat Development]     [Yosemite News]     [Linux USB]     [Samba]

  Powered by Linux