日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關咨詢
選擇下列產品馬上在線溝通
服務時間:8:30-17:00
你可能遇到了下面的問題
關閉右側工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
Go這樣設置版本號:我們的項目也可以

大家好,我是 polarisxu。

為平順等地區(qū)用戶提供了全套網(wǎng)頁設計制作服務,及平順網(wǎng)站建設行業(yè)解決方案。主營業(yè)務為網(wǎng)站建設、成都網(wǎng)站設計、平順網(wǎng)站設計,以傳統(tǒng)方式定制建設網(wǎng)站,并提供域名空間備案等一條龍服務,秉承以專業(yè)、用心的態(tài)度為用戶提供真誠的服務。我們深信只要達到每一位用戶的要求,就會得到認可,從而選擇與我們長期合作。這樣,我們也可以走得更遠!

項目中,特別是開源項目,會特別重視項目的版本號。有些項目,會把版本號寫入源碼中,每次升級都修改源碼號。不過這不是特別好的方式。本文通過學習 Go 語言源碼的處理方式來掌握它,并應用于自己的項目中。

本文基于 Go1.17,不同版本的實現(xiàn)細節(jié)可能有所不同

01 如何獲取版本號

在 Go 語言項目中,如果要獲取當前 Go 語言版本,只需要調用 runtime.Version:

 
 
 
  1. package main
  2. import (
  3.  "fmt"
  4.  "runtime"
  5. )
  6. func main() {
  7.  fmt.Println("Go Version:", runtime.Version())
  8. }

02 如何實現(xiàn)的

查看 runtime.Version 的源碼:

 
 
 
  1. // buildVersion is the Go tree's version string at build time.
  2. //
  3. // If any GOEXPERIMENTs are set to non-default values, it will include
  4. // "X:".
  5. //
  6. // This is set by the linker.
  7. //
  8. // This is accessed by "go version ".
  9. var buildVersion string
  10. // Version returns the Go tree's version string.
  11. // It is either the commit hash and date at the time of the build or,
  12. // when possible, a release tag like "go1.3".
  13. func Version() string {
  14.  return buildVersion
  15. }\

根據(jù)注釋提示,在 Go 倉庫源碼中,找到 src/cmd/link,這是 Go 鏈接器的實現(xiàn)。在其中的 internal/ld/main.go 文件找到了如下代碼:

 
 
 
  1. buildVersion := buildcfg.Version
  2. if goexperiment := buildcfg.GOEXPERIMENT(); goexperiment != "" {
  3.   buildVersion += " X:" + goexperiment
  4. }
  5. addstrdata1(ctxt, "runtime.buildVersion="+buildVersion)

buildVersion 值從 buildcfg.Version 獲取,如果設置了 GOEXPERIMENT(環(huán)境變量值),則用該值。

著重看 buildcfg.Version 如何得到的:

 
 
 
  1. var (
  2.  defaultGOROOT string // set by linker
  3.  GOROOT   = envOr("GOROOT", defaultGOROOT)
  4.  GOARCH   = envOr("GOARCH", defaultGOARCH)
  5.  GOOS     = envOr("GOOS", defaultGOOS)
  6.  GO386    = envOr("GO386", defaultGO386)
  7.  GOARM    = goarm()
  8.  GOMIPS   = gomips()
  9.  GOMIPS64 = gomips64()
  10.  GOPPC64  = goppc64()
  11.  GOWASM   = gowasm()
  12.  GO_LDSO  = defaultGO_LDSO
  13.  Version  = version
  14. )

很奇怪,Version 的值,直接用 version 賦值的。但 version 的值是什么?在 src/cmd/dist/buildruntime.go 文件中,有一個函數(shù) mkbuildcfg,用于生成 buildcfg:

 
 
 
  1. // mkbuildcfg writes internal/buildcfg/zbootstrap.go:
  2. //
  3. // package buildcfg
  4. //
  5. // const defaultGOROOT = 
  6. // const defaultGO386 = 
  7. // ...
  8. // const defaultGOOS = runtime.GOOS
  9. // const defaultGOARCH = runtime.GOARCH
  10. //
  11. // The use of runtime.GOOS and runtime.GOARCH makes sure that
  12. // a cross-compiled compiler expects to compile for its own target
  13. // system. That is, if on a Mac you do:
  14. //
  15. // GOOS=linux GOARCH=ppc64 go build cmd/compile
  16. //
  17. // the resulting compiler will default to generating linux/ppc64 object files.
  18. // This is more useful than having it default to generating objects for the
  19. // original target (in this example, a Mac).
  20. func mkbuildcfg(file string) {
  21.  var buf bytes.Buffer
  22.  fmt.Fprintf(&buf, "http:// Code generated by go tool dist; DO NOT EDIT.\n")
  23.  fmt.Fprintln(&buf)
  24.  fmt.Fprintf(&buf, "package buildcfg\n")
  25.  fmt.Fprintln(&buf)
  26.  fmt.Fprintf(&buf, "import \"runtime\"\n")
  27.  fmt.Fprintln(&buf)
  28.  fmt.Fprintf(&buf, "const defaultGO386 = `%s`\n", go386)
  29.  fmt.Fprintf(&buf, "const defaultGOARM = `%s`\n", goarm)
  30.  fmt.Fprintf(&buf, "const defaultGOMIPS = `%s`\n", gomips)
  31.  fmt.Fprintf(&buf, "const defaultGOMIPS64 = `%s`\n", gomips64)
  32.  fmt.Fprintf(&buf, "const defaultGOPPC64 = `%s`\n", goppc64)
  33.  fmt.Fprintf(&buf, "const defaultGOEXPERIMENT = `%s`\n", goexperiment)
  34.  fmt.Fprintf(&buf, "const defaultGO_EXTLINK_ENABLED = `%s`\n", goextlinkenabled)
  35.  fmt.Fprintf(&buf, "const defaultGO_LDSO = `%s`\n", defaultldso)
  36.  fmt.Fprintf(&buf, "const version = `%s`\n", findgoversion())
  37.  fmt.Fprintf(&buf, "const defaultGOOS = runtime.GOOS\n")
  38.  fmt.Fprintf(&buf, "const defaultGOARCH = runtime.GOARCH\n")
  39.  writefile(buf.String(), file, writeSkipSame)
  40. }

