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 */
