Hi Collin,

> The warnings say:
> 
> >     ../gllib/string.h:809:20: error: declaration of 'memchr' has a 
> > different language linkage
> >       809 | _GL_CXXALIASWARN1 (memchr, void *,
> >           |                    ^
> >     /usr/include/string.h:94:1: note: previous definition is here
> >        94 | memchr (void *__s, int __c, size_t __n) __THROW
> >           | ^
> 
> Initially looking at glibc's string.h on my system I had suspicions of
> the following code in string.h:
> 
>     /* Tell the caller that we provide correct C++ prototypes.  */
>     #if defined __cplusplus && (__GNUC_PREREQ (4, 4) \
>                           || __glibc_clang_prereq (3, 5))
>     # define __CORRECT_ISO_CPP_STRING_H_PROTO
>     #endif
>     [...]
>     #ifdef __CORRECT_ISO_CPP_STRING_H_PROTO
>     extern "C++"
>     {
>     extern void *memchr (void *__s, int __c, size_t __n)
>         __THROW __asm ("memchr") __attribute_pure__ __nonnull ((1));
>     extern const void *memchr (const void *__s, int __c, size_t __n)
>         __THROW __asm ("memchr") __attribute_pure__ __nonnull ((1));
>     [...]
> 
> Upon looking further I see that someone else ran into errors like this
> using clang++ in 2021 [1]. AFAIK it was never resolved but the archives
> split replies by month I think. So maybe I am wrong.

It was never resolved, correct. Alexandre's mail from 2021 is still unresolved
on my side. But when I try the testdir4 recipe from that thread today,
with all versions from clang 18 down to clang 11, it all compiles fine.
I therefore believe that Alexandre's problem was fixed through
https://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=commitdiff;h=0b3f5d1b4c0b13bb51b4b6aa63392aa5231da3fc

But it was a different situation, without <sys/un.h>.

> I have attached a patch that should
> fix the testdir of all modules while using clang++.

The patch does not look right, no. AFAIU, __CORRECT_ISO_CPP_STRING_H_PROTO
is defined for all modern versions of clang, and what your patch does
is to disable the _GL_CXXALIASWARN / _GL_CXXALIASWARN1 code in this
situation.

What I see is that if I move the '#include <string.h>' from inside to
outside the __BEGIN_DECLS / __END_DECLS block in <sys/un.h>, the errors
go away. This suggests that the fix is to make sure <string.h> is
included first, outside an 'extern "C++" { ... }' block.

So, we need the idioms for a header file with GL_GENERATE_... and
#@INCLUDE_NEXT@ ... The following header files have these idioms:
  lib/assert.in.h
  lib/endian.in.h
  lib/errno.in.h
  lib/float.in.h
  lib/fnmatch.in.h
  lib/getopt.in.h
  lib/glob.in.h
  lib/iconv.in.h
  lib/inttypes.in.h
  lib/limits.in.h
  lib/monetary.in.h
  lib/net_if.in.h
  lib/netinet_in.in.h
  lib/stdalign.in.h
  lib/stdarg.in.h
  lib/stddef.in.h
  lib/stdint.in.h
  lib/sysexits.in.h
  lib/sys_msg.in.h
  lib/sys_sem.in.h
  lib/sys_shm.in.h
  lib/sys_socket.in.h
Among these, let me pick lib/netinet_in.in.h. This patch fixes the problem.


2024-07-26  Bruno Haible  <br...@clisp.org>

        sys_un: Avoid compilation error in C++ <string.h> on glibc systems.
        * m4/sys_un_h.m4 (gl_SYS_UN_H): Require AC_CANONICAL_HOST. Set
        GL_GENERATE_SYS_UN_H to true on glibc systems. Invoke
        gl_CHECK_NEXT_HEADERS. Initialize HAVE_SYS_UN_H.
        * lib/sys_un.in.h: Use include_next and a split double-inclusion guard.
        In C++ mode, include <stddef.h> and <string.h> first.
        * modules/sys_un (Depends-on): Add include_next.
        (Makefile.am): Substitute INCLUDE_NEXT, PRAGMA_SYSTEM_HEADER,
        PRAGMA_COLUMNS, NEXT_SYS_UN_H, HAVE_SYS_UN_H. Arrange to remove 'sys'
        directory at "make mostlyclean".

diff --git a/lib/sys_un.in.h b/lib/sys_un.in.h
index 52993d65f5..c137e7cef4 100644
--- a/lib/sys_un.in.h
+++ b/lib/sys_un.in.h
@@ -18,17 +18,47 @@
 /* Written by Collin Funk.  */
 
 #ifndef _@GUARD_PREFIX@_SYS_UN_H
-#define _@GUARD_PREFIX@_SYS_UN_H 1
 
-/* Windows requires <winsock2.h> to be included before <afunix.h>.  */
-#if @HAVE_WINSOCK2_H@
-# include <winsock2.h>
+#if __GNUC__ >= 3
+@PRAGMA_SYSTEM_HEADER@
 #endif
-#if @HAVE_AFUNIX_H@
-# include <afunix.h>
+@PRAGMA_COLUMNS@
+
+#if @HAVE_SYS_UN_H@
+
+/* On glibc, in C++ mode with clang, <stddef.h> and <string.h> need to be
+   included before <sys/un.h>, because otherwise <sys/un.h> includes them 
inside
+   an 'extern "C" { ... }' block, which leads to compilation errors in gnulib's
+   <string.h> override.  */
+# if defined __cplusplus
+#  include <stddef.h>
+#  include <string.h>
+# endif
+
+/* The include_next requires a split double-inclusion guard.  */
+# @INCLUDE_NEXT@ @NEXT_SYS_UN_H@
+
 #endif
 
+#ifndef _@GUARD_PREFIX@_SYS_UN_H
+#define _@GUARD_PREFIX@_SYS_UN_H 1
+
+#if !@HAVE_SYS_UN_H@
+
+/* A platform that lacks <sys/un.h>.  */
+
+/* Windows requires <winsock2.h> to be included before <afunix.h>.  */
+# if @HAVE_WINSOCK2_H@
+#  include <winsock2.h>
+# endif
+# if @HAVE_AFUNIX_H@
+#  include <afunix.h>
+# endif
+
 /* If a platform does not support AF_UNIX sockets 'struct sockaddr_un' will
    not be defined.  You may use HAVE_UNIXSOCKET after including <config.h>.  */
 
 #endif
+
+#endif /* _@GUARD_PREFIX@_SYS_UN_H */
+#endif /* _@GUARD_PREFIX@_SYS_UN_H */
diff --git a/m4/sys_un_h.m4 b/m4/sys_un_h.m4
index ed19b70cb5..959cd86c0a 100644
--- a/m4/sys_un_h.m4
+++ b/m4/sys_un_h.m4
@@ -1,5 +1,5 @@
 # sys_un_h.m4
-# serial 1
+# serial 2
 dnl Copyright 2024 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,26 +7,43 @@
 
 AC_DEFUN_ONCE([gl_SYS_UN_H],
 [
+  AC_REQUIRE([AC_CANONICAL_HOST])
+
   dnl Check if UNIX domain sockets are supported.
   AC_REQUIRE([gl_SOCKET_FAMILY_UNIX])
 
   GL_GENERATE_SYS_UN_H=false
-
   if test $gl_cv_socket_unix = yes; then
-
     dnl Check if using a Windows version that supports AF_UNIX.
     dnl See 
<https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/>.
     if test "$ac_cv_header_winsock2_h" = yes \
        && test "$ac_cv_header_afunix_h" = yes; then
       GL_GENERATE_SYS_UN_H=true
     fi
+    case "$host_os" in
+      dnl On glibc systems, we need to include <string.h> before <sys/un.h>,
+      dnl at least in C++ mode with clang.
+      *-gnu* | gnu*) GL_GENERATE_SYS_UN_H=true ;;
+    esac
   fi
 
-  dnl Checked in gl_SOCKET_FAMILY_UNIX.
-  if test "$ac_cv_header_afunix_h" = yes; then
-    HAVE_AFUNIX_H=1
-  else
-    HAVE_AFUNIX_H=0
+  if $GL_GENERATE_SYS_UN_H; then
+    AC_CHECK_HEADERS([sys/un.h])
+    gl_CHECK_NEXT_HEADERS([sys/un.h])
+
+    if test $ac_cv_header_sys_un_h = yes; then
+      HAVE_SYS_UN_H=1
+    else
+      HAVE_SYS_UN_H=0
+    fi
+    AC_SUBST([HAVE_SYS_UN_H])
+
+    dnl Checked in gl_SOCKET_FAMILY_UNIX.
+    if test "$ac_cv_header_afunix_h" = yes; then
+      HAVE_AFUNIX_H=1
+    else
+      HAVE_AFUNIX_H=0
+    fi
+    AC_SUBST([HAVE_AFUNIX_H])
   fi
-  AC_SUBST([HAVE_AFUNIX_H])
 ])
