Skip to main content

Module merge

Module merge 

Source
Expand description

One header, merged across every release that has it.

Design: spec/cross-compile/08-sysroots.md section 8.3. The shape of the answer is Zig’s generic-glibc, which is one tree with the per-version differences written inside the files as conditionals on __GLIBC_MINOR__, and the technique for deriving one rather than maintaining it by hand is ziglang/universal-headers, which document 01.2 records as the state of the art and as unfinished.

§What a merge is allowed to do

Write text that every release shipped, and conditionals around the text that only some of them shipped. That is all. It never edits a declaration, never reflows anything and never invents a line, with one exception that is not an exception so much as a requirement: glibc’s own definition of __GLIBC_MINOR__ has to go, because the compiler is what defines it in a merged tree, and what replaces it is a check that somebody did.

§The two ways cutting a file up can break it

A conditional put in the wrong place turns a working header into one that does not compile, or worse into one that compiles differently, so both ways are checked rather than avoided by being careful.

The first is a piece that cannot be split, which is a macro or a directive continued with a backslash, or a line whose trailing comment closes further down. norm::pieces is what makes that impossible: the smallest thing the merge can put a conditional between is a logical line.

The second is a piece that is part of the file’s own conditional. A region that contains an #endif whose #if is above it, or an #else belonging to an #if above it, cannot be wrapped in an #if of ours: our #endif would close theirs, or their #else would become ours.

The answer to the second one is to make the region bigger until it holds the whole of whatever it was reaching into, and the region says which way to grow rather than being searched for. A branch that closes an #if from above needs the text above it, a branch that leaves an #if of its own open needs the text below it, and growing stops as soon as no branch reaches out. Growing upward takes back a region already decided, which is the one place a decision here is reconsidered. A file where the region grows to the whole file is one copy per release, which is how this started and is still the answer for a file whose releases disagree about where their own conditionals are.

§Why it reads its own output back

Because the only statement worth making about a merged tree is that it is the releases it was merged from, and the way to say that is to take it apart again. Every file, for every release that has it, is evaluated at that release’s version and held against what that release shipped. A merge that cannot reproduce its inputs is a bug in this file, and the check runs before the tree is written rather than in a test over a fixture, because the fixture that matters is glibc.

Structs§

Merged
One merged header.

Enums§

Kind
What the merge had to do to one file.

Constants§

GUARD
What replaces glibc’s own definition of the version macro.

Functions§

one
Merges one header. texts has one entry per release, None where that release does not have it.