[libc] Add public_includes stanza to hdrgen and use it in socket headers (#205543)

This patch adds support for a public_includes stanza in header YAML
files, allowing generated public headers to include other public
headers.

I use this to make arpa/inet.h include netinet/in.h, and netinet/in.h
include sys/socket.h. While POSIX doesn't strictly require these headers
to include each other, it permits it, and many real-world applications
depend on this behavior.

To make this work, I also needed to reorder the header targets in
include/CMakeLists.txt so that targets sys_socket and netinet_in are
defined before targets declare dependencies on them.

There are a couple of other files that could use this feature (right now
they handle it through the header template), but I'll do that as a
separate patch.

Assisted by Gemini.
This commit is contained in:
Pavel Labath authored and GitHub committed 2026-06-29 08:13:17 +02:00
1 parent bac7ca5f17
commit 2bd8d73902
7 files changed
+89 -59

No files matched your search

+60 -57
View File
@@ -203,63 +203,6 @@ add_header_macro(
.llvm-libc-macros.sysexits_macros
)
# TODO: This should be conditional on POSIX networking being included.
file(MAKE_DIRECTORY ${LIBC_INCLUDE_DIR}/arpa)
add_header_macro(
arpa_inet
../libc/include/arpa/inet.yaml
arpa/inet.h
DEPENDS
.llvm_libc_common_h
.inttypes
.llvm-libc-types.in_addr_t
.llvm-libc-types.struct_in_addr
.llvm-libc-macros.inet_address_macros
)
file(MAKE_DIRECTORY ${LIBC_INCLUDE_DIR}/netinet)
add_header_macro(
netinet_in
../libc/include/netinet/in.yaml
netinet/in.h
DEPENDS
.llvm-libc-macros.netinet_in_macros
.llvm-libc-macros.inet_address_macros
.llvm-libc-types.in_addr_t
.llvm-libc-types.in_port_t
.llvm-libc-types.sa_family_t
.llvm-libc-types.struct_sockaddr_in
.llvm-libc-types.struct_sockaddr_in6
.llvm-libc-types.struct_in_addr
.llvm-libc-types.struct_in6_addr
.llvm-libc-types.struct_ip_mreq
.llvm-libc-types.struct_ip_mreq_source
.llvm-libc-types.struct_ip_mreqn
.llvm-libc-types.struct_ip_msfilter
.llvm-libc-types.struct_ip_opts
.llvm_libc_common_h
)
add_header_macro(
netinet_tcp
../libc/include/netinet/tcp.yaml
netinet/tcp.h
DEPENDS
.llvm_libc_common_h
)
add_header_macro(
netinet_udp
../libc/include/netinet/udp.yaml
netinet/udp.h
DEPENDS
.llvm-libc-types.struct_udphdr
.llvm_libc_common_h
)
add_header_macro(
assert
../libc/include/assert.yaml
@@ -952,6 +895,66 @@ add_header_macro(
.llvm-libc-types.siginfo_t
)
# TODO: This should be conditional on POSIX networking being included.
file(MAKE_DIRECTORY ${LIBC_INCLUDE_DIR}/netinet)
add_header_macro(
netinet_in
../libc/include/netinet/in.yaml
netinet/in.h
DEPENDS
.llvm-libc-macros.netinet_in_macros
.llvm-libc-macros.inet_address_macros
.llvm-libc-types.in_addr_t
.llvm-libc-types.in_port_t
.llvm-libc-types.sa_family_t
.llvm-libc-types.struct_sockaddr_in
.llvm-libc-types.struct_sockaddr_in6
.llvm-libc-types.struct_in_addr
.llvm-libc-types.struct_in6_addr
.llvm-libc-types.struct_ip_mreq
.llvm-libc-types.struct_ip_mreq_source
.llvm-libc-types.struct_ip_mreqn
.llvm-libc-types.struct_ip_msfilter
.llvm-libc-types.struct_ip_opts
.llvm_libc_common_h
.sys_socket
)
add_header_macro(
netinet_tcp
../libc/include/netinet/tcp.yaml
netinet/tcp.h
DEPENDS
.llvm_libc_common_h
)
add_header_macro(
netinet_udp
../libc/include/netinet/udp.yaml
netinet/udp.h
DEPENDS
.llvm-libc-types.struct_udphdr
.llvm_libc_common_h
)
file(MAKE_DIRECTORY ${LIBC_INCLUDE_DIR}/arpa)
add_header_macro(
arpa_inet
../libc/include/arpa/inet.yaml
arpa/inet.h
DEPENDS
.inttypes
.llvm_libc_common_h
.llvm-libc-types.in_addr_t
.llvm-libc-types.in_port_t
.llvm-libc-types.socklen_t
.llvm-libc-types.struct_in_addr
.llvm-libc-macros.inet_address_macros
.netinet_in
)
add_header_macro(
termios
../libc/include/termios.yaml
+11
View File
@@ -3,13 +3,24 @@ standards:
- posix
merge_yaml_files:
- ../htons-family.yaml
public_includes:
# This is permitted (but not required) by POSIX and many applications depend
# on it. If we have a "pedantic" mode in the future, we might want to exclude
# it there.
- netinet/in.h
macros:
# Macros also defined by netinet/in.h, but listing them explicitly as they are
# required by POSIX.
- macro_name: INET_ADDRSTRLEN
macro_header: inet-address-macros.h
- macro_name: INET6_ADDRSTRLEN
macro_header: inet-address-macros.h
types:
# Types also defined by netinet/in.h, but listing them explicitly as they are
# required by POSIX.
- type_name: in_port_t
- type_name: in_addr_t
- type_name: socklen_t
- type_name: struct_in_addr
enums: []
objects: []
+8 -1
View File
@@ -3,6 +3,11 @@ standards:
- posix
merge_yaml_files:
- ../htons-family.yaml
public_includes:
# This is permitted (but not required) by POSIX and many applications depend
# on it. If we have a "pedantic" mode in the future, we might want to exclude
# it there.
- sys/socket.h
macros:
- macro_name: IPPROTO_IP
macro_header: netinet-in-macros.h
@@ -103,7 +108,6 @@ macros:
types:
- type_name: in_port_t
- type_name: in_addr_t
- type_name: sa_family_t
- type_name: struct_sockaddr_in
- type_name: struct_sockaddr_in6
- type_name: struct_in_addr
@@ -113,6 +117,9 @@ types:
- type_name: struct_ip_mreqn
- type_name: struct_ip_msfilter
- type_name: struct_ip_opts
# Type also defined by sys/socket.h, but listing it explicitly as it is
# required by POSIX.
- type_name: sa_family_t
enums: []
objects:
- object_name: in6addr_any
+6 -1
View File
@@ -116,6 +116,7 @@ class HeaderFile:
self.standards = []
self.merge_yaml_files = []
self.license_text = []
self.public_includes = []
def add_macro(self, macro):
self.macros.append(macro)
@@ -139,6 +140,9 @@ class HeaderFile:
self.objects = sorted(set(self.objects) | set(other.objects))
self.functions = sorted(set(self.functions) | set(other.functions))
self.extra_standards |= other.extra_standards
self.public_includes = sorted(
set(self.public_includes) | set(other.public_includes)
)
if self.license_text:
assert not other.license_text, "only one `license_text` allowed"
else:
@@ -183,7 +187,8 @@ class HeaderFile:
def includes(self):
return (
{
{f"<{inc}>" for inc in self.public_includes}
| {
PurePosixPath("llvm-libc-macros") / macro.header
for macro in self.macros
if macro.header is not None
@@ -39,6 +39,7 @@ def yaml_to_classes(yaml_data, header_class, entry_points=None):
header.extra_standards = yaml_data.get("extra_standards", {})
header.license_text = yaml_data.get("license_text", [])
header.merge_yaml_files = yaml_data.get("merge_yaml_files", [])
header.public_includes = yaml_data.get("public_includes", [])
for macro_data in yaml_data.get("macros", []):
macro = Macro(
@@ -11,6 +11,7 @@
#include "__llvm-libc-common.h"
#include "llvm-libc-types/meep.h"
#include "llvm-libc-types/road.h"
#include <acme/anvil.h>
__BEGIN_C_DECLS
@@ -4,6 +4,8 @@ merge_yaml_files:
header: custom.h
standards:
- acme
public_includes:
- acme/anvil.h
functions:
- name: runner