Go sets the version number like this: our project can also

Time:2021-12-4

Go sets the version number like this: our project can also

Hello, I’m polarisxu.

Projects, especially open source projects, will pay special attention to the of the projectVersion number。 For some projects, the version number will be written into the source code, and the source code number will be modified every time you upgrade. But this is not a particularly good way. Through learningGoLanguage source code to master it and apply it to their own projects.

This article is based on go1.17. The implementation details of different versions may be different

01 how to get version number

In the go language project, if you want to obtain the current go language version, you only need to call runtime.version:

  1. packagemain
  2. import(
  3. “fmt”
  4. “runtime”
  5. )
  6. funcmain(){
  7. fmt.Println(“GoVersion:”,runtime.Version())
  8. }

02 how

View the source code of runtime.version:

  1. //buildVersionistheGotree’sversionstringatbuildtime.
  2. //
  3. //IfanyGOEXPERIMENTsaresettonon-defaultvalues,itwillinclude
  4. //”X:”.
  5. //
  6. //Thisissetbythelinker.
  7. //
  8. //Thisisaccessedby”goversion”.
  9. varbuildVersionstring
  10. //VersionreturnstheGotree’sversionstring.
  11. //Itiseitherthecommithashanddateatthetimeofthebuildor,
  12. //whenpossible,areleasetaglike”go1.3″.
  13. funcVersion()string{
  14. returnbuildVersion
  15. }\

According to the comment prompt, find Src / CMD / link in the source code of the go warehouse, which is the implementation of the go linker. The following code is found in the internal / LD / main.go file:

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

The buildversion value is obtained from buildcfg.version. If goexpersient (environment variable value) is set, this value is used.

Focus on how to get buildcfg.version:

  1. var(
  2. defaultGOROOTstring//setbylinker
  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. )

