From the release of 22147 cmd/go : Simplify embedding the compiled git SHA in a binary file , now you have (with Go 1. 12+, Q1 2019, 2+ a few years later) an alternative for dependencies (not yet for your main program).
Therefore, you still need -ldflags to write the version of your sources.
But not for recording the version of your dependencies: it is now available.
Starting with Go version 1.12, you can get versions of all modules compiled into a binary file (in module mode) using runtime/debug.BuildInfo .
If the version used is a pseudo version, it also includes the first dozen characters of the VCS commit identifier.
// BuildInfo represents the build information read from the running binary. type BuildInfo struct { Path string // The main package path Main Module // The main module information Deps []*Module // Module dependencies } // ReadBuildInfo returns the build information embedded in the running binary. The information is available only in binaries built with module support. func ReadBuildInfo() (info *BuildInfo, ok bool)
This comes from the commit 45e9c55 :
runtime / debugging: add an API to read module information in binary
When the module is turned on, the go tool embeds the assembly information associated with the module in a binary file, including dependencies and replacement information (see src/cmd/go/internal/modload#PackageBuildInfo() , from commit f7248f0 ).
The recently introduced ReadBuildInfo reads information and makes it available programmatically.
You can see how it was used in release 26404: "cmd / go: programmatically export module information for binary files"
package main import ( "log" "runtime/debug" "github.com/kr/pretty" ) func main() { bi, ok := debug.ReadBuildInfo() if !ok { log.Fatal("!ok") } pretty.Println(bi) }
You get:
&debug.BuildInfo{ Path: "foo.to/v", Main: debug.Module{ Path: "foo.to/v", Version: "(devel)", Sum: "", Replace: (*debug.Module)(nil), }, Deps: { &debug.Module{ Path: "github.com/kr/pretty", Version: "v0.1.0", Sum: "h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=", Replace: (*debug.Module)(nil), }, &debug.Module{ Path: "github.com/kr/text", Version: "v0.1.0", Sum: "h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=", Replace: (*debug.Module)(nil), }, }, }
If you build a binary file in module mode from outside the module using 1.12 ( # 24250 ), then you will get all the information about its version.
but the reported version of the binary at the moment is always (devel) . Even if it is fixed and marked
So the main problem remains: Issues / 29814 " cmd/go : use version control to detect the version of the main module?" .
When a binary is created from the module source tree, the output from runtime/debug.ReadBuildInfo currently reports that this module has a version (devel) .
If the source tree is an intact checkout from the version control system or is in the module cache (read-only), we could instead query the version control system to find the appropriate version or pseudo version for embedding.
However, there are a few caveats:
- This would require us to execute VCS commands in the user source tree. Historically, running VCS commands has been the source of too many vulnerabilities of go commands, so we really would like to avoid issuing VCS commands unless they are absolutely necessary.
- For this commit, we can create a pseudo version for this commit, but we cannot say whether this commit was published in the source.
It would be nice to keep the invariant so that only published versions are advertised in the published debugging information, but this can lead to additional extraction from the network. - Inside the module, we apply replacements and exceptions to this module, and a custom VCS check may also apply some transformations.
(devel) is currently giving a hint that these module-specific changes are in effect: if we instead specified an explicit version, we would need to provide some way to indicate that the replacements and exceptions were applied.
Go 1.13 (Q3 2019) includes:
The go version command now accepts arguments with the names of executable files and directories.
- When the executable is invoked,
go version prints the version of Go used to build the executable. - If the
-m flag is used, go version prints go version information of the executable plug-in, if available. ( runtime/debug#BuildInfo ) - When called from a directory,
go version prints information about the executable file contained in the directory and its subdirectories.