Trying to make the syncthing package on Arch Linux reproducible.
I’m trying to figure why the build id is still random even with -buildid= in the ldflags.
Here is the relevant snippet:
export GOFLAGS="-buildmode=pie -trimpath '-ldflags=-linkmode=external -buildid=' -mod=readonly -modcacherw"
go run build.go -no-upgrade -version v${pkgver} build
go run build.go -no-upgrade -version v${pkgver} build strelaysrv
go run build.go -no-upgrade -version v${pkgver} build stdiscosrv
I don’t see why this wouldn’t work, except maybe if GOFLAGS or the ldflags within aren’t respected.
So, is the GOFLAGS environment variable respected when building (through build.go)?
Only seems to be related in the way that both are trying to get reproducible builds.
I know why it’s not reproducible. It’s because of the build ID that the Go linker adds. I figured that out from diffoscope.
So I attempted to set -buildid= in ldflags in GOFLAGS to set the build ID to a blank string to improve reproducibility, but the thing is, it’s still using a random build ID that’s different on every build.
I don’t see why blanking the build ID helped out Catfriend1, but in my case it was just a red herring/domino effect. It was the unique temporary file paths created by Go that were stored in syncthing.debug that were the problem.
You might think what I’m saying conflicts with this:
But “it” here means the build ID, not the entire build.
Here is the relevant diffoscope output of comparing the build in extra-debug to a build I made myself:
The go-build2698637364 folder name part is not reproducible.
I saw a change in the .gnu_debuglink in the non-debug package, and at first I thought it was another copy of the build ID was in there, but no, it was a CRC of the syncthing.debug file. See also loqs’ comment.
A workaround to make the entire build reproducible is to add to -s -buildid= to the ldflags, but that has the disadvantage of rendering the debug (syncthing-debug) package useless.
I was playing around with this and fail to accomplish reproducible builds even when it should be possible. That is to say, I get repeatable builds, but not the same binary from machine A and machine B with the same inputs.
For example, I create a linux/amd64 binary on my mac and on another linux box,
EXTRA_LDFLAGS="-s -buildid=" BUILDDEBUG=1 SOURCE_DATE_EPOCH=123456789 \
BUILD_USER=jb BUILD_HOST=reproducible GOTOOLCHAIN=go1.24.4 CGO_ENABLED=0 \
go run build.go -goos linux -goarch amd64 build ; sha256sum syncthing
imho they should be identical but they differ in lots of places – strings, and then offsets all over in the code. I’m not sure why. If anyone has looked into this previously and has any tips, I’m all ears. It’s not something prioritised, just something I got nerd sniped into due to the discussions going on…
(Deliberately leaving the new C-based SQLite stuff out here with CGO_ENABLED=0 to keep it simple in the first case…)
(Also staying away from the macos and windows builds as those have signatures and syso extensions and whatnot that complicate the picture)
Interesting. When looking at Syncthing-Fork Reproducibility Status I’ve finally gotten to a reproducible build via F-Droid’s build servers. That included setting the SOURCE_DATE_EPOCH & BUILD_ID=“” & BUILD_HOST=static_string & BUILD_USER=static_string