[PATCH][RFC] libstdc++ Provide <cerrno> and <errno.h> for freestanding

Jonathan Wakely <[email protected]> Mon, 3 Aug 2026 17:55:57 +0100
Newsgroups gmane.comp.gcc.patches,gmane.comp.gcc.libstdc++.devel
Message-ID <[email protected]>
The <cerrno> header is freestanding in C++26. Since we don't have to be
compatible with a C library or a kernel for freestanding, we can just
define the error number macros to arbitrary values.

We need to provide a consistent set of definitions whether <cerrno> or
<errno.h> is included, and whether a freestanding header is included by
using -ffreestanding with a full hosted installation, or with a
non-hosted (i.e. --disable-hosted-libstdcxx) installation. We do not
want a situation where including <errno.h> uses a system libc header and
defines one set of values, but <cerrno> provides our own freestanding
values.

The approach taken here is to install our own copy of <errno.h> which
does #include_next <errno.h> for hosted and which defines its own values
for freestanding. Our <cerrno> will then find our own <errno.h> and so
<cerrno> and <errno.h> will be consistent, and the macro values will
always be the same for the freestanding headers.

libstdc++-v3/ChangeLog:

	* include/Makefile.am (c_base_freestanding): Move cerrno to
	here from ...
	(c_base_headers): ... here.
	(c_compatibility_headers): Add errno.h.
	* include/Makefile.in: Regenerate.
	* include/c_compatibility/errno.h: Replace include <cerrno> with
	include_next <errno.h>.
	[!_GLIBCXX_HOSTED] (E2BIG,EACCES,EADDRINUSE,EADDRNOTAVAIL)
	(EAFNOSUPPORT,EAGAIN,EALREADY,EBADF,EBADMSG,EBUSY,ECANCELED)
	(ECHILD,ECONNABORTED,ECONNREFUSED,ECONNRESET,EDEADLK)
	(EDESTADDRREQ,EDOM,EEXIST,EFAULT,EFBIG,EHOSTUNREACH,EIDRM)
	(EILSEQ,EINPROGRESS,EINTR,EINVAL,EIO,EISCONN,EISDIR,ELOOP)
	(EMFILE,EMLINK,EMSGSIZE,ENAMETOOLONG,ENETDOWN,ENETRESET)
	(ENETUNREACH,ENFILE,ENOBUFS,ENODEV,ENOENT,ENOEXEC,ENOLCK)
	(ENOLINK,ENOMEM,ENOMSG,ENOPROTOOPT,ENOSPC,ENOSYS,ENOTCONN)
	(ENOTDIR,ENOTEMPTY,ENOTRECOVERABLE,ENOTSOCK,ENOTSUP,ENOTTY)
	(ENXIO,EOPNOTSUPP,EOVERFLOW,EOWNERDEAD,EPERM,EPIPE,EPROTO)
	(EPROTONOSUPPORT,EPROTOTYPE,ERANGE,EROFS,ESPIPE,ESRCH)
	(ETIMEDOUT,ETXTBSY,EWOULDBLOCK,EXDEV): Define.
---

I don't really like this patch, but sending it for comment.

Every time we add our own <name.h> C header it complicates things, and
we have various bug reports (and patches) related to those files causing
problems during bootstrap of obscure canadian-cross configurations.

So I'm a bit concerned that adding <errno.h> just for Freestanding would
end up causing regressions that affect Hosted builds too.


 libstdc++-v3/include/Makefile.am             |  3 +-
 libstdc++-v3/include/Makefile.in             |  3 +-
 libstdc++-v3/include/c_compatibility/errno.h | 91 +++++++++++++++++++-
 3 files changed, 94 insertions(+), 3 deletions(-)

diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index 3c30aa21d6b5..18bb9f224563 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -902,6 +902,7 @@ endif
 c_base_srcdir = $(C_INCLUDE_DIR)
 c_base_builddir = .
 c_base_freestanding = \
+	${c_base_srcdir}/cerrno \
 	${c_base_srcdir}/cfloat \
 	${c_base_srcdir}/climits \
 	${c_base_srcdir}/cstdalign \
@@ -919,7 +920,6 @@ c_base_headers = \
 	${c_base_srcdir}/cassert \
 	${c_base_srcdir}/ccomplex \
 	${c_base_srcdir}/cctype \
-	${c_base_srcdir}/cerrno \
 	${c_base_srcdir}/cfenv \
 	${c_base_srcdir}/cinttypes \
 	${c_base_srcdir}/ciso646 \
@@ -947,6 +947,7 @@ endif
 if GLIBCXX_C_HEADERS_C_GLOBAL
 c_compatibility_headers = \
 	${c_compatibility_srcdir}/complex.h \
+	${c_compatibility_srcdir}/errno.h \
 	${c_compatibility_srcdir}/fenv.h \
 	${c_compatibility_srcdir}/tgmath.h \
 	${c_compatibility_srcdir}/math.h \
diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
index d081481293ff..feb6665ca401 100644
--- a/libstdc++-v3/include/Makefile.in
+++ b/libstdc++-v3/include/Makefile.in
@@ -1250,6 +1250,7 @@ experimental_bits_headers = \
 c_base_srcdir = $(C_INCLUDE_DIR)
 c_base_builddir = .
 c_base_freestanding = \
