Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

doc: best practices for cross-compiling universal binaries to distribute #48540

Open
mvdan opened this issue Sep 22, 2021 · 5 comments
Open

doc: best practices for cross-compiling universal binaries to distribute #48540

mvdan opened this issue Sep 22, 2021 · 5 comments
Labels
Documentation NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone

Comments

@mvdan
Copy link
Member

mvdan commented Sep 22, 2021

This issue is somewhat similar to #42119, in that it would be a collection of general recommendations for a fairly common use case that I see users struggle with.

Cross-compiling in Go is simple - for example, from linux/amd64, I can build a binary for windows/arm64 via just GOOS=windows GOARCH=arm64 go build. However, in practice that's often not enough when one wants to publish prebuilt binaries as part of a release's "download" page.

In no particular order, one needs to consider:

  • What GOOS/GOARCH combinations to build for. I personally go for the first class ports on my projects via cmd/dist: show which GOOS/GOARCH combinations are first class ports #38874. Other projects might want a broader set.
  • Explicitly and consistently keep CGO_ENABLED on (=1) or off (=0). By default, it will be on for the host target, and off for all other targets. This can result in confusion and bugs, as one binary behaves differently from the others.
  • Keep the build reproducible. At minimum, this requires the use of -trimpath. For others to reproduce the same binary, full instructions should be published, including the Go version and build commands.
  • Keep the binary fully static. This is fairly complex until cmd/go: build: add -static flag #26492 gets implemented.
  • Ensure the binaries include version information. Since most developers build from VCS clones, this won't happen in most cases until cmd/go: stamp git/vcs current HEAD hash/commit hash/dirty bit in binaries #37475 is implemented.
  • Ensure hardware requirements are adequately low. For example, building with GOAMD64=v3 will leave out most pre-2013 x86 users. Explicitly lowering these requirements is a good idea since your system might have higher defaults.

Note that these are general recommendations, and not must-haves by any means. For example, maybe I don't want my cgo binaries to be fully static, because my users want to supply their own version of a large C dependency. Or maybe my hardware requirements are higher because my project targets specific new hardware that already meets those.

@mvdan
Copy link
Member Author

mvdan commented Sep 22, 2021

One question might be: why not automate all of this via a tool similar to https://pkg.go.dev/golang.org/x/exp/cmd/gorelease? That might certainly be a good idea. I still think documenting the general best practices is a must, because many of these decisions will vary depending on the project. One great example is CGo: some projects require it for their release builds, some others avoid it.

So an automated tool may be a good idea, but I see it as a layer on top of this doc page. You could think of it as a tool that automates the most common decisions for the list above, to be sufficient for >90% of Go projects.

@mvdan
Copy link
Member Author

mvdan commented Sep 22, 2021

I also realise many such "automating" tools exist, like goreleaser. That's pretty out of scope, as they tend to do far more than just build binaries, and still fall under "would build on top of this doc page".

@mvdan
Copy link
Member Author

mvdan commented Sep 22, 2021

I should also note that the advice gets increasingly complex if you dive into any of the topics at hand. For example, if you choose to build with CGo, then you have to be careful with what versions of C libraries you're building. Cross-compiling with CGo also brings its own toolchain problems, such as #47175 and #44112.

I don't think the doc page should aim to be exhaustive with all these narrow topics, but it could certainly point the users towards other threads or docs which do.

@andig
Copy link
Contributor

andig commented Sep 22, 2021

More complexity added when signing or notarizing binaries e.g. for Mac.

@martisch
Copy link
Contributor

Ensure hardware requirements are adequately low. For example, building with GOAMD64=v3 will leave out most pre-2013 x86 users.

GOAMD64=v3 will also leave out CPUs as new as 2021 atom, pentium and celeron chips and amd embedded still being produced which are used a lot in NAS devices, routers and low end laptops as none of these have AVX: https://www.cpu-world.com/Compare_CPUs/Intel_J6413,Intel_CM8070104291511/?

@mknyszek mknyszek added this to the Unreleased milestone Oct 4, 2021
@mknyszek mknyszek added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Oct 4, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Documentation NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
None yet
Development

No branches or pull requests

5 participants