It’s strange that the value of version is directly assigned by version. But what is the value of version? In Src / CMD / dist / builderuntime.go file, there is a function mkbuildcfg to generate buildcfg:

  1. //mkbuildcfgwritesinternal/buildcfg/zbootstrap.go:
  2. //
  3. //packagebuildcfg
  4. //
  5. //constdefaultGOROOT=
  6. //constdefaultGO386=
  7. //…
  8. //constdefaultGOOS=runtime.GOOS
  9. //constdefaultGOARCH=runtime.GOARCH
  10. //
  11. //Theuseofruntime.GOOSandruntime.GOARCHmakessurethat
  12. //across-compiledcompilerexpectstocompileforitsowntarget
  13. //system.Thatis,ifonaMacyoudo:
  14. //
  15. //GOOS=linuxGOARCH=ppc64gobuildcmd/compile
  16. //
  17. //theresultingcompilerwilldefaulttogeneratinglinux/ppc64objectfiles.
  18. //Thisismoreusefulthanhavingitdefaulttogeneratingobjectsforthe
  19. //originaltarget(inthisexample,aMac).
  20. funcmkbuildcfg(filestring){
  21. varbufbytes.Buffer
  22. fmt.Fprintf(&buf,”//Codegeneratedbygotooldist;DONOTEDIT.\n”)
  23. fmt.Fprintln(&buf)
  24. fmt.Fprintf(&buf,”packagebuildcfg\n”)
  25. fmt.Fprintln(&buf)
  26. fmt.Fprintf(&buf,”import\”runtime\”\n”)
  27. fmt.Fprintln(&buf)
  28. fmt.Fprintf(&buf,”constdefaultGO386=`%s`\n”,go386)
  29. fmt.Fprintf(&buf,”constdefaultGOARM=`%s`\n”,goarm)
  30. fmt.Fprintf(&buf,”constdefaultGOMIPS=`%s`\n”,gomips)
  31. fmt.Fprintf(&buf,”constdefaultGOMIPS64=`%s`\n”,gomips64)
  32. fmt.Fprintf(&buf,”constdefaultGOPPC64=`%s`\n”,goppc64)
  33. fmt.Fprintf(&buf,”constdefaultGOEXPERIMENT=`%s`\n”,goexperiment)
  34. fmt.Fprintf(&buf,”constdefaultGO_EXTLINK_ENABLED=`%s`\n”,goextlinkenabled)
  35. fmt.Fprintf(&buf,”constdefaultGO_LDSO=`%s`\n”,defaultldso)
  36. fmt.Fprintf(&buf,”constversion=`%s`\n”,findgoversion())
  37. fmt.Fprintf(&buf,”constdefaultGOOS=runtime.GOOS\n”)
  38. fmt.Fprintf(&buf,”constdefaultGOARCH=runtime.GOARCH\n”)
  39. writefile(buf.String(),file,writeSkipSame)
  40. }

The value of version is obtained through findgoversion (), which is defined in Src / CMD / dist / build.go: (some details are omitted)

  1. //findgoversiondeterminestheGoversiontouseintheversionstring.
  2. funcfindgoversion()string{
  3. //The$GOROOT/VERSIONfiletakespriority,fordistributions
  4. //withoutthesourcerepo.
  5. path:=pathf(“%s/VERSION”,goroot)
  6. ifisfile(path){
  7. }
  8. //The$GOROOT/VERSION.cachefileisacachetoavoidinvoking
  9. //giteverytimewerunthiscommand.UnlikeVERSION,itgets
  10. //deletedbythecleancommand.
  11. path=pathf(“%s/VERSION.cache”,goroot)
  12. ifisfile(path){
  13. returnchomp(readfile(path))
  14. }
  15. //Showanicererrormessageifthisisn’taGitrepo.
  16. if!isGitRepo(){
  17. fatalf(“FAILED:notaGitrepo;mustputaVERSIONfilein$GOROOT”)
  18. }
  19. //Otherwise,useGit.
  20. //Whatisthecurrentbranch?
  21. branch:=chomp(run(goroot,CheckExit,”git”,”rev-parse”,”–abbrev-ref”,”HEAD”))
  22. //Cacheversion.
  23. writefile(tag,path,0)
  24. returntag
  25. }

Obtain the version in one order (if the previous acquisition cannot be found, follow the subsequent acquisition steps in turn)

  • Get from $goroot / version. Put the version information in this file. You can see the information of this file in your go installation directory
  • Get from $goroot / version.cache
  • The version information is generated according to the GIT warehouse, and the cache is generated. In this way, it is directly read from $goroot / version.cache

03 own project

Through the above analysis, this paper summarizes how the go version is written into the go source code:

  • The official version is obtained through a file in the project root directory, such as $goroot / version;
  • Informal version, get version information through git; In order to avoid repeated git related operations during compilation, a cache can be generated;
  • Control version information through environment variables;

Finally, the version information can be disclosed to users through an API.

For our own go project, we can obtain the version information through git, which can be realized through shell script. Finally, when compiling the go project, the version information is passed in through – X.

Now let’s implement this function through scripts.

The project code is as follows:

  1. //main.go
  2. packagemain
  3. import(
  4. “fmt”
  5. )
  6. varVersionstring
  7. funcmain(){
  8. fmt.Println(“Version:”,Version)
  9. }

Now write a shell script to compile the above code:

  1. #!/bin/sh
  2. version=””
  3. if[-f”VERSION”];then
  4. version=`catVERSION`
  5. fi
  6. if[[-z$version]];then
  7. if[-d”.git”];then
  8. version=`gitsymbolic-refHEAD|cut-b12-`-`gitrev-parseHEAD`
  9. else
  10. version=”unknown”
  11. fi
  12. fi
  13. gobuild-ldflags”-Xmain.Version=$version”main.go
  • If there is a version file, read the value of the file as version information;
  • If the value of version is empty, judge whether the current project is a git project. If yes, the version information is obtained. Format: Master commithash; Otherwise, the version information is set to unknown;
  • Pass version information to main.version through ldflags of go build;

In this way, the version in the project is set to the correct value.

04 summary

By studying the version information in the go source code, this paper has mastered the practice of setting version information for excellent open source projects. Finally, I demonstrated how to use this skill in my own project.

This article does not demonstrate environment variables, which are generally used less.

Recommended Today

Hive built-in function summary

1. Related help operation functions View built-in functions: Show functions; Display function details: desc function ABS; Display function extension information: desc function extended concat; 2. Learn the ultimate mental method of built-in function Step 1: carefully read all the functions of the show functions command to establish an overall understanding and impression Step 2: use […]