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.* > + 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? > + > + 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 > >