Generate reproducible Go binaries.
Use asdf to manage Go versions.
Executables generated by the Go compiler can be byte for byte reproduced using metadata embedded in the binary. The metadata includes whether the version control has any local changes:
$ git clone https://github.com/msantos/goreap
$ cd goreap/cmd/goreap
$ git checkout 300f4137a4d9f90c4b41c7997e76a4a15bead740
$ CGO_ENABLED=0 go build -trimpath -ldflags "-s -w"
$ go version -m goreap
goreap: go1.18.1
path github.com/msantos/goreap/cmd/goreap
mod github.com/msantos/goreap (devel)
dep golang.org/x/sys v0.0.0-20210113181707-4bcb84eeeb78 h1:nVuTkr9L6Bq62qpUqKo/RnZCFfzDBL0bYo6w9OJUqZY=
build -compiler=gc
build -ldflags="-s -w"
build CGO_ENABLED=0
build GOARCH=amd64
build GOOS=linux
build GOAMD64=v1
build vcs=git
build vcs.revision=300f4137a4d9f90c4b41c7997e76a4a15bead740
build vcs.time=2022-04-17T12:29:28Z
build vcs.modified=false
$ sha256sum goreap
06780f56efac35dba2ff9ae105b94e97582e6164dc59abf8219c4fb24f11c27a goreap
Unmanaged files in the git repository change the build metadata and the binary checksum:
$ touch foo
$ git status
...
Untracked files:
foo
$ CGO_ENABLED=0 go build -trimpath -ldflags "-s -w"
$ go version -m goreap
goreap: go1.18.1
path github.com/msantos/goreap/cmd/goreap
mod github.com/msantos/goreap (devel)
dep golang.org/x/sys v0.0.0-20210113181707-4bcb84eeeb78 h1:nVuTkr9L6Bq62qpUqKo/RnZCFfzDBL0bYo6w9OJUqZY=
build -compiler=gc
build -ldflags="-s -w"
build CGO_ENABLED=0
build GOARCH=amd64
build GOOS=linux
build GOAMD64=v1
build vcs=git
build vcs.revision=300f4137a4d9f90c4b41c7997e76a4a15bead740
build vcs.time=2022-04-17T12:29:28Z
build vcs.modified=true
$ sha256sum goreap
162479ba1a84fa8a88bc9b72fe1e98bf3f2da565af0bbfb627f3baa1c2cb098c goreap
Note:
git clean -f -x -d
CGO_ENABLED=0 go build -trimpath -ldflags "-s -w"
CGO_ENABLED
: disable use of libc, use pure go-trimpath
: remove paths from stacktraces-ldflags
: reduce binary size by removing debug tablesEnsure the same Go version is installed:
asdf plugin add go https://github.com/asdf-community/asdf-golang.git
asdf install go $(asdf latest go)
The version for a git repo can be set:
$ asdf local go 1.17.5
$ git add .tool-versions
$ mkdir test
$ git init
$ curl --location https://raw.githubusercontent.com/github/gitignore/main/Go.gitignore > .gitignore
$ go mod init test
package main
import (
"fmt"
"os"
)
func main() {
fmt.Fprintln(os.Stderr, "test")
}
$ go fmt ./...
$ golangci-lint run
$ golangci-lint run --enable-all
$ git add .
$ git commit
$ GOARCH=arm CGO_ENABLED=0 go build -trimpath -ldflags "-s -w"
# asdf install go 1.17.5
$ sha256sum test
7b85cb1914f6cdf34b58de83e0e52c30fcff7e8081824988c7db1c2572b4e0c4 test
(markdown)