On Tue, 1 Apr 2025 at 11:34, Tomasz Kaminski <tkami...@redhat.com> wrote: > > > > On Mon, Mar 31, 2025 at 7:28 PM Jonathan Wakely <jwak...@redhat.com> wrote: >> >> 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. >> --- >> >> Testing x86_64-linux and sparc-solaris2.11, looks fine so far. >> >> 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 > > From documentation this is deprecated in favor of AC_LANG_PUSH.
It looks like that is supported by autoconf 2.69 and is already used elsewhere in GCC. We don't currently use it in libstdc++ but it should be safe to do so. >> + AC_LANG_CPLUSPLUS >> + ac_save_CXXFLAGS="$CXXFLAGS" >> + CXXFLAGS="$CXXFLAGS -std=c++20" > > The program that is compiled does not seem to require C++20. > If we change the declaration of "t" to use "= {}", we could do it in C++98. > Any reason to adjust the flags at all? We only need to use the tm_zone member in C++20 mode, and it's possible that on some platform it's not exposed for older standards (very unlikely, but possible). I wanted to test for exactly what we require. I don't feel strongly about it though. >> >> + >> + AC_CACHE_CHECK([for tm_zone member of struct tm], glibcxx_cv_tm_zone, [ >> + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include <time.h> >> + ], >> + [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 <dirent.h> 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 <string.h>. */ >> #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 <unistd.h>. */ >> #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 <uchar.h> 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 <sys/time.h> 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<typename T1, typename T2> >> 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 <time.h> >> + >> +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 <sys/types.h> >> -#include <time.h> >> - >> -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 <sys/types.h> >> -#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 >> <time.h> >> -" >> -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 <time.h> >> -#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>) >> -- >> 2.49.0 >>