On 11/6/26 1:46 PM, Camm Maguire wrote:
Greetings, again!
Raymond Toy<[email protected]> writes:
Anyway, perhaps Claude can think of something and save us some time.
I very briefly skimmed the log. Not sure what I’m looking for or if AI could
help figure out the underlying option.
I personally don’t care about parallel builds, if we’re talking about
building gcl. It is kind of slow, but I rarely ever build gcl. I guess
that’s different for you.
Alas, the issue here is not build time, but build reproducibility,
an upcoming Debian requirement. I have about 6 months to figure out
why setting SOURCE_DATE_EPOCH to a known constant and repeating the
build does not generate the same result. Can Claude help with that?
That’s a more concrete question that I could ask Claude about. I’ll let
you know if I get anything or get stuck.
Well, that was quick. Here is what Claude said. Don’t know if that helps
you in any way. Feel free to ask more questions. And you do know that
Claude has a free tier, right? It’s pretty capable and can do a lot
before you run into limits.
|SOURCE_DATE_EPOCH| only fixes timestamps. Most of GCL’s non-determinism
comes from how its images are made: the final |saved_gcl| /
|saved_ansi_gcl| is a dump of a running process’s memory. Anything that
varies between runs and lands in the heap ends up in the binary.
Usual culprits
1.
*The image is an unexec’d heap.*
GCL builds the system by starting a raw image, loading compiled |.o|
files with its own loader, and dumping memory with |save-system|
(unexec). Byte-identical output requires every allocation, GC, and
stray value to come out the same in both runs. That’s a much
stronger requirement than deterministic compilation.
2.
*Address-space variation.*
GCL tries to disable ASLR (|personality(ADDR_NO_RANDOMIZE)| and
re-exec), but layout can still shift. The stack base moves with the
size of the environment and argv, and |brk|/|mmap| placement can
differ with kernel settings or sandboxing (seccomp, containers,
|setarch|). Once addresses differ, every pointer in the heap differs
too.
3.
*Conservative GC.*
GCL scans the C stack conservatively. Stale words on the stack,
which depend on environment size, |PWD|, and similar, can keep
different objects alive. Collections also happen at slightly
different points. The result is different live sets and different
free-list layouts in the dumped heap.
4.
*Address-dependent ordering.*
EQ/EQL hash tables hash on addresses, so their bucket layout, and
anything built by iterating over them, varies with allocation addresses.
5.
*Uninitialized or unzeroed memory.*
Freed or padding regions of the heap and of the unexec’d data
segment can contain leftover bytes, and those get dumped verbatim.
6.
*Embedded environment data that isn’t a timestamp:*
* absolute build paths, such as the system directory,
|si::*system-directory*|, and source paths in compiled code and
debug info
* hostname, user, or |uname| output captured at configure time
* PIDs in compiler temp file names (|gazonk_<pid>_…|), which can
leak into generated C, init symbol names, or object files
* the gensym counter and |*random-state*| as they stand at save
time, which depend on what happened during the build
7.
*Toolchain nondeterminism.*
This is less likely with a modern GCC and binutils, but there can
still be |-frandom-seed| related symbol names and unsorted archive
members.
Narrowing it down
*
Run |diffoscope| on two builds. Diffs confined to the saved images,
with identical |.o| files, point to heap/GC/ASLR causes (1–5). Diffs
in the |.o| or |.c| files point to paths, PIDs, or the compiler (6–7).
*
Build twice in the same directory, with the same user, hostname, and
environment (|env -i| with a fixed env), under |setarch -R|. If the
results then match, the remaining variation is environmental rather
than intrinsic.
*
Watch for |gazonk| PIDs and absolute paths:
|strings saved_gcl | grep -E 'gazonk|/build/' |
Debian’s reproducible-builds effort has looked at GCL for exactly these
reasons. As far as I know it has not been fully reproducible there
either, largely because of the unexec/heap-dump issue.
​