其中 version 的值是通過 findgoversion() 得到,該函數(shù)定義在 src/cmd/dist/build.go 中:(省略了部分細節(jié))

 
 
 
  1. // findgoversion determines the Go version to use in the version string.
  2. func findgoversion() string {
  3.  // The $GOROOT/VERSION file takes priority, for distributions
  4.  // without the source repo.
  5.  path := pathf("%s/VERSION", goroot)
  6.  if isfile(path) {
  7.   ...
  8.  }
  9.  // The $GOROOT/VERSION.cache file is a cache to avoid invoking
  10.  // git every time we run this command. Unlike VERSION, it gets
  11.  // deleted by the clean command.
  12.  path = pathf("%s/VERSION.cache", goroot)
  13.  if isfile(path) {
  14.   return chomp(readfile(path))
  15.  }
  16.  // Show a nicer error message if this isn't a Git repo.
  17.  if !isGitRepo() {
  18.   fatalf("FAILED: not a Git repo; must put a VERSION file in $GOROOT")
  19.  }
  20.  // Otherwise, use Git.
  21.  // What is the current branch?
  22.  branch := chomp(run(goroot, CheckExit, "git", "rev-parse", "--abbrev-ref", "HEAD"))
  23.  ...
  24.  // Cache version.
  25.  writefile(tag, path, 0)
  26.  return tag
  27. }

按一下順序獲得 Version(如果前面的獲取不到,則依次執(zhí)行后續(xù)獲取步驟)

  • 從 $GOROOT/VERSION 獲取,在這個文件中放了版本信息,你可以看看你的 Go 安裝目錄下這個文件的信息
  • 從 $GOROOT/VERSION.cache 獲取
  • 根據(jù) Git 倉庫生成版本信息,并且生成緩存,這樣后續(xù)直接讀取 $GOROOT/VERSION.cache 獲取

03 自己項目

通過前文分析,總結下 Go 版本是如何寫入 Go 源碼的:

  • 正式版本,通過項目根目錄的一個文件得到,比如 $GOROOT/VERSION;
  • 非正式版本,通過 Git 獲得版本信息;為了避免編譯時重復執(zhí)行 Git 相關操作,可以生成緩存;
  • 通過環(huán)境變量控制版本信息;

最后,可以通過一個 API 把版本信息公開給用戶。

對于我們自己的 Go 項目,通過 Git 獲得版本信息,可以通過 shell 腳本實現(xiàn),最后編譯 Go 項目時,將版本信息通過 -X 傳遞進去。

現(xiàn)在我們通過腳本來實現(xiàn)這個功能。

項目代碼如下:

 
 
 
  1. // main.go
  2. package main
  3. import (
  4.  "fmt"
  5. )
  6. var Version string
  7. func main() {
  8.  fmt.Println("Version:", Version)
  9. }

現(xiàn)在寫一個 shell 腳本,通過該腳本對以上代碼進行編譯:

 
 
 
  1. #!/bin/sh
  2. version=""
  3. if [ -f "VERSION" ]; then
  4.     version=`cat VERSION`
  5. fi
  6. if [[ -z $version ]]; then
  7.     if [ -d ".git" ]; then
  8.         version=`git symbolic-ref HEAD | cut -b 12-`-`git rev-parse HEAD`
  9.     else
  10.         version="unknown"
  11.     fi
  12. fi
  13. go build -ldflags "-X main.Version=$version" main.go
  • 如果有 VERSION 文件,讀取該文件的值作為版本信息;
  • 如果 version 的值是空,判斷當前項目是否是 Git 項目。是,則獲取版本信息,格式:master-commithash;否則,版本信息設置為 unknown;
  • 通過 go build 的 ldflags 傳遞版本信息給 main.Version;

這樣項目中的 Version 就設置上正確的值了。

04 總結

本文通過對 Go 源碼中版本信息的學習研究,掌握了優(yōu)秀開源項目設置版本信息的做法。最后,演示了如何在自己的項目中用上該技能。

本文沒有演示環(huán)境變量,一般用的比較少。


網(wǎng)站標題:Go這樣設置版本號:我們的項目也可以
文章來源:http://www.5511xx.com/article/ccddici.html