go: cmd/dist: remove precompiled .a files from binary distributions [freeze exception]
The downloadable archives at https://golang.org/dl/ currently contain precompiled .a files for all packages in the standard library. Each archive has a set of .a files for one platform, plus another set for -race
builds.
These files take up quite a bit of space, and they’re fast to rebuild on demand. We should consider removing them from binary Go distributions.
For example, in 1.17rc1 on darwin/amd64, the whole distribution uncompressed is 435M. The pkg/darwin_amd64
directory is 97M (22%), and the pkg/darwin_amd64_race
directory is 109M (25%). Compressed as a zip file with default settings, the archive is 135M. Without .a files, it’s 86M (63%).
After #40042 was fixed, the C compiler version is included in the cache key for each package that uses cgo. That means that if no C compiler is installed on the system, or if a different C compiler version is installed (very common), go build
and other commands will rebuild packages that depend on cgo instead of using the versions installed in $GOROOT/pkg
. As of 1.17rc1, there are 27 packages in std
that use cgo directly or indirectly, most prominently, net
. The precompiled files for these packages are almost never used unless the installed C compiler exactly matches the version used to build the Go distribution.
Note that the fix for #40042 is causing builds to fail on systems without a C compiler installed (#47215), so it may be partially or completely rolled back in 1.17. If we implement this proposal, we’d have the same problem, so we may want to think about changing the default value of CGO_ENABLED
(#47251).
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Reactions: 24
- Comments: 60 (20 by maintainers)
Links to this issue
Commits related to this issue
- Remove golang's pre-compiled packages These are apparently not needed when you're using a C compiler (which we are), and can save (as of now) ~230MB on the uncompressed image. See https://github.com... — committed to submariner-io/shipyard by mkolesnik 2 years ago
- go/internal/gcimporter,cmd/compile/internal/importer: skip tests that need 'go list' on js/wasm js/wasm doesn't support os.Exec, so it can't run 'go list' to locate export data for packages in the st... — committed to golang/go by bcmills 2 years ago
- cmd/dist: produce intermedate .a files in a temporary location Before this change, the .a files for the intermediate go toolchains were produced in the same location as the install target. This chang... — committed to golang/go by matloob 2 years ago
- cmd/go: don't substitute '$WORK' for work directory in -x heredocs When writing the set of commands excuted for go build -x, $WORK is substituted for the work directory in all the commnands. But this... — committed to golang/go by matloob 2 years ago
- cmd/go: don't install most GOROOT .a files in pkg Packages in GOROOT that don't use cgo will not be installed in GOROOT/pkg, and will instead be cached as usual like other Go packages. - add a inter... — committed to golang/go by matloob 2 years ago
- cmd/compile/internal/types2: fix tests on js/wasm The js/wasm builder started failing as of CL 432535 due to needing 'go build' to import standard-library packages that are no longer installed to GOR... — committed to golang/go by bcmills 2 years ago
- cmd/api: skip tests when 'os/exec' is supported but 'go build' is not This may fix the android-.*-emu builders, which are currently broken. For #47257. Change-Id: I370dad2cb8031f8f5fdfbeb9c284c4f79... — committed to golang/go by bcmills 2 years ago
- internal/releasetargets: remove Race config from 1.20 Go 1.20 will not be shipping with precompiled .a files for most packages in the distribution in favor of having them compiled as needed and cache... — committed to golang/build by matloob 2 years ago
- cmd/go: add move test for goroot This an end-to-end test that sets GOROOT to a symlink to the distribution, approximating copying it to a new location, and checks that packages in the standard libra... — committed to golang/go by matloob 2 years ago
- cmd/dist: fix a variable scope bug: We reused p so we were deleting the same directory twice instead of two different directories. Fix that. For #47257 Change-Id: I315ad87d0a9182e00ae4c11b82986227e... — committed to golang/go by matloob 2 years ago
- go/internal/gcimporter,cmd/compile/internal/importer: skip tests that need 'go list' on js/wasm js/wasm doesn't support os.Exec, so it can't run 'go list' to locate export data for packages in the st... — committed to TroutSoftware/go by bcmills 2 years ago
- cmd/dist: produce intermedate .a files in a temporary location Before this change, the .a files for the intermediate go toolchains were produced in the same location as the install target. This chang... — committed to TroutSoftware/go by matloob 2 years ago
- cmd/go: don't substitute '$WORK' for work directory in -x heredocs When writing the set of commands excuted for go build -x, $WORK is substituted for the work directory in all the commnands. But this... — committed to TroutSoftware/go by matloob 2 years ago
- cmd/go: don't install most GOROOT .a files in pkg Packages in GOROOT that don't use cgo will not be installed in GOROOT/pkg, and will instead be cached as usual like other Go packages. - add a inter... — committed to TroutSoftware/go by matloob 2 years ago
- cmd/compile/internal/types2: fix tests on js/wasm The js/wasm builder started failing as of CL 432535 due to needing 'go build' to import standard-library packages that are no longer installed to GOR... — committed to TroutSoftware/go by bcmills 2 years ago
- cmd/api: skip tests when 'os/exec' is supported but 'go build' is not This may fix the android-.*-emu builders, which are currently broken. For #47257. Change-Id: I370dad2cb8031f8f5fdfbeb9c284c4f79... — committed to TroutSoftware/go by bcmills 2 years ago
- cmd/go: add move test for goroot This an end-to-end test that sets GOROOT to a symlink to the distribution, approximating copying it to a new location, and checks that packages in the standard libra... — committed to TroutSoftware/go by matloob 2 years ago
- cmd/dist: fix a variable scope bug: We reused p so we were deleting the same directory twice instead of two different directories. Fix that. For #47257 Change-Id: I315ad87d0a9182e00ae4c11b82986227e... — committed to TroutSoftware/go by matloob 2 years ago
- doc: add a release note for fewer pre-compiled GOROOT .a files For #47257 Change-Id: I3837220d02741da92d723484c82d11e82c92151a Reviewed-on: https://go-review.googlesource.com/c/go/+/448017 TryBot-Re... — committed to golang/go by matloob 2 years ago
- cmd/go: decide whether to install .a based on number of CgoFiles Instead of hardcoding the set of five packages that depend on cgo to decide whether a package should have an install target, make the ... — committed to golang/go by matloob 2 years ago
I think it’s pretty important that a Go binary installation work on a system with no C compiler installed. And at least in the past on macOS Go programs would only work if using the cgo version of the net package. So I think we at least need to provide the .a files for the standard library packages that use cgo, which I think is currently net and os/user.
@ianlancetaylor
I would agree with you a priori, but as I understand the current state of the world, the introduction of the build cache broke this case many releases back, with no complaints (or at least not enough that we’ve tried to fix it). The .a files that ship do not actually have the right cache keys embedded inside them to be used by essentially any out-of-the-box install of Go. Instead, they get recomputed (in the cache only, not in the install location) the first time you build something.
Assuming I am right about that (I have not done the experiment myself), then I think it is OK to just drop the .a files entirely and not worry about the “cgo without C compiler” case anymore.
Another reason to do this is that internet speeds vary wildly. To some people, downloading an extra 50MiB is a split second, but to many others it’s staring at their screen for an extra minute. I don’t have an ETA for FTTH reaching my building in the UK, for example 😃
CPU speeds and compile times also vary, but I think the lower bound is much less worrying - even with a five-year-old thin laptop, one should be able to build the standard library in 10-20s.
I don’t like that we as a team are trying to land major features of the release at the absolute last possible moment and I would prefer not to have to make this decision. With that said, we know that the go command doesn’t get much testing until the RC anyway, so in this specific case it probably doesn’t make much practical difference.
Approved. If there are a lot of follow-ups we should take another look.
My suggestion here would be to define that
go install x
only ever installs binaries, never .a files. That would change this from being about cmd/dist and the Go distribution to being about cmd/go. The distributions would shrink as a side effect, and the meaning ofgo install
would become clearer.@jayconrod I think you are correct that with our current implementation we could call the macOS libraries directly without having to use cgo. The same is true on AIX and Solaris, for that matter.
I wonder how viable this is?
I know very little about the guts of the
net
package. Reading https://pkg.go.dev/net#hdr-Name_Resolution, it looks like there are Go and cgo implementation for name resolution. When cgo is available, they’re both compiled in and selected dynamically (GODEBUG=netdns=go
orGODEBUG=netdns=cgo
can pick one at run-time). On macOS, the cgo version seems to be preferred.But does the cgo version actually need to be written with cgo? On macOS at least, we link dynamically with
/usr/lib/libSystem.B.dylib
even withCGO_ENABLED=0
, so we don’t need the external linker. CL 227037 leads me to believe it’s possible to call C code from Go with assembly trampolines. (This is mostly a thought experiment; I don’t want to re-implementnet
or awaken Cthulhu).Based on the discussion above, this proposal seems like a likely accept. — rsc for the proposal review group
Does that imply that on macOS it already isn’t possible to build a working Go program that depends on
net
withCGO_ENABLED=0
?If so, that would imply that without a working C compiler it also isn’t possible to build programs that depend on both
net
and some third-party package whose source files vary based on thecgo
build constraint: thecgo
constraint is met ifCGO_ENABLED=1
even if the C compiler is present. So that would force users to choose between two options:CGO_ENABLED=1
and get build errors due to attempting to compile third-party//go:build cgo
files without a working C compiler.CGO_ENABLED=0
, and get the appropriate source files for third-party packages but a non-workingnet
package.I think we could resolve that in one of three ways:
net
package to not require a C compiler on macOS.cmd/go
to build thenet
package on macOS using a C compiler even ifCGO_ENABLED=0
.</strike>net
on macOS.This proposal has been added to the active column of the proposals project and will now be reviewed at the weekly proposal review meetings. — rsc for the proposal review group
I think we can plausibly check in the relevant cgo-generated pieces for the few stdlib packages that need cgo. Then we wouldn’t need a special case for “install runtime/cgo.a but no other .a files”.
CGO_ENABLED=0 is effectively the same as cross-compiled, and same headaches: netdns’s go is simply inadequate, at least for use cases where DNS queries are routed based on domain name to different resolvers by the operating system. /etc/resolv.conf does not adequately describe the OS DNS routing behavior; there’s no good way for netdns to ever do this correctly.
@rsc I was under this impression too until looking at #47215 last week. The C compiler version only became part of the cache key in #40042. So this is true for 1.17rc1, but not for 1.16 or lower. If neither CC nor CGO_CFLAGS are explicitly set, the go command will happily use the precompiled
runtime/cgo.a
, even if no C compiler is installed. We’re looking at a narrow rollback of this in CL 335409.(@bcmills pointed out cases where the cache keys don’t match on macOS, but they do match on Linux, and that’s the platform I’m most worried about, since a lot of folks are building in Docker without installing a C compiler).