[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH] bypass broken inline strtod() definition in <stdlib.h> on Mi
From: |
Bruno Haible |
Subject: |
Re: [PATCH] bypass broken inline strtod() definition in <stdlib.h> on Mingw |
Date: |
Mon, 14 Jun 2010 01:43:09 +0200 |
User-agent: |
KMail/1.9.9 |
Hi Ben,
> The problem is that AC_FUNC_STRTOD assumes that strtod does not
> exist when cross-compiling, which in turn makes the strtod module
> assume that it does not need to handle an existing declaration.
Ah, so AC_FUNC_STRTOD makes gnulib think that strtod() does not exist,
although in fact it does exist. Just because of the worst-case guess
that says "ac_cv_func_strtod=no".
> --- a/m4/strtod.m4
> +++ b/m4/strtod.m4
> @@ -1,4 +1,4 @@
> -# strtod.m4 serial 14
> +# strtod.m4 serial 15
> dnl Copyright (C) 2002-2003, 2006-2010 Free Software Foundation, Inc.
> dnl This file is free software; the Free Software Foundation
> dnl gives unlimited permission to copy and/or distribute it,
> @@ -11,7 +11,13 @@ AC_DEFUN([gl_FUNC_STRTOD],
> dnl Note: AC_FUNC_STRTOD does AC_LIBOBJ([strtod]).
> if test $ac_cv_func_strtod = no; then
> HAVE_STRTOD=0
> - gl_PREREQ_STRTOD
> +
> + # AC_FUNC_STRTOD assumes that strtod is missing when cross-compiling,
> + # but to reliably provide it we need to know whether it is declared.
> + AC_CHECK_DECLS_ONCE([strtod])
> + if test "$ac_cv_have_decl_strtod" = yes; then
> + REPLACE_STRTOD=1
> + fi
> else
> AC_CACHE_CHECK([whether strtod obeys C99], [gl_cv_func_strtod_works],
> [AC_RUN_IFELSE([AC_LANG_PROGRAM([[
> @@ -77,10 +83,12 @@ numeric_equal (double x, double y)
> [gl_cv_func_strtod_works="guessing no"])])
> if test "$gl_cv_func_strtod_works" != yes; then
> REPLACE_STRTOD=1
> - gl_PREREQ_STRTOD
> - dnl Use undocumented macro to set POW_LIB correctly.
> - _AC_LIBOBJ_STRTOD
> - fi
> + fi
> + fi
> + if test $HAVE_STRTOD = 0 || test $REPLACE_STRTOD = 1; then
> + gl_PREREQ_STRTOD
> + dnl Use undocumented macro to set POW_LIB correctly.
> + _AC_LIBOBJ_STRTOD
> fi
> ])
This is better. I like about it that it introduces the now common idiom
if test $HAVE_STRTOD = 0 || test $REPLACE_STRTOD = 1; then
But there are still two problems:
- In the first branch it can happen that you set HAVE_STRTOD=0 and
REPLACE_STRTOD=1. The macro should set one or the other, not both.
Reason: The macros in the generated <stdlib.h> do the wrong thing
in C++ mode if HAVE_STRTOD = 0 && REPLACE_STRTOD = 1.
- When we are cross-compiling, we should avoid pessimistic guesses
such as "ac_cv_func_strtod=no". The reason is that the most frequent
use of cross-compiling is done for embedded Linux devices (devices
with BusyBox, or everything-on-a-chip systems). In such cases,
it is not well seen if gnulib provides a replacement function when
in fact it is not needed at all. So, please, when cross-compiling,
give a thought to the embedded Linux case (with glibc or uClibc).
So: Do current embedded Linuxes have the strtod bugs or not? Take a
look at the AC_FUNC_STRTOD macro in autoconf/lib/autoconf/functions.m4:
7bd04c77 (Akim Demaille 2000-08-01 11:16:33 +0000 1537)#
AC_FUNC_STRTOD
7bd04c77 (Akim Demaille 2000-08-01 11:16:33 +0000 1538)#
--------------
7134f17d (Akim Demaille 2002-09-28 14:06:07 +0000
1539)AN_FUNCTION([strtod], [AC_FUNC_STRTOD])
7bd04c77 (Akim Demaille 2000-08-01 11:16:33 +0000
1540)AC_DEFUN([AC_FUNC_STRTOD],
1492d7c5 (Akim Demaille 2001-11-12 15:47:35 +0000
1541)[AC_SUBST(POW_LIB)dnl
1492d7c5 (Akim Demaille 2001-11-12 15:47:35 +0000
1542)AC_CACHE_CHECK(for working strtod, ac_cv_func_strtod,
6a2a74c2 (Akim Demaille 2001-07-04 14:37:52 +0000
1543)[AC_RUN_IFELSE([AC_LANG_SOURCE([[
11ee0ab5 (Paul Eggert 2004-05-03 20:15:44 +0000
1544)]AC_INCLUDES_DEFAULT[
11ee0ab5 (Paul Eggert 2004-05-03 20:15:44 +0000 1545)#ifndef
strtod
7bd04c77 (Akim Demaille 2000-08-01 11:16:33 +0000 1546)double
strtod ();
11ee0ab5 (Paul Eggert 2004-05-03 20:15:44 +0000 1547)#endif
7bd04c77 (Akim Demaille 2000-08-01 11:16:33 +0000 1548)int
7bd04c77 (Akim Demaille 2000-08-01 11:16:33 +0000 1549)main()
7bd04c77 (Akim Demaille 2000-08-01 11:16:33 +0000 1550){
7bd04c77 (Akim Demaille 2000-08-01 11:16:33 +0000 1551) {
7bd04c77 (Akim Demaille 2000-08-01 11:16:33 +0000 1552) /*
Some versions of Linux strtod mis-parse strings with leading '+'. */
7bd04c77 (Akim Demaille 2000-08-01 11:16:33 +0000 1553) char
*string = " +69";
7bd04c77 (Akim Demaille 2000-08-01 11:16:33 +0000 1554) char
*term;
7bd04c77 (Akim Demaille 2000-08-01 11:16:33 +0000 1555) double
value;
7bd04c77 (Akim Demaille 2000-08-01 11:16:33 +0000 1556) value
= strtod (string, &term);
7bd04c77 (Akim Demaille 2000-08-01 11:16:33 +0000 1557) if
(value != 69 || term != (string + 4))
a71c24a7 (Paul Eggert 2006-04-03 03:18:39 +0000 1558)
return 1;
7bd04c77 (Akim Demaille 2000-08-01 11:16:33 +0000 1559) }
7bd04c77 (Akim Demaille 2000-08-01 11:16:33 +0000 1560)
7bd04c77 (Akim Demaille 2000-08-01 11:16:33 +0000 1561) {
7bd04c77 (Akim Demaille 2000-08-01 11:16:33 +0000 1562) /*
Under Solaris 2.4, strtod returns the wrong value for the
7bd04c77 (Akim Demaille 2000-08-01 11:16:33 +0000 1563)
terminating character under some conditions. */
7bd04c77 (Akim Demaille 2000-08-01 11:16:33 +0000 1564) char
*string = "NaN";
7bd04c77 (Akim Demaille 2000-08-01 11:16:33 +0000 1565) char
*term;
7bd04c77 (Akim Demaille 2000-08-01 11:16:33 +0000 1566) strtod
(string, &term);
7bd04c77 (Akim Demaille 2000-08-01 11:16:33 +0000 1567) if
(term != string && *(term - 1) == 0)
a71c24a7 (Paul Eggert 2006-04-03 03:18:39 +0000 1568)
return 1;
7bd04c77 (Akim Demaille 2000-08-01 11:16:33 +0000 1569) }
a71c24a7 (Paul Eggert 2006-04-03 03:18:39 +0000 1570) return 0;
7bd04c77 (Akim Demaille 2000-08-01 11:16:33 +0000 1571)}
6a2a74c2 (Akim Demaille 2001-07-04 14:37:52 +0000 1572)]])],
b44e483c (Akim Demaille 2003-05-17 10:30:07 +0000 1573)
ac_cv_func_strtod=yes,
b44e483c (Akim Demaille 2003-05-17 10:30:07 +0000 1574)
ac_cv_func_strtod=no,
b44e483c (Akim Demaille 2003-05-17 10:30:07 +0000 1575)
ac_cv_func_strtod=no)])
7bd04c77 (Akim Demaille 2000-08-01 11:16:33 +0000 1576)if test
$ac_cv_func_strtod = no; then
7bd04c77 (Akim Demaille 2000-08-01 11:16:33 +0000 1577)
_AC_LIBOBJ_STRTOD
7bd04c77 (Akim Demaille 2000-08-01 11:16:33 +0000 1578)fi
7bd04c77 (Akim Demaille 2000-08-01 11:16:33 +0000 1579)])
With two old old old tests and no reasonable cross-compiling behaviour I
would say that the best thing to do is to move these two blocks of C code
into gl_FUNC_STRTOD's test, and stop using AC_FUNC_STRTOD. Then the
autoconf documentation can mark this macro obsolescent, and on the gnulib
side this test runs one program, not two, and we have full control over
the cross-compilation behaviour.
So, I would propose
1) to apply the patch below,
2) to use the common idiom
if test $HAVE_STRTOD = 0 || test $REPLACE_STRTOD = 1; then
like you did above,
3) to improve the cross-compiling guess.
Bruno
2010-06-13 Bruno Haible <address@hidden>
* m4/strtod.m4 (gl_FUNC_STRTOD): Stop using AC_FUNC_STRTOD.
--- m4/strtod.m4.orig Mon Jun 14 01:40:50 2010
+++ m4/strtod.m4 Mon Jun 14 01:38:49 2010
@@ -1,4 +1,4 @@
-# strtod.m4 serial 14
+# strtod.m4 serial 15
dnl Copyright (C) 2002-2003, 2006-2010 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
@@ -7,11 +7,17 @@
AC_DEFUN([gl_FUNC_STRTOD],
[
AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
- AC_FUNC_STRTOD
- dnl Note: AC_FUNC_STRTOD does AC_LIBOBJ([strtod]).
- if test $ac_cv_func_strtod = no; then
+ dnl Test whether strtod is declared.
+ dnl Don't call AC_FUNC_STRTOD, because it does not have the right guess
+ dnl when cross-compiling.
+ dnl Don't call AC_CHECK_FUNCS([strtod]) because it would collide with the
+ dnl ac_cv_func_strtod variable set by the AC_FUNC_STRTOD macro,
+ AC_CHECK_DECLS_ONCE([strtod])
+ if test $ac_cv_have_decl_strtod != yes; then
HAVE_STRTOD=0
gl_PREREQ_STRTOD
+ dnl Use undocumented macro to set POW_LIB correctly.
+ _AC_LIBOBJ_STRTOD
else
AC_CACHE_CHECK([whether strtod obeys C99], [gl_cv_func_strtod_works],
[AC_RUN_IFELSE([AC_LANG_PROGRAM([[
@@ -28,6 +34,24 @@
}
]], [[
{
+ /* In some old versions of Linux (2000 or before), strtod mis-parses
+ strings with leading '+'. */
+ const char *string = " +69";
+ char *term;
+ double value = strtod (string, &term);
+ if (value != 69 || term != (string + 4))
+ return 1;
+ }
+ {
+ /* Under Solaris 2.4, strtod returns the wrong value for the
+ terminating character under some conditions. */
+ const char *string = "NaN";
+ char *term;
+ strtod (string, &term);
+ if (term != string && *(term - 1) == 0)
+ return 1;
+ }
+ {
/* Older glibc and Cygwin mis-parse "-0x". */
const char *string = "-0x";
char *term;
- [PATCH] bypass broken inline strtod() definition in <stdlib.h> on Mingw, Ben Pfaff, 2010/06/11
- Re: [PATCH] bypass broken inline strtod() definition in <stdlib.h> on Mingw, Bruno Haible, 2010/06/11
- Re: [PATCH] bypass broken inline strtod() definition in <stdlib.h> on Mingw, Ben Pfaff, 2010/06/13
- Re: AC_FUNC_STRTOD, Bruno Haible, 2010/06/14
- Re: AC_FUNC_STRTOD, Eric Blake, 2010/06/14
- Re: AC_FUNC_STRTOD, Russ Allbery, 2010/06/15
- Re: AC_FUNC_STRTOD, Paolo Bonzini, 2010/06/15
- Re: [PATCH] bypass broken inline strtod() definition in <stdlib.h> on Mingw, Ben Pfaff, 2010/06/14
- Re: [PATCH] bypass broken inline strtod() definition in <stdlib.h> on Mingw, Bruno Haible, 2010/06/15
- Re: [PATCH] bypass broken inline strtod() definition in <stdlib.h> on Mingw, Ben Pfaff, 2010/06/15