Repository navigation
[types] Take the C library's types from the system's own headers - #1348
Merged
Merged
Conversation
C and C++ headers rendered for a Linux program defined the C library's types again, which collided with the system's headers wherever the compiler had them, and with what Windows' and macOS' compilers' own headers declare. A program joined to glibc's, bionic's or musl's library (HeaderLibrarySystems.def) now takes those types from that system's headers where the compiler has its C library: a probe defines _GNU_SOURCE, as the libraries were read, and NEVERD_LIBC_FROM_SYSTEM, and the header includes the headers its C library types come from, which the regenerated libraries name before each type (#pragma neverd_header). Everywhere else it defines them itself, renaming those the compiler's own headers may declare otherwise for its definitions (PreludeNames.def) and undefining member names a C library defines as macros meanwhile. So that its layouts hold on other compilers: a record a typedef names is declared and named by the typedef; an i386 record holding eight-byte scalars takes pack(4), which the parser reads back as none; GNU's bit-fields take gcc_struct under MinGW; an array of an unknown record is said in a comment. Python's __int128 takes C's alignment. The C API and CLI take the system library, the checker compiles each library on its own system and on the others, and the fetch script fetches zig and the generator's sources.
This was referenced Oct 18, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
C and C++ headers rendered for a Linux program defined the C library's own types again. They collided with the system headers wherever the compiler had them. Examples: C++'s
struct __fsid_tagainst glibc's typedef of an anonymous record, and a 32-bit__off_tthat islongin glibc butint32_tin the portable spelling. On Windows and macOS, the same types collided with what those compilers' own headers declare.A program joined to glibc's, bionic's or musl's library (
HeaderLibrarySystems.def) now gets a header that takes those types from the system's own headers where the compiler has that C library. Everywhere else, Windows and macOS among them, it defines them itself.Which types are the C library's. Any type whose name the joined library has, including the program's own DWARF definition of it (
struct stat).On the system. A probe ahead of every include defines
_GNU_SOURCE, as the libraries were read, and thenNEVERD_LIBC_FROM_SYSTEM, when all of these hold:__GLIBC__,__BIONIC__, or neither for musl).The probe fails clearly when glibc's or bionic's headers were read earlier without
_GNU_SOURCE.NEVERD_OWN_LIBC_TYPESasks for the header's own definitions instead.There, the header includes only the headers its C library types come from:
generate_linux_types.pyfollows the preprocessor's include stack and writes#pragma neverd_header("stdio.h")before each declaration, naming the unit header that brought it in;LocalType::Header);NEVERD_GNU_STRUCTand the member macros' guards.The library's prototypes are declared only where the system's headers do not declare them.
Elsewhere. The definitions stand, but the compiler's own headers may declare some of their names otherwise (
PreludeNames.def):bits/types.h, macOS's__mbstate_t), C's<stddef.h>and<stdint.h>names, and what the Windows C runtimes'<corecrt.h>declares (time_t,wint_t). The header uses#define X neverd_X, restored withpush_macro/pop_macro, so the program's layouts hold and the names stay the compiler's afterwards. The C parser reads these renames as the system's own names.<sys/cdefs.h>defines as macros (__unusedon macOS and bionic).__SOCKADDR_ARGotherwise.Layouts that hold on other compilers.
typedef struct { ... } X, ortypedef struct X X) is declaredtypedef struct X X;and namedX, as the system's headers name it.LocalType::TypedefNamedcomes from the C parser and the DWARF import.#pragma pack(push, 4). That changes nothing on i386 and keeps the layout where compilers align them to eight. The parser reads a pack of the ABI's own limit that changes no layout as no pack.NEVERD_GNU_STRUCT, which is MinGW'sgcc_struct.jmp_buf) is written as a comment, as are the prototypes that take it.__int128gets an aligned class, aslong doublehas. Before, a record holding one was too small on ARM64.Interfaces.
"systemLibrary"(by default the library the program joins;falsefor none) and"headerPragmas".neverd types --system-library,--header-pragmas.fetch_render_toolchains.pyalso fetches zig (macOS's and musl's headers), libnativehelper and system/logging at the Android libraries' commits, and musl 1.2.5 (SHA-256 matching Debian's copy), which the generator reads.check_type_renders.py --system-librarycompiles every spelling on the library's own system, and its portable C on every other system of its pointer width.Verification
check_type_renders.py --system-libraryon all 12 libraries. Each library's own system compiles every spelling:Its portable C compiles, defining the C library's types, on:
_IO_FILE,fenv_t)A glibc program's header, compiled for every target.
linux_libc_calls_x64andlinux_libc_calls_x86, with checks and prototypes, compile with 0 errors on:NEVERD_OWN_LIBC_TYPES;MSVC fails only the two bit-field records. In C, the prototypes there warn where they redeclare routines the compiler knows otherwise, such as
vprintfwith itsva_list.Tests.
SessionCAPITest.TheCLibrarysTypesComeFromTheSystemsHeaders(DWARF objectsdwarf_libc.{x64,x86}.o, built asdwarf_libc.csays),TypeRender.TheCLibrarysTypesComeFromItsHeadersOnItsSystem,TypeRender.RecordsATypedefNamesGoByThatName,TypeRender.I386RecordsLayOutAsI386OnEveryCompiler,TypeRender.ChecksLeaveTheFillersOut,TypeParse.HeaderPragmasNameTheSystemHeaderOfTheTypesAfterThem,TypeParse.AHeadersOwnRenamesLeaveTheSystemsNames,TypeParse.APackOfTheABIsOwnLimitIsNoPacking.SessionCAPITest.ThirtyTwoBitLinuxObjectsLayRecordsOutAsGCCDoesnow expects i386's pack.Limitations
_IO_FILEandfenv_tand musl'sfenv_ttake another layout there, which the checks report.tagLC_IDunder MinGW) and macOS's libSystem; the next change does those.