golang 基础库之golang版本,介绍了如何获取Golang的运行时版本,以及通过源码解析版本是如何获取的
获取Golang版本Golang 版本
1.12.1
实现
package main
import (
"log"
"runtime"
)
const info = `
程序 %s 运行...
由 Go:%s 版本编译
`
func main() {
log.Printf(info, "Example", runtime.Version())
}
原理
runtimeGoVersion
package runtime
import "runtime/internal/sys"
// Version returns the Go tree's version string.
// It is either the commit hash and date at the time of the build or,
// when possible, a release tag like "go1.3".
func Version() string {
return sys.TheVersion
}
Versionruntime/internal/sysTheVersion$GOROOT/src/runtime/internal/sys/zversion.go
// Code generated by go tool dist; DO NOT EDIT.
package sys
const TheVersion = `go1.12.1`
const Goexperiment = ``
const StackGuardMultiplierDefault = 1
go tool dist$GOROOT/src/cmd/dist/buildruntime.gomkzversionTheVersionfindgoversion
package main
// mkzversion writes zversion.go:
//
// package sys
//
// const TheVersion = <version>
// const Goexperiment = <goexperiment>
// const StackGuardMultiplier = <multiplier value>
//
func mkzversion(dir, file string) {
var buf bytes.Buffer
fmt.Fprintf(&buf, "// Code generated by go tool dist; DO NOT EDIT.\n")
fmt.Fprintln(&buf)
fmt.Fprintf(&buf, "package sys\n")
fmt.Fprintln(&buf)
fmt.Fprintf(&buf, "const TheVersion = `%s`\n", findgoversion())
fmt.Fprintf(&buf, "const Goexperiment = `%s`\n", os.Getenv("GOEXPERIMENT"))
fmt.Fprintf(&buf, "const StackGuardMultiplierDefault = %d\n", stackGuardMultiplierDefault())
writefile(buf.String(), file, writeSkipSame)
}
findgoversion$GOROOT/src/cmd/dist/build.go
package main
// findgoversion determines the Go version to use in the version string.
func findgoversion() string {
// The $GOROOT/VERSION file takes priority, for distributions
// without the source repo.
path := pathf("%s/VERSION", goroot)
if isfile(path) {
b := chomp(readfile(path))
// Commands such as "dist version > VERSION" will cause
// the shell to create an empty VERSION file and set dist's
// stdout to its fd. dist in turn looks at VERSION and uses
// its content if available, which is empty at this point.
// Only use the VERSION file if it is non-empty.
if b != "" {
// Some builders cross-compile the toolchain on linux-amd64
// and then copy the toolchain to the target builder (say, linux-arm)
// for use there. But on non-release (devel) branches, the compiler
// used on linux-amd64 will be an amd64 binary, and the compiler
// shipped to linux-arm will be an arm binary, so they will have different
// content IDs (they are binaries for different architectures) and so the
// packages compiled by the running-on-amd64 compiler will appear
// stale relative to the running-on-arm compiler. Avoid this by setting
// the version string to something that doesn't begin with devel.
// Then the version string will be used in place of the content ID,
// and the packages will look up-to-date.
// TODO(rsc): Really the builders could be writing out a better VERSION file instead,
// but it is easier to change cmd/dist than to try to make changes to
// the builder while Brad is away.
if strings.HasPrefix(b, "devel") {
if hostType := os.Getenv("META_BUILDLET_HOST_TYPE"); strings.Contains(hostType, "-cross") {
fmt.Fprintf(os.Stderr, "warning: changing VERSION from %q to %q\n", b, "builder "+hostType)
b = "builder " + hostType
}
}
return b
}
}
// The $GOROOT/VERSION.cache file is a cache to avoid invoking
// git every time we run this command. Unlike VERSION, it gets
// deleted by the clean command.
path = pathf("%s/VERSION.cache", goroot)
if isfile(path) {
return chomp(readfile(path))
}
// Show a nicer error message if this isn't a Git repo.
if !isGitRepo() {
fatalf("FAILED: not a Git repo; must put a VERSION file in $GOROOT")
}
// Otherwise, use Git.
// What is the current branch?
branch := chomp(run(goroot, CheckExit, "git", "rev-parse", "--abbrev-ref", "HEAD"))
// What are the tags along the current branch?
tag := "devel"
precise := false
// If we're on a release branch, use the closest matching tag
// that is on the release branch (and not on the master branch).
if strings.HasPrefix(branch, "release-branch.") {
tag, precise = branchtag(branch)
}
if !precise {
// Tag does not point at HEAD; add hash and date to version.
tag += chomp(run(goroot, CheckExit, "git", "log", "-n", "1", "--format=format: +%h %cd", "HEAD"))
}
// Cache version.
writefile(tag, path, 0)
return tag
}
$GOROOT/VERSION$GOROOT/VERSION.cache$GOROOT/VERSION.cacheGitGogit