The typical hairy error within include files is that an overridden
include file A includes B, which itself requires A and fails if A is only
partially (i.e. not yet completely) included.

When the only reason for A to include B is some macros which are not otherwise
used within other header files, this hairy situation can be avoided by moving
the '#include B' to the end of A.

There are a few places where this can be done:


2025-08-15  Bruno Haible  <[email protected]>

        Reduce risk of compilation errors within include files.
        * lib/dirent.in.h: Move include <sys/stat.h> near the end of the file.
        * lib/stdlib.in.h: Move include <sys/wait.h> near the end of the file.
        * lib/sys_select.in.h: Move include <string.h> near the end of the file.
        * lib/unistd.in.h: Add comment.

diff --git a/lib/dirent.in.h b/lib/dirent.in.h
index 9d3bffa97f..e6c59e5a41 100644
--- a/lib/dirent.in.h
+++ b/lib/dirent.in.h
@@ -101,40 +101,6 @@ static_assert (DT_UNKNOWN != DT_FIFO && DT_UNKNOWN != 
DT_CHR
 /* Other optional information about a directory entry.  */
 #define _GL_DT_NOTDIR 0x100   /* Not a directory */
 
-/* Conversion between S_IF* and DT_* file types.  */
-#if ! (defined IFTODT && defined DTTOIF)
-# include <sys/stat.h>
-# ifdef S_ISWHT
-#  define _GL_DIRENT_S_ISWHT(mode) S_ISWHT(mode)
-# else
-#  define _GL_DIRENT_S_ISWHT(mode) 0
-# endif
-# ifdef S_IFWHT
-#  define _GL_DIRENT_S_IFWHT S_IFWHT
-# else
-#  define _GL_DIRENT_S_IFWHT (DT_WHT << 12) /* just a guess */
-# endif
-#endif
-/* Conversion from a 'stat' mode to a DT_* value.  */
-#ifndef IFTODT
-# define IFTODT(mode) \
-   (S_ISREG (mode) ? DT_REG : S_ISDIR (mode) ? DT_DIR \
-    : S_ISLNK (mode) ? DT_LNK : S_ISBLK (mode) ? DT_BLK \
-    : S_ISCHR (mode) ? DT_CHR : S_ISFIFO (mode) ? DT_FIFO \
-    : S_ISSOCK (mode) ? DT_SOCK \
-    : _GL_DIRENT_S_ISWHT (mode) ? DT_WHT : DT_UNKNOWN)
-#endif
-/* Conversion from a DT_* value to a 'stat' mode.  */
-#ifndef DTTOIF
-# define DTTOIF(dirtype) \
-   ((dirtype) == DT_REG ? S_IFREG : (dirtype) == DT_DIR ? S_IFDIR \
-    : (dirtype) == DT_LNK ? S_IFLNK : (dirtype) == DT_BLK ? S_IFBLK \
-    : (dirtype) == DT_CHR ? S_IFCHR :  dirtype == DT_FIFO ? S_IFIFO \
-    : (dirtype) == DT_SOCK ? S_IFSOCK \
-    : (dirtype) == DT_WHT ? _GL_DIRENT_S_IFWHT \
-    : (dirtype) << 12 /* just a guess */)
-#endif
-
 #if !@DIR_HAS_FD_MEMBER@
 # if !GNULIB_defined_DIR
 /* struct gl_directory is a type with a field 'int fd_to_close'.
@@ -426,5 +392,44 @@ _GL_WARN_ON_USE (alphasort, "alphasort is unportable - "
 #endif
 
 
+/* Includes that provide only macros that don't need to be overridden.
+   (Includes that are needed for type definitions and function declarations
+   have their place above, before the function overrides.)  */
+
+/* Conversion between S_IF* and DT_* file types.  */
+#if ! (defined IFTODT && defined DTTOIF)
+# include <sys/stat.h>
+# ifdef S_ISWHT
+#  define _GL_DIRENT_S_ISWHT(mode) S_ISWHT(mode)
+# else
+#  define _GL_DIRENT_S_ISWHT(mode) 0
+# endif
+# ifdef S_IFWHT
+#  define _GL_DIRENT_S_IFWHT S_IFWHT
+# else
+#  define _GL_DIRENT_S_IFWHT (DT_WHT << 12) /* just a guess */
+# endif
+#endif
+/* Conversion from a 'stat' mode to a DT_* value.  */
+#ifndef IFTODT
+# define IFTODT(mode) \
+   (S_ISREG (mode) ? DT_REG : S_ISDIR (mode) ? DT_DIR \
+    : S_ISLNK (mode) ? DT_LNK : S_ISBLK (mode) ? DT_BLK \
+    : S_ISCHR (mode) ? DT_CHR : S_ISFIFO (mode) ? DT_FIFO \
+    : S_ISSOCK (mode) ? DT_SOCK \
+    : _GL_DIRENT_S_ISWHT (mode) ? DT_WHT : DT_UNKNOWN)
+#endif
+/* Conversion from a DT_* value to a 'stat' mode.  */
+#ifndef DTTOIF
+# define DTTOIF(dirtype) \
+   ((dirtype) == DT_REG ? S_IFREG : (dirtype) == DT_DIR ? S_IFDIR \
+    : (dirtype) == DT_LNK ? S_IFLNK : (dirtype) == DT_BLK ? S_IFBLK \
+    : (dirtype) == DT_CHR ? S_IFCHR :  dirtype == DT_FIFO ? S_IFIFO \
+    : (dirtype) == DT_SOCK ? S_IFSOCK \
+    : (dirtype) == DT_WHT ? _GL_DIRENT_S_IFWHT \
+    : (dirtype) << 12 /* just a guess */)
+#endif
+
+
 #endif /* _@GUARD_PREFIX@_DIRENT_H */
 #endif /* _@GUARD_PREFIX@_DIRENT_H */
diff --git a/lib/stdlib.in.h b/lib/stdlib.in.h
index 1342db4877..d74db3c7c7 100644
--- a/lib/stdlib.in.h
+++ b/lib/stdlib.in.h
@@ -62,12 +62,6 @@
 /* NetBSD 5.0 mis-defines NULL.  */
 #include <stddef.h>
 
-/* MirBSD 10 defines WEXITSTATUS in <sys/wait.h>, not in <stdlib.h>.
-   glibc 2.41 defines WCOREDUMP in <sys/wait.h>, not in <stdlib.h>.  */
-#if @GNULIB_SYSTEM_POSIX@ && !(defined WEXITSTATUS && defined WCOREDUMP)
-# include <sys/wait.h>
-#endif
-
 /* Solaris declares getloadavg() in <sys/loadavg.h>.  */
 #if (@GNULIB_GETLOADAVG@ || defined GNULIB_POSIXCHECK) && @HAVE_SYS_LOADAVG_H@
 /* OpenIndiana has a bug: <sys/time.h> must be included before
@@ -2027,6 +2021,18 @@ _GL_CXXALIASWARN (wctomb);
 
 _GL_INLINE_HEADER_END
 
+
+/* Includes that provide only macros that don't need to be overridden.
+   (Includes that are needed for type definitions and function declarations
+   have their place above, before the function overrides.)  */
+
+/* MirBSD 10 defines WEXITSTATUS in <sys/wait.h>, not in <stdlib.h>.
+   glibc 2.41 defines WCOREDUMP in <sys/wait.h>, not in <stdlib.h>.  */
+#if @GNULIB_SYSTEM_POSIX@ && !(defined WEXITSTATUS && defined WCOREDUMP)
+# include <sys/wait.h>
+#endif
+
+
 #endif /* _@GUARD_PREFIX@_STDLIB_H */
 #endif /* _@GUARD_PREFIX@_STDLIB_H */
 #endif
diff --git a/lib/sys_select.in.h b/lib/sys_select.in.h
index a06725020d..c10f8f9de7 100644
--- a/lib/sys_select.in.h
+++ b/lib/sys_select.in.h
@@ -101,14 +101,6 @@
 #  include <sys/time.h>
 # endif
 
-/* On AIX 7 and Solaris 10, <sys/select.h> provides an FD_ZERO implementation
-   that relies on memset(), but without including <string.h>.
-   But in any case avoid namespace pollution on glibc systems.  */
-# if (defined __OpenBSD__ || defined _AIX || defined __sun || defined __osf__ 
|| defined __BEOS__) \
-     && ! defined __GLIBC__
-#  include <string.h>
-# endif
-
 /* The include_next requires a split double-inclusion guard.  */
 # @INCLUDE_NEXT@ @NEXT_SYS_SELECT_H@
 
