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 <br...@clisp.org> * 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;