autoconf-patches
[Top][All Lists]
Advanced

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

Re: proposed gnulib-related additions to Autoconf


From: Ralf Wildenhues
Subject: Re: proposed gnulib-related additions to Autoconf
Date: Sat, 1 Apr 2006 13:19:00 +0200
User-agent: Mutt/1.5.9i

Hi Paul,

Here is a preliminary version of the proposed rewrite; I'll try to
finish it tomorrow, unless beaten to.

* Ralf Wildenhues wrote on Fri, Mar 31, 2006 at 09:31:38AM CEST:
> * Paul Eggert wrote on Fri, Mar 31, 2006 at 09:10:25AM CEST:
> > Ralf Wildenhues <address@hidden> writes:
> > >
> > > That thing should not be called foo.
> > 
> > OK, I'll change it to ac_$3.
> 
> That's fine.

After refactoring the macro did not need $3 aka MAX-VARIABLE except for
this, so I decided to change this to ac__var_ again.

Notes:

First, there is still a bug in both your version and mine, AFAICS: if
you pass a MIN-VARIABLE for an unsigned entity, and that variable is not
yet defined, it computes the wrong result.

Eric mentioned the desire for a macro to compute all of stdint.
So I decided it was worthwhile to have one that does not expand to
megabytes of redundant code, even if it was very slow.  Thus the
version below allows shell variables as arguments.  All that is
still missing is factoring out the autoheader related stuff (since
autoheader needs m4 literals for tracing) and a corresponding
AC_C_TYPE_RANGE_INTEGERS which works on lists, all quite similar to
AC_CHECK_HEADERS.  (Probably it'd be good to have a wrapper for the
public version of AC_C_TYPE_RANGE_INTEGER that m4_fatals non-literal
arguments.)

I decided it was easiest for the implementation to have one macro which
computes min, max, and the number of (value) bits.  Only the max
variable has to be passed, but any missing value will cause a correct
recomputation of the necessary values.

The macro will only compute the number of value bits if necessary, i.e.,
if the MAX-VARIABLE is not already defined in INCLUDES or you actually
pass a VALUE-BITS-VARIABLE.

Would you rather prefer a BITS-VARIABLE to a VALUE-BITS-VARIABLE, by
the way?

Currently the VALUE-BITS-VARIABLE is not tested for being defined
already.  Should that be included for safety?

I tried to accomodate for all that was brought up in the previous
discussion.  The testsuite found one more subtle bug: in this code
  while :; do
   AC_COMPILE_IFELSE([program], [if-true], [break])
  done

the break will inhibit the cleanup code that removes conftest.c and
conftest.err and such.  This bug is present in some other macros as
well.

The patch is against current CVS, and needs adjustment of some calls of
AC_C_TYPE_RANGE_INTEGER in your patch: I changed the number of arguments
and moved the INCLUDES argument.  So, AC_TYPE_RANGE_LONG_LONG_INT and
AC_TYPE_RANGE_UNSIGNED_LONG_LONG_INT need to be adjusted (4th argument
-> 5th argument).

Test suite additions (besides the generated ones) are still pending,
as well as the documentation update.  FYI there is sample usage below.

These macros may be optimized a bit further: to do a binary search, to
short-cut the sign and suffix computation for all the basic types in M4,
and to allow the user to pre-define the sign (as that is often known in
advance).  I left all those as exercises to the so-inclined reader.  ;-)

Cheers,
Ralf


Sample configure.ac #1:

AC_INIT
AC_CONFIG_HEADERS([config.h])
AC_PROG_CC
AC_C_TYPE_RANGE_INTEGER([short], [MIN_SHORT], [MAX_SHORT])
AC_C_TYPE_RANGE_INTEGER([short], [SHRT_MIN], [SHRT_MAX])
AC_C_TYPE_RANGE_INTEGER([int8_t], [INT8_MIN], [INT8_MAX])
AC_C_TYPE_RANGE_INTEGER([char], [char_short], [char_max], [char_vbits])
AC_C_TYPE_RANGE_INTEGER([mychar], [mychar_short], [mychar_max], [mychar_vbit], 
[typedef char mychar;])
AC_C_TYPE_RANGE_INTEGER([unsigned long], [ulg_min], [ulg_max])
AC_C_TYPE_RANGE_INTEGER([long], [lg_min], [lg_max])
AC_C_TYPE_RANGE_INTEGER([foo], [foo_min], [foo_max], [foo_vbit], [typedef 
unsigned long long foo;])
AC_C_TYPE_RANGE_INTEGER([bar], [bar_min], [bar_max])
AC_OUTPUT


