From 97cbe3cd5f36470884e940bda4469dc9b5b93cfd Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Mon, 31 Mar 2025 15:07:12 +0100 Subject: [PATCH] Libstdc++: Fix bootstrap failure for cross without tm.tm_zone [PR119550] In r15-8491-g778c28c70f8573 I added a use of the Autoconf macro AC_STRUCT_TIMEZONE, but that requires a link-test for the global tzname object if tm.tm_zone isn't supported. That link-test isn't allowed for cross-compilation, so bootstrap fails if tm.tm_zone isn't supported. Since libstdc++ only cares about tm.tm_zone and won't use tzname anyway, we don't need the link-test. Replace AC_STRUCT_TIMEZONE with a custom macro that only checks for tm.tm_zone. We can improve on the Autoconf macro by checking it's a suitable type, which isn't actually checked by AC_STRUCT_TIMEZONE. libstdc++-v3/ChangeLog: PR libstdc++/119550 * acinclude.m4 (GLIBCXX_STRUCT_TM_TM_ZONE): New macro. * config.h.in: Regenerate. * configure: Regenerate. * configure.ac: Use GLIBCXX_STRUCT_TM_TM_ZONE. * include/bits/chrono_io.h (__formatter_chrono::_M_c): Check _GLIBCXX_USE_STRUCT_TM_TM_ZONE instead of _GLIBCXX_HAVE_STRUCT_TM_TM_ZONE. --- libstdc++-v3/acinclude.m4 | 35 ++++ libstdc++-v3/config.h.in | 21 +-- libstdc++-v3/configure | 238 ++++++++------------------ libstdc++-v3/configure.ac | 5 +- libstdc++-v3/include/bits/chrono_io.h | 2 +- 5 files changed, 109 insertions(+), 192 deletions(-) diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4 index e668d2dba27..02fd349e11d 100644 --- a/libstdc++-v3/acinclude.m4 +++ b/libstdc++-v3/acinclude.m4 @@ -5744,6 +5744,41 @@ AC_DEFUN([GLIBCXX_ZONEINFO_DIR], [ fi ]) +dnl +dnl Check for a tm_zone member in struct tm. +dnl +dnl This member is defined as const char* in Glibc, newlib, POSIX.1-2024, +dnl and as char* in BSD (including macOS). +dnl +dnl Defines: +dnl _GLIBCXX_USE_STRUCT_TM_TM_ZONE if struct tm has a tm_zone member. +dnl +AC_DEFUN([GLIBCXX_STRUCT_TM_TM_ZONE], [ + + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -std=c++20" + + AC_CACHE_CHECK([for tm_zone member of struct tm], glibcxx_cv_tm_zone, [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include + ], + [struct tm t{}; t.tm_zone = (char*)0;] + )], + [glibcxx_cv_tm_zone=yes], + [glibcxx_cv_tm_zone=no] + ) + ]) + + if test $glibcxx_cv_tm_zone = yes; then + AC_DEFINE(_GLIBCXX_USE_STRUCT_TM_TM_ZONE, 1, + [Define if struct tm has a tm_zone member.]) + fi + + CXXFLAGS="$ac_save_CXXFLAGS" + AC_LANG_RESTORE +]) + dnl dnl Check whether lock tables can be aligned to avoid false sharing. dnl diff --git a/libstdc++-v3/config.h.in b/libstdc++-v3/config.h.in index be151f43dd6..77bbaf1beaa 100644 --- a/libstdc++-v3/config.h.in +++ b/libstdc++-v3/config.h.in @@ -74,10 +74,6 @@ don't. */ #undef HAVE_DECL_STRNLEN -/* Define to 1 if you have the declaration of `tzname', and to 0 if you don't. - */ -#undef HAVE_DECL_TZNAME - /* Define to 1 if you have the header file. */ #undef HAVE_DIRENT_H @@ -412,9 +408,6 @@ /* Define to 1 if `d_type' is a member of `struct dirent'. */ #undef HAVE_STRUCT_DIRENT_D_TYPE -/* Define to 1 if `tm_zone' is a member of `struct tm'. */ -#undef HAVE_STRUCT_TM_TM_ZONE - /* Define if strxfrm_l is available in . */ #undef HAVE_STRXFRM_L @@ -506,17 +499,9 @@ /* Define to 1 if the target supports thread-local storage. */ #undef HAVE_TLS -/* Define to 1 if your `struct tm' has `tm_zone'. Deprecated, use - `HAVE_STRUCT_TM_TM_ZONE' instead. */ -#undef HAVE_TM_ZONE - /* Define if truncate is available in . */ #undef HAVE_TRUNCATE -/* Define to 1 if you don't have `tm_zone' but do have the external array - `tzname'. */ -#undef HAVE_TZNAME - /* Define to 1 if you have the header file. */ #undef HAVE_UCHAR_H @@ -605,9 +590,6 @@ /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS -/* Define to 1 if your declares `struct tm'. */ -#undef TM_IN_SYS_TIME - /* Version number of package */ #undef VERSION @@ -906,6 +888,9 @@ /* Define to restrict std::__basic_file<> to stdio APIs. */ #undef _GLIBCXX_USE_STDIO_PURE +/* Define if struct tm has a tm_zone member. */ +#undef _GLIBCXX_USE_STRUCT_TM_TM_ZONE + /* Define if struct stat has timespec members. */ #undef _GLIBCXX_USE_ST_MTIM diff --git a/libstdc++-v3/configure b/libstdc++-v3/configure index 67d2b8c7b72..56d0bcb297e 100755 --- a/libstdc++-v3/configure +++ b/libstdc++-v3/configure @@ -2731,63 +2731,6 @@ $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_decl - -# ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES -# ---------------------------------------------------- -# Tries to find if the field MEMBER exists in type AGGR, after including -# INCLUDES, setting cache variable VAR accordingly. -ac_fn_c_check_member () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 -$as_echo_n "checking for $2.$3... " >&6; } -if eval \${$4+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$5 -int -main () -{ -static $2 ac_aggr; -if (ac_aggr.$3) -return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - eval "$4=yes" -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$5 -int -main () -{ -static $2 ac_aggr; -if (sizeof ac_aggr.$3) -return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - eval "$4=yes" -else - eval "$4=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -eval ac_res=\$$4 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_member cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. @@ -12337,7 +12280,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 12340 "configure" +#line 12283 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -12443,7 +12386,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 12446 "configure" +#line 12389 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -16239,7 +16182,7 @@ $as_echo "$glibcxx_cv_atomic_long_long" >&6; } # Fake what AC_TRY_COMPILE does. cat > conftest.$ac_ext << EOF -#line 16242 "configure" +#line 16185 "configure" int main() { typedef bool atomic_type; @@ -16274,7 +16217,7 @@ $as_echo "$glibcxx_cv_atomic_bool" >&6; } rm -f conftest* cat > conftest.$ac_ext << EOF -#line 16277 "configure" +#line 16220 "configure" int main() { typedef short atomic_type; @@ -16309,7 +16252,7 @@ $as_echo "$glibcxx_cv_atomic_short" >&6; } rm -f conftest* cat > conftest.$ac_ext << EOF -#line 16312 "configure" +#line 16255 "configure" int main() { // NB: _Atomic_word not necessarily int. @@ -16345,7 +16288,7 @@ $as_echo "$glibcxx_cv_atomic_int" >&6; } rm -f conftest* cat > conftest.$ac_ext << EOF -#line 16348 "configure" +#line 16291 "configure" int main() { typedef long long atomic_type; @@ -16501,7 +16444,7 @@ $as_echo "mutex" >&6; } # unnecessary for this test. cat > conftest.$ac_ext << EOF -#line 16504 "configure" +#line 16447 "configure" int main() { _Decimal32 d1; @@ -16543,7 +16486,7 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu # unnecessary for this test. cat > conftest.$ac_ext << EOF -#line 16546 "configure" +#line 16489 "configure" template struct same { typedef T2 type; }; @@ -54482,6 +54425,65 @@ _ACEOF fi +# For std::chrono formatters to use tm::tm_zone + + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -std=c++20" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tm_zone member of struct tm" >&5 +$as_echo_n "checking for tm_zone member of struct tm... " >&6; } +if ${glibcxx_cv_tm_zone+:} false; then : + $as_echo_n "(cached) " >&6 +else + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +int +main () +{ +struct tm t{}; t.tm_zone = (char*)0; + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_tm_zone=yes +else + glibcxx_cv_tm_zone=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_tm_zone" >&5 +$as_echo "$glibcxx_cv_tm_zone" >&6; } + + if test $glibcxx_cv_tm_zone = yes; then + +$as_echo "#define _GLIBCXX_USE_STRUCT_TM_TM_ZONE 1" >>confdefs.h + + fi + + CXXFLAGS="$ac_save_CXXFLAGS" + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + # For src/c++11/shared_ptr.cc alignment. @@ -54697,112 +54699,6 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5 -$as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; } -if ${ac_cv_struct_tm+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include - -int -main () -{ -struct tm tm; - int *p = &tm.tm_sec; - return !p; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_struct_tm=time.h -else - ac_cv_struct_tm=sys/time.h -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_tm" >&5 -$as_echo "$ac_cv_struct_tm" >&6; } -if test $ac_cv_struct_tm = sys/time.h; then - -$as_echo "#define TM_IN_SYS_TIME 1" >>confdefs.h - -fi - -ac_fn_c_check_member "$LINENO" "struct tm" "tm_zone" "ac_cv_member_struct_tm_tm_zone" "#include -#include <$ac_cv_struct_tm> - -" -if test "x$ac_cv_member_struct_tm_tm_zone" = xyes; then : - -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_TM_TM_ZONE 1 -_ACEOF - - -fi - -if test "$ac_cv_member_struct_tm_tm_zone" = yes; then - -$as_echo "#define HAVE_TM_ZONE 1" >>confdefs.h - -else - ac_fn_c_check_decl "$LINENO" "tzname" "ac_cv_have_decl_tzname" "#include -" -if test "x$ac_cv_have_decl_tzname" = xyes; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_TZNAME $ac_have_decl -_ACEOF - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tzname" >&5 -$as_echo_n "checking for tzname... " >&6; } -if ${ac_cv_var_tzname+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test x$gcc_no_link = xyes; then - as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 -fi -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#if !HAVE_DECL_TZNAME -extern char *tzname[]; -#endif - -int -main () -{ -return tzname[0][0]; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_var_tzname=yes -else - ac_cv_var_tzname=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_var_tzname" >&5 -$as_echo "$ac_cv_var_tzname" >&6; } - if test $ac_cv_var_tzname = yes; then - -$as_echo "#define HAVE_TZNAME 1" >>confdefs.h - - fi -fi - - # Define documentation rules conditionally. # See if makeinfo has been installed and is modern enough diff --git a/libstdc++-v3/configure.ac b/libstdc++-v3/configure.ac index fe0cdde1f7a..a6c01b29e94 100644 --- a/libstdc++-v3/configure.ac +++ b/libstdc++-v3/configure.ac @@ -572,6 +572,9 @@ GLIBCXX_EMERGENCY_EH_ALLOC # For src/c++20/tzdb.cc defaults. GLIBCXX_ZONEINFO_DIR +# For std::chrono formatters to use tm::tm_zone +GLIBCXX_STRUCT_TM_TM_ZONE + # For src/c++11/shared_ptr.cc alignment. GLIBCXX_CHECK_ALIGNAS_CACHELINE @@ -584,8 +587,6 @@ GLIBCXX_CHECK_FILEBUF_NATIVE_HANDLES # For std::text_encoding GLIBCXX_CHECK_TEXT_ENCODING -AC_STRUCT_TIMEZONE - # Define documentation rules conditionally. # See if makeinfo has been installed and is modern enough diff --git a/libstdc++-v3/include/bits/chrono_io.h b/libstdc++-v3/include/bits/chrono_io.h index 3a5bc5695fb..d8721093706 100644 --- a/libstdc++-v3/include/bits/chrono_io.h +++ b/libstdc++-v3/include/bits/chrono_io.h @@ -905,7 +905,7 @@ namespace __format // time zone info available for the time in __tm. __tm.tm_isdst = -1; -#ifdef _GLIBCXX_HAVE_STRUCT_TM_TM_ZONE +#ifdef _GLIBCXX_USE_STRUCT_TM_TM_ZONE // POSIX.1-2024 adds tm.tm_zone which will be used for %Z. // BSD has had tm_zone since 1987 but as char* so cast away const. if constexpr (__is_time_point_v<_Tp>)