On 5/18/24 4:46 AM, Bruno Haible wrote:
>> I see. What is the correct solution here?
> 
> See the idioms used by, say, arpa_inet.in.h.
> 
>> Or something like this:
>>
>> #if @HAVE_ENDIAN_H@
>> # @INCLUDE_NEXT@ @NEXT_ENDIAN_H@
>> #endif
> 
> This is part of it. But there's more details needed.

Can you check the attached patch? I think that it should work or
at least be in the correct direction...

On my system in a testdir with all modules I don't get the error, so
it is a bit hard to test. :(

I've split the configure checks into one checking for uint16_t, etc.
and the other checking for macros/function definitions. The reason for
this is that glibc defines macros/functions properly, so we just need
the stdint.h types. I assume this might occur on other systems but
that is just a guess.

For other platforms the configure checks might fail because
function-like macros are used. In that case we can include endian.h
from the system and #undef the macros before our own definition.

Also, double checking that I understand the #include_next idioms would
be appreciated.

Feel free to push this patch if it is okay. I don't want this module
to mess with your CI jobs.

Collin 
From 670b8be73f4b79d4a6993dafcd12ae81721a85b6 Mon Sep 17 00:00:00 2001
From: Collin Funk <collin.fu...@gmail.com>
Date: Sat, 18 May 2024 06:36:55 -0700
Subject: [PATCH] endian: Make sure system headers can be included.

Reported by Bruno Haible in
<https://lists.gnu.org/archive/html/bug-gnulib/2024-05/msg00290.html>.

* lib/endian.in.h (be16toh, be32toh, be64toh, htobe16, htobe32, htobe64)
(le16toh, le32toh, le64toh, htole16, htole32, htole64): Don't define
functions if the system has working versions.
* m4/endian_h.m4 (gl_ENDIAN_H): Separate checks for stdint types and
proper macro/function definitions.
* modules/endian (Depends-on): Add include_next. Update module
dependency conditions.
(Makefile.am): Perform sed replacements on the header substitute.
---
 ChangeLog       | 14 ++++++++++
 lib/endian.in.h | 46 +++++++++++++++++++++++++++++---
 m4/endian_h.m4  | 70 +++++++++++++++++++++++++++++++++++--------------
 modules/endian  | 15 ++++++++---
 4 files changed, 120 insertions(+), 25 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 29adf56ab7..90953430be 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2024-05-18  Collin Funk  <collin.fu...@gmail.com>
+
+	endian: Make sure system headers can be included.
+	Reported by Bruno Haible in
+	<https://lists.gnu.org/archive/html/bug-gnulib/2024-05/msg00290.html>.
+	* lib/endian.in.h (be16toh, be32toh, be64toh, htobe16, htobe32, htobe64)
+	(le16toh, le32toh, le64toh, htole16, htole32, htole64): Don't define
+	functions if the system has working versions.
+	* m4/endian_h.m4 (gl_ENDIAN_H): Separate checks for stdint types and
+	proper macro/function definitions.
+	* modules/endian (Depends-on): Add include_next. Update module
+	dependency conditions.
+	(Makefile.am): Perform sed replacements on the header substitute.
+
 2024-05-18  Bruno Haible  <br...@clisp.org>
 
 	endian tests: Verify that it can be used from C++.
diff --git a/lib/endian.in.h b/lib/endian.in.h
index 5d755fd7cf..65473201ea 100644
--- a/lib/endian.in.h
+++ b/lib/endian.in.h
@@ -17,8 +17,30 @@
 
 /* Written by Collin Funk.  */
 
-#ifndef _GL_ENDIAN_H
-#define _GL_ENDIAN_H 1
+#ifndef _@GUARD_PREFIX@_ENDIAN_H
+
+#if __GNUC__ >= 3
+@PRAGMA_SYSTEM_HEADER@
+#endif
+@PRAGMA_COLUMNS@
+
+#if @HAVE_ENDIAN_H@
+
+/* The include_next requires a split double-inclusion guard.  */
+# @INCLUDE_NEXT@ @NEXT_ENDIAN_H@
+
+#endif
+
+
+/* glibc defines all macros and functions but is missing types from
+   stdint.h.  */
+#if @ENDIAN_H_JUST_MISSING_STDINT@
+# include <stdint.h>
+#else
+
+/* Others platforms.  */
+#ifndef _@GUARD_PREFIX@_ENDIAN_H
+#define _@GUARD_PREFIX@_ENDIAN_H 1
 
 /* This file uses _GL_INLINE, WORDS_BIGENDIAN.  */
 #if !_GL_CONFIG_H_INCLUDED
@@ -47,6 +69,22 @@ _GL_INLINE_HEADER_BEGIN
 # define BYTE_ORDER LITTLE_ENDIAN
 #endif
 
+/* Make sure function-like macros get undefined.  */
+#if @HAVE_ENDIAN_H@
+# undef be16toh
+# undef be32toh
+# undef be64toh
+# undef htobe16
+# undef htobe32
+# undef htobe64
+# undef le16toh
+# undef le32toh
+# undef le64toh
+# undef htole16
+# undef htole32
+# undef htole64
+#endif
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -193,4 +231,6 @@ htole64 (uint64_t x)
 
 _GL_INLINE_HEADER_END
 
-#endif /* _GL_ENDIAN_H */
+#endif /* _@GUARD_PREFIX@_ENDIAN_H */
+#endif /* _@GUARD_PREFIX@_ENDIAN_H */
+#endif /* @ENDIAN_H_JUST_MISSING_STDINT@ */
diff --git a/m4/endian_h.m4 b/m4/endian_h.m4
index ec0d111ae3..29dab603e3 100644
--- a/m4/endian_h.m4
+++ b/m4/endian_h.m4
@@ -1,5 +1,5 @@
 # endian_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,
@@ -12,8 +12,25 @@ AC_DEFUN_ONCE([gl_ENDIAN_H]
   AC_REQUIRE([gl_BIGENDIAN])
 
   AC_CHECK_HEADERS_ONCE([endian.h])
+  gl_CHECK_NEXT_HEADERS([endian.h])
   if test $ac_cv_header_endian_h = yes; then
-    AC_CACHE_CHECK([if endian.h conforms to POSIX],
+    HAVE_ENDIAN_H=1
+    dnl Check if endian.h defines uint16_t, uint32_t, and uint64_t.
+    AC_CACHE_CHECK([if endian.h defines stdint types],
+      [gl_cv_header_endian_h_stdint_types],
+      [AC_COMPILE_IFELSE(
+         [AC_LANG_PROGRAM(
+            [[#include <endian.h>
+            ]],
+            [[uint16_t t1 = 0;
+              uint32_t t2 = 0;
+              uint64_t t3 = 0;
+              return !(t1 + t2 + t3);
+            ]])],
+      [gl_cv_header_endian_h_stdint_types=yes],
+      [gl_cv_header_endian_h_stdint_types=no])
+    ])
+    AC_CACHE_CHECK([if endian.h defines functions and macros],
       [gl_cv_header_working_endian_h],
       [gl_cv_header_working_endian_h=no
        AC_COMPILE_IFELSE(
@@ -29,29 +46,25 @@ AC_DEFUN_ONCE([gl_ENDIAN_H]
 # error "Byte order not defined."
 #endif
 
-/* Check for uint16_t, uint32_t, uint64_t along with
-   byte order conversion functions that accept floating-point
-   arguments.  */
-
 /* Big endian to host.  */
-uint16_t value16_1 = be16toh (0.0);
-uint32_t value32_1 = be32toh (0.0);
-uint64_t value64_1 = be64toh (0.0);
+int value16_1 = be16toh (0.0);
+int value32_1 = be32toh (0.0);
+int value64_1 = be64toh (0.0);
 
 /* Host to big endian.  */
-uint16_t value16_2 = htobe16 (0.0);
-uint32_t value32_2 = htobe32 (0.0);
-uint64_t value64_2 = htobe64 (0.0);
+int value16_2 = htobe16 (0.0);
+int value32_2 = htobe32 (0.0);
+int value64_2 = htobe64 (0.0);
 
 /* Little endian to host.  */
-uint16_t value16_3 = le16toh (0.0);
-uint32_t value32_3 = le32toh (0.0);
-uint64_t value64_3 = le64toh (0.0);
+int value16_3 = le16toh (0.0);
+int value32_3 = le32toh (0.0);
+int value64_3 = le64toh (0.0);
 
 /* Host to little endian.  */
-uint16_t value16_4 = htole16 (0.0);
-uint32_t value32_4 = htole32 (0.0);
-uint64_t value64_4 = htole64 (0.0);
+int value16_4 = htole16 (0.0);
+int value32_4 = htole32 (0.0);
+int value64_4 = htole64 (0.0);
 
 /* Make sure the variables get used.  */
 return !(value16_1 + value32_1 + value64_1
@@ -62,10 +75,29 @@ AC_DEFUN_ONCE([gl_ENDIAN_H]
          [gl_cv_header_working_endian_h=yes],
          [gl_cv_header_working_endian_h=no])
       ])
+  else
+    HAVE_ENDIAN_H=0
   fi
-  if test $gl_cv_header_working_endian_h = yes; then
+
+  dnl Check if endian.h should be generated.
+  if test $gl_cv_header_endian_h_stdint_types = yes \
+     && test $gl_cv_header_working_endian_h = yes; then
     GL_GENERATE_ENDIAN_H=false
   else
     GL_GENERATE_ENDIAN_H=true
   fi
+
+  dnl Check if endian.h works but is missing types from stdint.h.
+  if test $GL_GENERATE_ENDIAN_H; then
+    if test $gl_cv_header_working_endian_h = yes; then
+      ENDIAN_H_JUST_MISSING_STDINT=1
+    else
+      ENDIAN_H_JUST_MISSING_STDINT=0
+    fi
+  else
+    ENDIAN_H_JUST_MISSING_STDINT=0
+  fi
+
+  AC_SUBST([HAVE_ENDIAN_H])
+  AC_SUBST([ENDIAN_H_JUST_MISSING_STDINT])
 ])
diff --git a/modules/endian b/modules/endian
index 9da2d2d19c..203163efe1 100644
--- a/modules/endian
+++ b/modules/endian
@@ -8,8 +8,9 @@ m4/endian_h.m4
 
 Depends-on:
 gen-header
-extern-inline           [$GL_GENERATE_ENDIAN_H]
-byteswap                [$GL_GENERATE_ENDIAN_H]
+include_next
+extern-inline           [$GL_GENERATE_ENDIAN_H && test $ENDIAN_H_JUST_MISSING_STDINT = 0]
+byteswap                [$GL_GENERATE_ENDIAN_H && test $ENDIAN_H_JUST_MISSING_STDINT = 0]
 stdint                  [$GL_GENERATE_ENDIAN_H]
 
 configure.ac:
@@ -25,7 +26,15 @@ BUILT_SOURCES += $(ENDIAN_H)
 if GL_GENERATE_ENDIAN_H
 endian.h: endian.in.h $(top_builddir)/config.status
 @NMD@	$(AM_V_GEN)$(MKDIR_P) '%reldir%'
-	$(gl_V_at)$(SED_HEADER_TO_AT_t) $(srcdir)/endian.in.h
+	$(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|@''HAVE_ENDIAN_H''@|$(HAVE_ENDIAN_H)|g' \
+              -e 's|@''NEXT_ENDIAN_H''@|$(NEXT_ENDIAN_H)|g' \
+              -e 's|@''ENDIAN_H_JUST_MISSING_STDINT''@|$(ENDIAN_H_JUST_MISSING_STDINT)|g' \
+        $(srcdir)/endian.in.h > $@-t
 	$(AM_V_at)mv $@-t $@
 lib_SOURCES += endian.c
 else
-- 
2.45.1

Reply via email to