Fix detection and handling of strchrnul() for macOS 15.4.

As of 15.4, macOS has strchrnul(), but access to it is blocked behind
a check for MACOSX_DEPLOYMENT_TARGET >= 15.4.  But our does-it-link
configure check finds it, so we try to use it, and fail with the
present default deployment target (namely 15.0).  This accounts for
today's buildfarm failures on indri and sifaka.

This is the identical problem that we faced some years ago when Apple
introduced preadv and pwritev in the same way.  We solved that in
commit f014b1b9b by using AC_CHECK_DECLS instead of AC_CHECK_FUNCS
to check the functions' availability.  So do the same now for
strchrnul().  Interestingly, we already had a workaround for
"the link check doesn't agree with <string.h>" cases with glibc,
which we no longer need since only the header declaration is being
checked.

Testing this revealed that the meson version of this check has never
worked, because it failed to use "-Werror=unguarded-availability-new".
(Apparently nobody's tried to build with meson on macOS versions that
lack preadv/pwritev as standard.)  Adjust that while at it.  Also,
we had never put support for "-Werror=unguarded-availability-new"
into v13, but we need that now.

Co-authored-by: Tom Lane <tgl@sss.pgh.pa.us>
Co-authored-by: Peter Eisentraut <peter@eisentraut.org>
Discussion: https://postgr.es/m/385134.1743523038@sss.pgh.pa.us
Backpatch-through: 13
This commit is contained in:
Tom Lane 2025-04-01 16:49:51 -04:00
parent db8238da42
commit e4440a73c7
5 changed files with 135 additions and 22 deletions

110
configure vendored
View File

@ -5448,6 +5448,98 @@ if test x"$pgac_cv_prog_CC_cflags__Werror_vla" = x"yes"; then
fi
# On macOS, complain about usage of symbols newer than the deployment target
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${CC} supports -Werror=unguarded-availability-new, for CFLAGS" >&5
$as_echo_n "checking whether ${CC} supports -Werror=unguarded-availability-new, for CFLAGS... " >&6; }
if ${pgac_cv_prog_CC_cflags__Werror_unguarded_availability_new+:} false; then :
$as_echo_n "(cached) " >&6
else
pgac_save_CFLAGS=$CFLAGS
pgac_save_CC=$CC
CC=${CC}
CFLAGS="${CFLAGS} -Werror=unguarded-availability-new"
ac_save_c_werror_flag=$ac_c_werror_flag
ac_c_werror_flag=yes
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
main ()
{
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
pgac_cv_prog_CC_cflags__Werror_unguarded_availability_new=yes
else
pgac_cv_prog_CC_cflags__Werror_unguarded_availability_new=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
ac_c_werror_flag=$ac_save_c_werror_flag
CFLAGS="$pgac_save_CFLAGS"
CC="$pgac_save_CC"
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_prog_CC_cflags__Werror_unguarded_availability_new" >&5
$as_echo "$pgac_cv_prog_CC_cflags__Werror_unguarded_availability_new" >&6; }
if test x"$pgac_cv_prog_CC_cflags__Werror_unguarded_availability_new" = x"yes"; then
CFLAGS="${CFLAGS} -Werror=unguarded-availability-new"
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${CXX} supports -Werror=unguarded-availability-new, for CXXFLAGS" >&5
$as_echo_n "checking whether ${CXX} supports -Werror=unguarded-availability-new, for CXXFLAGS... " >&6; }
if ${pgac_cv_prog_CXX_cxxflags__Werror_unguarded_availability_new+:} false; then :
$as_echo_n "(cached) " >&6
else
pgac_save_CXXFLAGS=$CXXFLAGS
pgac_save_CXX=$CXX
CXX=${CXX}
CXXFLAGS="${CXXFLAGS} -Werror=unguarded-availability-new"
ac_save_cxx_werror_flag=$ac_cxx_werror_flag
ac_cxx_werror_flag=yes
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
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
main ()
{
;
return 0;
}
_ACEOF
if ac_fn_cxx_try_compile "$LINENO"; then :
pgac_cv_prog_CXX_cxxflags__Werror_unguarded_availability_new=yes
else
pgac_cv_prog_CXX_cxxflags__Werror_unguarded_availability_new=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
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
ac_cxx_werror_flag=$ac_save_cxx_werror_flag
CXXFLAGS="$pgac_save_CXXFLAGS"
CXX="$pgac_save_CXX"
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_prog_CXX_cxxflags__Werror_unguarded_availability_new" >&5
$as_echo "$pgac_cv_prog_CXX_cxxflags__Werror_unguarded_availability_new" >&6; }
if test x"$pgac_cv_prog_CXX_cxxflags__Werror_unguarded_availability_new" = x"yes"; then
CXXFLAGS="${CXXFLAGS} -Werror=unguarded-availability-new"
fi
# -Wvla is not applicable for C++
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${CC} supports -Wendif-labels, for CFLAGS" >&5
@ -15697,7 +15789,7 @@ fi
LIBS_including_readline="$LIBS"
LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'`
for ac_func in backtrace_symbols clock_gettime copyfile fdatasync getifaddrs getpeerucred getrlimit kqueue mbstowcs_l memset_s poll posix_fallocate ppoll pstat pthread_is_threaded_np readlink setproctitle setproctitle_fast setsid shm_open strchrnul strsignal symlink sync_file_range uselocale wcstombs_l
for ac_func in backtrace_symbols clock_gettime copyfile fdatasync getifaddrs getpeerucred getrlimit kqueue mbstowcs_l memset_s poll posix_fallocate ppoll pstat pthread_is_threaded_np readlink setproctitle setproctitle_fast setsid shm_open strsignal symlink sync_file_range uselocale wcstombs_l
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
@ -16214,6 +16306,22 @@ cat >>confdefs.h <<_ACEOF
#define HAVE_DECL_STRNLEN $ac_have_decl
_ACEOF
# We can't use AC_REPLACE_FUNCS to replace these functions, because it
# won't handle deployment target restrictions on macOS
ac_fn_c_check_decl "$LINENO" "strchrnul" "ac_cv_have_decl_strchrnul" "#include <string.h>
"
if test "x$ac_cv_have_decl_strchrnul" = xyes; then :
ac_have_decl=1
else
ac_have_decl=0
fi
cat >>confdefs.h <<_ACEOF
#define HAVE_DECL_STRCHRNUL $ac_have_decl
_ACEOF
# This is probably only present on macOS, but may as well check always
ac_fn_c_check_decl "$LINENO" "F_FULLFSYNC" "ac_cv_have_decl_F_FULLFSYNC" "#include <fcntl.h>
"

