Repository: go
Issue: all: Alpine Linux ships modified Go binaries
Labels: NeedsInvestigation

One of the goals of Go 1.21's reproducible builds effort was to have the binaries we post on go.dev/dl match the binaries that other distributions post after building from source. Of course, to make that the case, the other distributions need to not patch the source.

For Go 1.21, we incorporated the various minor fixes that Ubuntu had accumulated, with the effect that Ubuntu's debs, while not exactly the same binaries, are easily reproduced. Specifically, the recipe is to build with GO386=softfloat and then run 'strip' on the binaries. For Go 1.22 it would be nice to make go build -ldflags=-s have the same effect as strip on ELF systems, so that `GO386=softfloat GO_LDFLAGS=-s ./make.bash -distpack` would reproduce the Ubuntu binaries, but even today, we have a trivial reproduction.

For Go 1.21, we also arranged that binaries built on Alpine would automatically use musl as the dynamic linker, and we arranged for the Go toolchain itself to not use dynamic binaries, so that the posted binaries would work unmodified on Alpine. Unfortunately, Alpine is [still patching the source code of the Go toolchain](https://git.alpinelinux.org/aports/tree/community/go?h=master), and so their binaries do not match the official ones. Specifically, they make two changes that affect the binaries:

[0001-cmd-link-prefer-musl-s-over-glibc-s-ld.so-during-dyn.patch](https://git.alpinelinux.org/aports/tree/community/go/0001-cmd-link-prefer-musl-s-over-glibc-s-ld.so-during-dyn.patch) changes the preference list for what happens when running on a system with _both_ the glibc and the musl dynamic linker installed. In this case the Go linker has a choice, and the default is to choose glibc, but Alpine wants Go to choose musl. 

@nmeum, is there some standard config file on the system, perhaps some file in etc, that indicates that musl should be preferred over glibc? How does the clang or gcc toolchain on Alpine know? If there is some standard file, the Go linker could look at it too in Go 1.22. That would allow removing this patch.

[0003-Prevent-Go-from-downloading-other-toolchain-versions.patch](https://git.alpinelinux.org/aports/tree/community/go/0003-Prevent-Go-from-downloading-other-toolchain-versions.patch) is hard-coding `pathOnly = true`, overriding the user's own environment settings. This is unnecessary and limits Go's functionality on Alpine. The commentary says:

	// On Alpine, we don't allow downloading other toolchain since
	// these are linked dynamically against glibc (i.e. do not work).

but this is not true: starting with Go 1.21.0, the toolchain binaries are statically linked pure Go programs, with no references to glibc, and so they should work fine on Alpine. (If this is not true I'd like to fix that.) It's true that downloading older toolchains won't work, but the way toolchain downloads work, automatic downloads only ever fetch newer toolchains. The incompatibility would only arise with explicit versions set in the environment like

	GOTOOLCHAIN=go1.20.4 go test

It doesn't make sense to disable the entire feature just to avoid problems with this relatively uncommon use case. (Again, the most common use case by far will be downloading a newer toolchain, and those work.)

I understand that Alpine would prefer to set a system default, and we created the go.env for that purpose, and in fact [https://git.alpinelinux.org/aports/tree/community/go/0004-go.env-Don-t-switch-Go-toolchain-version-as-directed.patch](https://git.alpinelinux.org/aports/tree/community/go/0004-go.env-Don-t-switch-Go-toolchain-version-as-directed.patch) does exactly that, by changing the default from `GOTOOLCHAIN=auto` to `GOTOOLCHAIN=local`. That seems perfectly reasonable as a policy choice, and `go.env` is the place to set policy. Making the change there allows users to override the policy decision when they have different choices, either by setting an explicit environment variable or using `go env -w`. 

@nmeum, given the existence of the 0004 patch, can the 0003 patch be removed?