+	${c_base_srcdir}/cerrno \
 	${c_base_srcdir}/cfloat \
 	${c_base_srcdir}/climits \
 	${c_base_srcdir}/cstdalign \
@@ -1265,7 +1266,6 @@ c_base_freestanding = \
 @GLIBCXX_HOSTED_TRUE@	${c_base_srcdir}/cassert \
 @GLIBCXX_HOSTED_TRUE@	${c_base_srcdir}/ccomplex \
 @GLIBCXX_HOSTED_TRUE@	${c_base_srcdir}/cctype \
-@GLIBCXX_HOSTED_TRUE@	${c_base_srcdir}/cerrno \
 @GLIBCXX_HOSTED_TRUE@	${c_base_srcdir}/cfenv \
 @GLIBCXX_HOSTED_TRUE@	${c_base_srcdir}/cinttypes \
 @GLIBCXX_HOSTED_TRUE@	${c_base_srcdir}/ciso646 \
@@ -1287,6 +1287,7 @@ c_compatibility_srcdir = ${glibcxx_srcdir}/include/c_compatibility
 c_compatibility_builddir = .
 @GLIBCXX_C_HEADERS_C_GLOBAL_TRUE@c_compatibility_headers = \
 @GLIBCXX_C_HEADERS_C_GLOBAL_TRUE@	${c_compatibility_srcdir}/complex.h \
+@GLIBCXX_C_HEADERS_C_GLOBAL_TRUE@	${c_compatibility_srcdir}/errno.h \
 @GLIBCXX_C_HEADERS_C_GLOBAL_TRUE@	${c_compatibility_srcdir}/fenv.h \
 @GLIBCXX_C_HEADERS_C_GLOBAL_TRUE@	${c_compatibility_srcdir}/tgmath.h \
 @GLIBCXX_C_HEADERS_C_GLOBAL_TRUE@	${c_compatibility_srcdir}/math.h \
diff --git a/libstdc++-v3/include/c_compatibility/errno.h b/libstdc++-v3/include/c_compatibility/errno.h
index 07e3c17e9173..3eea20e081bb 100644
--- a/libstdc++-v3/include/c_compatibility/errno.h
+++ b/libstdc++-v3/include/c_compatibility/errno.h
@@ -29,6 +29,95 @@
 #ifndef _GLIBCXX_ERRNO_H
 #define _GLIBCXX_ERRNO_H 1
 
-#include <cerrno>
+#include <bits/c++config.h>
+
+#if _GLIBCXX_HOSTED
+#include_next <errno.h>
+// Adhere to section 17.4.1.2 clause 5 of ISO 14882:1998
+#ifndef errno
+#define errno errno
+#endif
+
+#else
+__thread inline int __errno_v = 0;
+
+#define errno __errno_v
+
+#define E2BIG  10007
+#define EACCES  10013
+#define EADDRINUSE  10098
+#define EADDRNOTAVAIL  10099
+#define EAFNOSUPPORT  10097
+#define EAGAIN  10011
+#define EALREADY  10114
+#define EBADF  10009
+#define EBADMSG  10074
+#define EBUSY  10016
+#define ECANCELED  10125
+#define ECHILD  10010
+#define ECONNABORTED  10103
+#define ECONNREFUSED  10111
+#define ECONNRESET  10104
+#define EDEADLK  10035
+#define EDESTADDRREQ  10089
+#define EDOM  10033
+#define EEXIST  10017
+#define EFAULT  10014
+#define EFBIG  10027
+#define EHOSTUNREACH  10113
+#define EIDRM  10043
+#define EILSEQ  10084
+#define EINPROGRESS  10115
+#define EINTR  10004
+#define EINVAL  10022
+#define EIO  10005
+#define EISCONN  10106
+#define EISDIR  10021
+#define ELOOP  10040
+#define EMFILE  10024
+#define EMLINK  10031
+#define EMSGSIZE  10090
+#define ENAMETOOLONG  10036
+#define ENETDOWN  10100
+#define ENETRESET  10102
+#define ENETUNREACH  10101
+#define ENFILE  10023
+#define ENOBUFS  10105
+#define ENODEV  10019
+#define ENOENT  10002
+#define ENOEXEC  10008
+#define ENOLCK  10037
+#define ENOLINK  10067
+#define ENOMEM  10012
+#define ENOMSG  10042
+#define ENOPROTOOPT  10092
+#define ENOSPC  10028
+#define ENOSYS  10038
+#define ENOTCONN  10107
+#define ENOTDIR  10020
+#define ENOTEMPTY  10039
+#define ENOTRECOVERABLE  10131
+#define ENOTSOCK  10088
+#define ENOTSUP  10095
+#define ENOTTY  10025
+#define ENXIO  10006
+#define EOPNOTSUPP  10095
+#define EOVERFLOW  10075
+#define EOWNERDEAD  10130
+#define EPERM  10001
+#define EPIPE  10032
+#define EPROTO  10071
+#define EPROTONOSUPPORT  10093
+#define EPROTOTYPE  10091
+#define ERANGE  10034
+#define EROFS  10030
+#define ESPIPE  10029
+#define ESRCH  10003
+#define ETIMEDOUT  10110
+#define ETXTBSY  10026
+#define EWOULDBLOCK  10011
+#define EXDEV  10018
+
+#endif // HOSTED
 
 #endif
-- 
2.55.0