diff --git a/modules/sys_un b/modules/sys_un
index af72a80aab..21505946a8 100644
--- a/modules/sys_un
+++ b/modules/sys_un
@@ -7,6 +7,7 @@ m4/sys_un_h.m4
 
 Depends-on:
 gen-header
+include_next
 sys_socket
 
 configure.ac:
@@ -24,15 +25,21 @@ sys/un.h: sys_un.in.h $(top_builddir)/config.status
 @NMD@  $(AM_V_GEN)$(MKDIR_P) '%reldir%'
        $(gl_V_at)$(SED_HEADER_STDOUT) \
              -e 's|@''GUARD_PREFIX''@|${gl_include_guard_prefix}|g' \
+             -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \
+             -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \
+             -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
+             -e 's|@''NEXT_SYS_UN_H''@|$(NEXT_SYS_UN_H)|g' \
+             -e 's|@''HAVE_SYS_UN_H''@|$(HAVE_SYS_UN_H)|g' \
              -e 's|@''HAVE_WINSOCK2_H''@|$(HAVE_WINSOCK2_H)|g' \
              -e 's|@''HAVE_AFUNIX_H''@|$(HAVE_AFUNIX_H)|g' \
-       $(srcdir)/sys_un.in.h > $@-t
+             $(srcdir)/sys_un.in.h > $@-t
        $(AM_V_at)mv $@-t $@
 else
 sys/un.h: $(top_builddir)/config.status
        rm -f $@
 endif
 MOSTLYCLEANFILES += sys/un.h sys/un.h-t
+MOSTLYCLEANDIRS += sys
 
 Include:
 <sys/un.h>




Reply via email to