@@ -352,5 +344,20 @@ _GL_WARN_ON_USE (select, "select is not always POSIX 
compliant - "
 
 
 #endif /* _@GUARD_PREFIX@_SYS_SELECT_H */
+
+
+/* Includes that provide only macros that don't need to be overridden.
+   (Includes that are needed for type definitions and function declarations
+   have their place above, before the function overrides.)  */
+
+/* On AIX 7 and Solaris 10, <sys/select.h> provides an FD_ZERO implementation
+   that relies on memset(), but without including <string.h>.
+   But in any case avoid namespace pollution on glibc systems.  */
+# if (defined __OpenBSD__ || defined _AIX || defined __sun || defined __osf__ 
|| defined __BEOS__) \
+     && ! defined __GLIBC__
+#  include <string.h>
+# endif
+
+
 #endif /* _@GUARD_PREFIX@_SYS_SELECT_H */
 #endif /* OSF/1 */
diff --git a/lib/unistd.in.h b/lib/unistd.in.h
index 0cf2728020..ea221481f8 100644
--- a/lib/unistd.in.h
+++ b/lib/unistd.in.h
@@ -2490,12 +2490,18 @@ _GL_CXXALIASWARN (write);
 
 _GL_INLINE_HEADER_END
 
+
+/* Includes that provide only macros that don't need to be overridden.
+   (Includes that are needed for type definitions and function declarations
+   have their place above, before the function overrides.)  */
+
 /* FreeBSD 14.0, NetBSD 10.0, OpenBSD 7.5, Solaris 11.4, and glibc 2.41
    do not define O_CLOEXEC in <unistd.h>.  */
 #if ! defined O_CLOEXEC
 # include <fcntl.h>
 #endif
 
+
 #endif /* _@GUARD_PREFIX@_UNISTD_H */
 #endif /* _GL_INCLUDING_UNISTD_H */
 #endif /* _@GUARD_PREFIX@_UNISTD_H */




Reply via email to