I tried to create a reproducible windows build of tcc. I chose windows because:
- I'm more familiar with Windows as a tcc build target.
- tcc targeting windows is self contained (has all headers/libs to create executables)
- tcc is distributed as binary for windows, so it would be nice if users could reproduce the official build on any OS.
- It might be able to detect problems with tcc.
- I wanted to make it easy to build tcc for windows without installing big environments.
What I came up with is a simple procedure which is compiler and operating-system agnostic*:
- Use a native compiler to create a native tcc executable which targets windows.
- Use this new tcc to build tcc for windows (this is how the normal makefile builds the libs for the windows cross compilers).
- It then outputs a single combined signature of all the output files such that it can be compared easily between environments.
- For simplicity, I used ONE_SOURCE (which still supports -run, but no libtcc).
I ended up with a script which builds 4 windows tcc compilers: native 32 and 64, and cross 32->64 and 64->32.
Its only input is a working native compiler, and it requires a posix-y shell, and works in busybox, dash, bash, etc.
To use it, place the attached file at the win32 dir of tcc, and then:
For the currently latest mob commit (3054a76 i386-gen: use EBX as 4th register) the build signature is 52155cb6a03fcfd2632dc649984875e1
This script completes on all the environments which I tried and produces identical binaries (and signature) regardless of the system and the initial compiler.
Tested environments/compilers which produce identical outputs:
- Ubuntu 16.04 32/64 (gcc 5.4 and clang-3.8, glibc)
- FreeBSD* (GhostBSD) 32/64 (gcc 4.4, glibc?)
- OSX* el capitan (Apple LLVM 8)
- Alpine** linux 64 (gcc 6.2, musl-libc)
- Windows: Msys2 32/64 (gcc 6.2), MSVC 2013 32/64
- And of course each of the 4 output tcc compilers which this script generates can generate identical 4 output compilers.
On windows, it's enough to use a binary distribution of tcc (zipped, but not 0.9.26) and busybox to generate identical outputs.
I didn't run the resulting tcc's through the existing tests, but I did use them as inputs to the script itself (generates identical outputs) and as input for the normal tcc configure, make, make test - where the generated tcc's do pass all tests.
I'm not sure how much value this has in general, but at the very least it's interesting IMO.
I _think_ it would be possible to generate identical compilers which target other systems too, even if they won't be as functional as the windows outputs, just to see how tcc "reacts" on different systems where it's supposed to generate eventual identical outputs, but I'm not familiar enough with the subject to really assess how feasible or useful it would be.
* On Alpine/OSX/BSD I wasn't able to build native tcc with configure+make, but the script still works and generates cross and then identical win-native tcc's.
** On GhostBSD 32/64 there's a tcc bug where the object files (for libtcc1.a) use BSD bits at elf header even if the target if not BSD. I worked around it but didn't push to mob since I don't think it's the best fix. The offending line is at (the current) tccelf.c:2577 :
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
And my workaround was to check if the target is not windows, which was good enough to generate identical signature as the other envs. There are actually a lot of similar target-unconditional BSD code, but changing this one alone was enough to generate identical output.