Sample configure.ac #2:
# This works with autoconf, but autoheader does not have
# the templates.  (That's why we need AC_C_TYPE_RANGE_INTEGERS.)
AC_DEFUN([my_INT_RANGES],
[eval set $1
while test "$[1]"; do
  AC_C_TYPE_RANGE_INTEGER([$[1]], [$[2]], [$[3]], [$[4]],
                          [AC_INCLUDES_DEFAULT
                           [#include <limits.h>]])
  shift; shift; shift; shift
done
])

AC_INIT
AC_CONFIG_HEADERS([config.h])
AC_PROG_CC_STDC
AC_CHECK_HEADERS([limits.h])

list="\
char char_min char_max char_vbits \
short MIN_SHORT MAX_SHORT '' \
int INT_MIN INT_MAX '' \
long LONG_MIN LONG_MAX '' \
'long long' LLONG_MIN LLONG_MAX '' \
intmax_t INTMAX_MIN INTMAX_MAX INTMAX_VBITS \
uintmax_t UINTMAX_MIN UINTMAX_MAX UINTMAX_BITS \
"
my_INT_RANGES([$list])

AC_OUTPUT



Index: lib/autoconf/c.m4
===================================================================
RCS file: /cvsroot/autoconf/autoconf/lib/autoconf/c.m4,v
retrieving revision 1.213
diff -u -r1.213 c.m4
--- lib/autoconf/c.m4   20 Mar 2006 20:28:56 -0000      1.213
+++ lib/autoconf/c.m4   1 Apr 2006 10:23:51 -0000
@@ -1670,3 +1634,207 @@
     fi
   fi
 ])
+
+
+# _AC_C_TYPE_SIGNBIT_INTEGER(TYPE, [INCLUDES = DEFAULT-INCLUDES])
+# ---------------------------------------------------------------
+# Compute the number of sign bits for TYPE.  The cache variable
+# is set to empty if the type is not defined.
+m4_define([_AC_C_TYPE_SIGNBIT_INTEGER],
+[
+  AS_VAR_PUSHDEF([ac_sbits], [ac_cv_signbits_$1])dnl
+  AC_CACHE_CHECK([for sign bits of $1], ac_sbits,
+    [AS_VAR_SET(ac_sbits, [])
+     AC_COMPILE_IFELSE(
+       [AC_LANG_BOOL_COMPILE_TRY([AC_INCLUDES_DEFAULT([$2])], [($1) -1 < 0])],
+       [AS_VAR_SET(ac_sbits, 1)],
+       [AC_COMPILE_IFELSE(
+         [AC_LANG_BOOL_COMPILE_TRY(
+            [AC_INCLUDES_DEFAULT([$2])], [0 < ($1) -1])],
+         [AS_VAR_SET(ac_sbits, [0])])])
+    ])
+  AS_VAR_POPDEF([ac_sbits])dnl
+])# _AC_C_TYPE_SIGNBIT_INTEGER
+
+
+# _AC_C_TYPE_VALUE_BITS_INTEGER(TYPE, [VALUE-BITS-VARIABLE],
+#                                     [INCLUDES = DEFAULT-INCLUDES])
+# ------------------------------------------------------------------
+# Compute the number of value bits for TYPE.  If VALUE-BITS-VARIABLE
+# is given, store the result there.
+# This macro needs the number of sign bits as computed by
+# _AC_C_TYPE_SIGNBIT_INTEGER.
+m4_define([_AC_C_TYPE_VALUE_BITS_INTEGER],
+[
+  AS_VAR_PUSHDEF([ac_vbits], [ac_cv_valuebits_$1])dnl
+  AS_VAR_PUSHDEF([ac_sbits], [ac_cv_signbits_$1])dnl
+  AC_CACHE_CHECK([for value bits of $1], ac_vbits,
+    [ac_signbit=AS_VAR_GET(ac_sbits)
+     case $ac_signbit in #(
+     1) ac_suffix=; ac_unsigned=;; #(
+     0) ac_suffix=U; ac_unsigned=unsigned;;
+     esac
+     if test -n "$ac_signbit"; then
+       ac_bits=8; ac_1=1
+       for ac_type in \
+           "$ac_unsigned int" \
+           "$ac_unsigned long int" \
+           "$ac_unsigned long long int"; do
+         AC_COMPILE_IFELSE(
+           [AC_LANG_PROGRAM(
+              [$3
+              extern $ac_type ac__var_;
+              extern $1 ac__var_;],
+              [return !ac__var_;])],
+           [ac_1=1$ac_suffix
+            case $ac_type in #(
+            *long\ long*) ac_bits=64; ac_1=${ac_1}LL ;; #(
+            *long*)       ac_bits=32; ac_1=${ac_1}L ;;
+            esac
+            break])
+       done
+
+       ac_shiftbits=`expr $ac_bits - 1 - $ac_signbit`
+       ac_max="(((($ac_1 << $ac_shiftbits) - 1) << 1) + 1)"
+
+       # Double the number of bits until this fails.
+       ac_go=:
+       while $ac_go; do
+         ac_bits1=`expr $ac_bits '*' 2`
+         ac_shiftbits=`expr $ac_bits1 - 1 - $ac_signbit`
+         ac_max1="(((($ac_1 << $ac_shiftbits) - 1) << 1) + 1)"
+
+         AC_COMPILE_IFELSE(
+           [AC_LANG_BOOL_COMPILE_TRY([AC_INCLUDES_DEFAULT([$3])],
+              [$ac_max < $ac_max1 && ($1) $ac_max1 == $ac_max1])],
+           [ac_bits=$ac_bits1; ac_max=$ac_max1],
+           [ac_go=false])
+       done
+
+       # Add 1 to the number of bits until this fails.
+       ac_go=:
+       while $ac_go; do
+         ac_bits1=`expr $ac_bits + 1`
+         ac_shiftbits=`expr $ac_bits1 - 1 - $ac_signbit`
+         ac_max1="(((($ac_1 << $ac_shiftbits) - 1) << 1) + 1)"
+
+         AC_COMPILE_IFELSE(
+           [AC_LANG_BOOL_COMPILE_TRY([AC_INCLUDES_DEFAULT([$3])],
+              [$ac_max < $ac_max1 && ($1) $ac_max1 == $ac_max1])],
+           [ac_bits=$ac_bits1; ac_max=$ac_max1],
+           [ac_go=false])
+       done
+
+       AS_VAR_SET(ac_vbits, [`expr $ac_bits - $ac_signbit`])
+     fi
+    ])
+  m4_ifval([$2],
+    [case $2:AS_VAR_GET(ac_vbits) in #(
+     ?*:?*)
+       AC_DEFINE_UNQUOTED([$2], [AS_VAR_GET(ac_vbits)],
+        [Define to the number of value bits for the integer type `$1', if it
+         is a valid type.]);;
+     esac])
+  AS_VAR_POPDEF([ac_vbits])dnl
+  AS_VAR_POPDEF([ac_sbits])dnl
+])# _AC_C_TYPE_VALUE_BITS_INTEGER
+
+
+# AC_C_TYPE_RANGE_INTEGER(TYPE, [MIN-VARIABLE], MAX-VARIABLE,
+#                        [VALUE-BITS-VARIABLE],
+#                        [INCLUDES = DEFAULT-INCLUDES])
+# -----------------------------------------------------------
+# Compute the bounds (and optionally the value bits) of the integer TYPE
+# and define MIN-VARIABLE, MAX-VARIABLE, and VALUE-BITS-VARIABLE to those
+# bounds and bits, respectively.  The bounds are expressions that are
+# suitable for use in the preprocessor, the value bits is an integer literal.
+# If one or both of MIN-VARIABLE or VALUE-BITS-VARIABLE are absent, do not
+# define them.  If either one of MIN-VARIABLE or MAX-VARIABLE is already
+# defined through INCLUDES, do not define it.  If TYPE does not work, do not
+# define either of the three variables.  Works OK if cross compiling.
+#
+# This macro makes use of the `ac_max' internal of the two previous macro.
+AC_DEFUN([AC_C_TYPE_RANGE_INTEGER],
+[
+  m4_ifval([$3], [], [m4_fatal([$0: need MAX-VARIABLE argument])])dnl
+  AS_VAR_PUSHDEF([ac_sbits], [ac_cv_signbits_$1])dnl
+  AS_VAR_PUSHDEF([ac_vbits], [ac_cv_valuebits_$1])dnl
+  AS_VAR_PUSHDEF([ac_cache_min], [ac_cv_value_$2])dnl
+  AS_VAR_PUSHDEF([ac_cache_max], [ac_cv_value_$3])dnl
+
+  _AC_C_TYPE_SIGNBIT_INTEGER([$1], [$5])
+
+  if test -n "AS_VAR_GET(ac_sbits)"; then
+    dnl Since AC_CACHE_CHECK does not have the functionality to
+    dnl execute some COMMANDS-TO-SET-THEM when one of multiple
+    dnl CACHE-IDs is not set, we have to commit a minor Autoconf crime
+    dnl here by precomputing and only feeding the cache variable with
+    dnl the result afterwards, to avoid garbled output.
+    dnl (The crime being that the work is done before the output that
+    dnl naturally associates with it is seen by the impatient user.)
+    ac_val_defined=
+    if test -z "AS_VAR_GET(ac_cache_max)"; then
+      AC_COMPILE_IFELSE(
+        [AC_LANG_BOOL_COMPILE_TRY([AC_INCLUDES_DEFAULT([$5])], [$3 == $3])],
+        [ac_val_defined=yes], [ac_val_defined=no])
+    fi
+    dnl Compute the value bits if
+    dnl - either ac_val_defined=no and they are not cached yet,
+    dnl - or we want to know the value bits anyway.
+    case AS_VAR_GET(ac_cache_max):$ac_val_defined:$4 in #(
+    :no:* | *:*:?* )
+      _AC_C_TYPE_VALUE_BITS_INTEGER([$1], [$4], [$5]) ;;
+    esac
+  fi
+  AC_CACHE_CHECK([for $3], ac_cache_max,
+  [case $ac_val_defined:AS_VAR_GET(ac_sbits) in #(
+   *:)    AS_VAR_SET(ac_cache_max, [no]) ;; #(
+   yes:*) AS_VAR_SET(ac_cache_max, [yes]) ;; #(
+   *)     AS_VAR_SET(ac_cache_max, [$ac_max]) ;;
+   esac])
+
+  case AS_VAR_GET(ac_cache_max) in #(
+  yes|no) ;; #(
+  *)
+    AC_DEFINE_UNQUOTED([$3], [AS_VAR_GET(ac_cache_max)],
+      [Define to the maximum value for the integer type `$1', if the
+       usual headers do not define $3 and if `$1' is a valid type.]);;
+  esac
+
+  m4_ifval([$2],
+    [if test -n "$2"; then
+       AC_CACHE_CHECK([for $2], ac_cache_min,
+        [if test "AS_VAR_GET(ac_cache_max)" = no; then
+           AS_VAR_SET(ac_cache_min, [no])
+         else
+           AC_COMPILE_IFELSE(
+             [AC_LANG_BOOL_COMPILE_TRY([AC_INCLUDES_DEFAULT([$5])],
+                [$2 == $2])],
+             [AS_VAR_SET(ac_cache_min, [yes])],
+             [ac_min="(- $3)"
+              ac_min1="(-1 - $3)"
+              AC_COMPILE_IFELSE(
+                [AC_LANG_BOOL_COMPILE_TRY([AC_INCLUDES_DEFAULT([$5])],
+                   [$ac_min1 < $ac_min && ($1) $ac_min1 == $ac_min1])],
+                [ac_min=$ac_min1],
+                [AC_COMPILE_IFELSE(
+                   [AC_LANG_BOOL_COMPILE_TRY([AC_INCLUDES_DEFAULT([$5])],
+                      [($1) -1 < 0])],
+                   [],
+                   [ac_min=0])])
+              AS_VAR_SET(ac_cache_min, [$ac_min])])
+          fi])
+
+       case AS_VAR_GET(ac_cache_min) in #(
+       yes|no) ;; #(
+       *)
+        AC_DEFINE_UNQUOTED([$2], [AS_VAR_GET(ac_cache_min)],
+          [Define to the minimum value for the integer type `$1', if the
+           usual headers do not define $2 and if `$1' is a valid type.]);;
+       esac
+     fi])
+  AS_VAR_POPDEF([ac_cache_max])dnl
+  AS_VAR_POPDEF([ac_cache_min])dnl
+  AS_VAR_POPDEF([ac_vbits])dnl
+  AS_VAR_POPDEF([ac_sbits])dnl
+])# AC_C_TYPE_RANGE_INTEGER




reply via email to

[Prev in Thread] Current Thread [Next in Thread]