View File

@ -511,6 +511,9 @@ if test "$GCC" = yes -a "$ICC" = no; then
AC_SUBST(PERMIT_DECLARATION_AFTER_STATEMENT)
# Really don't want VLAs to be used in our dialect of C
PGAC_PROG_CC_CFLAGS_OPT([-Werror=vla])
# On macOS, complain about usage of symbols newer than the deployment target
PGAC_PROG_CC_CFLAGS_OPT([-Werror=unguarded-availability-new])
PGAC_PROG_CXX_CFLAGS_OPT([-Werror=unguarded-availability-new])
# -Wvla is not applicable for C++
PGAC_PROG_CC_CFLAGS_OPT([-Wendif-labels])
PGAC_PROG_CXX_CFLAGS_OPT([-Wendif-labels])
@ -1758,7 +1761,6 @@ AC_CHECK_FUNCS(m4_normalize([
setproctitle_fast
setsid
shm_open
strchrnul
strsignal
symlink
sync_file_range
@ -1793,6 +1795,11 @@ AC_CHECK_DECLS(posix_fadvise, [], [], [#include <fcntl.h>])
AC_CHECK_DECLS(fdatasync, [], [], [#include <unistd.h>])
AC_CHECK_DECLS([strlcat, strlcpy, strnlen])
# We can't use AC_REPLACE_FUNCS to replace these functions, because it
# won't handle deployment target restrictions on macOS
AC_CHECK_DECLS([strchrnul], [], [], [#include <string.h>])
# This is probably only present on macOS, but may as well check always
AC_CHECK_DECLS(F_FULLFSYNC, [], [], [#include <fcntl.h>])

View File

@ -147,6 +147,10 @@
don't. */
#undef HAVE_DECL_RTLD_NOW
/* Define to 1 if you have the declaration of `strchrnul', and to 0 if you
don't. */
#undef HAVE_DECL_STRCHRNUL
/* Define to 1 if you have the declaration of `strlcat', and to 0 if you
don't. */
#undef HAVE_DECL_STRLCAT
@ -497,9 +501,6 @@
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the `strchrnul' function. */
#undef HAVE_STRCHRNUL
/* Define to 1 if you have the `strerror_r' function. */
#undef HAVE_STRERROR_R

View File

@ -348,13 +348,22 @@ static void leading_pad(int zpad, int signvalue, int *padlen,
static void trailing_pad(int padlen, PrintfTarget *target);
/*
* If strchrnul exists (it's a glibc-ism), it's a good bit faster than the
* equivalent manual loop. If it doesn't exist, provide a replacement.
* If strchrnul exists (it's a glibc-ism, but since adopted by some other
* platforms), it's a good bit faster than the equivalent manual loop.
* Use it if possible, and if it doesn't exist, use this replacement.
*
* Note: glibc declares this as returning "char *", but that would require
* casting away const internally, so we don't follow that detail.
*
* Note: macOS has this too as of Sequoia 15.4, but it's hidden behind
* a deployment-target check that causes compile errors if the deployment
* target isn't high enough. So !HAVE_DECL_STRCHRNUL may mean "yes it's
* declared, but it doesn't compile". To avoid failing in that scenario,
* use a macro to avoid matching <string.h>'s name.
*/
#ifndef HAVE_STRCHRNUL
#if !HAVE_DECL_STRCHRNUL
#define strchrnul pg_strchrnul
static inline const char *
strchrnul(const char *s, int c)
@ -364,19 +373,7 @@ strchrnul(const char *s, int c)
return s;
}
#else
/*
* glibc's <string.h> declares strchrnul only if _GNU_SOURCE is defined.
* While we typically use that on glibc platforms, configure will set
* HAVE_STRCHRNUL whether it's used or not. Fill in the missing declaration
* so that this file will compile cleanly with or without _GNU_SOURCE.
*/
#ifndef _GNU_SOURCE
extern char *strchrnul(const char *s, int c);
#endif
#endif /* HAVE_STRCHRNUL */
#endif /* !HAVE_DECL_STRCHRNUL */
/*

View File

@ -243,6 +243,7 @@ sub GenerateFiles
HAVE_DECL_POSIX_FADVISE => 0,
HAVE_DECL_RTLD_GLOBAL => 0,
HAVE_DECL_RTLD_NOW => 0,
HAVE_DECL_STRCHRNUL => 0,
HAVE_DECL_STRLCAT => 0,
HAVE_DECL_STRLCPY => 0,
HAVE_DECL_STRNLEN => 1,
@ -356,7 +357,6 @@ sub GenerateFiles
HAVE_SRANDOM => undef,
HAVE_STDINT_H => 1,
HAVE_STDLIB_H => 1,
HAVE_STRCHRNUL => undef,
HAVE_STRERROR_R => undef,
HAVE_STRINGS_H => undef,
HAVE_STRING_H => 1,