go module
After the release of go1.16, the go module auto
changed on
to , which means that in subsequent development, it is recommended to use the go module mode instead of the gopath mode for development.
In the past, I also mostly developed golang in the go module mode, but I am not familiar with it so far 别人是这样做的,我跟着做就是了
. There will be these questions:
- What do the contents defined in the go mod file represent;
- In addition to common
require
and occasionalreplace
keywords ,exclude
,retract
(1.16) What are these keywords and how are they used; - What is the grammatical format of the go mod file? I don’t seem to understand the grammatical format besides following other people’s writing.
github.com/tal-tech/go-zero v1.1.5
What do ,github.com/antlr/antlr4 v0.0.0-20210105212045-464bcbc32de2
,google.golang.org/protobuf v1.25.0 // indirect
and other formats represent, and why some are
// indirect
modified with ;- Why is there a go.sum under go.mod, and what is its function;
- …
I don't know how many people, like me, have a negligible understanding of go modules.
Recently, with these doubts, I went to study the official reference manual, and these doubts were solved.
project
Before officially entering the module introduction, it is necessary to first understand the relationship between project and module. I believe that students who have developed Android or Java have a very good understanding of module. Generally speaking, a project can be composed of multiple modules, and a module can be used as The independent
project is referenced by other projects as dependencies. The following golang demo
project contains foo
and bar
two modules
demo
├── bar
│ └── go.mod
└── foo
└── go.mod
module introduction
go module (hereinafter referred to as: module, module, project module)
is a collection of released versions of packages in golang. It is a way for Go to manage dependencies, similar to Gradle in Android and Maven in Java. Of course, their management form It must be very different, but the purpose is the same, to manage dependencies.
In go.mod, it contains the module path of the main module, module dependencies and its associated information (version, etc.). If a project module needs to be
go module mode
developed in (module mode), the root directory of the project module must contain go.mod
the file .
module path (module path)
The module path is the name in a project module, declared with module
the command , and it is also the prefix of the package import in the project module. Let's take a look at demo/foo
the module path below:
$ cat demo/foo/go.mod
module github.com/foo
go 1.16
require github.com/tal-tech/go-zero
github.com/foo
foo
It is the module path of the main module module, github.com/tal-tech/go-zero
which is also the module path, and they are also
the prefix of the package import in foo. I added a Echo
function , and then main.go
called it in . Let's observe the prefix of its package import
directory tree
foo
├── base
│ └── base.go
├── go.mod
└── main.go
main.go
package main
import "github.com/foo/base" // github.com/foo 为 module path
import "fmt"
func main() {
msg := base.Echo("go-zero")
fmt.Println(msg)
}
The main function of the module path is to describe what the function of a project module is and where it can be found. Therefore, the components of the module path include
- repo path
- repo folder
- Version
Its manifestations are as follows: {
{.repo_url}}/{
{.nameOfDir}}/{
{.version}}
, example: github.com/tal-tech/go-zero/v2
, github.com/tal-tech
which clearly informs the path repo
of , go-zero
which is the folder of repo, v2
which is the version number. Generally, the v1
version is generally not written by default, and only v1
when it is greater than , it needs to be used to distinguish.
version number
The version number here refers to the version of the dependent module in the go.mod file, which {
{.version}}
is . The in the following example v1.1.5
is the version number of the module dependency mentioned this time.
module github.com/foo
go 1.16
require github.com/tal-tech/go-zero v1.1.5
Version number composition and rules
The version number consists of major version
(major version), minor version
(minor version), patch version
(revision version);
- major version: After the content in the module has been changed backwards, the version will be upgraded. When the version number is upgraded,
minor version
andpatch version
must be reset to zero; - minor version: This version number will be upgraded after new features are released (features) or a backward compatible content change is made. When this version number is upgraded, it must be reset to zero
patch version
; - patch version: This version number can be upgraded when there is a bug fix or function optimization, and this version number can also be changed when there is a pre-release release requirement
Examples: v0.0.0
, v1.2.3
,v1.2.10-pre
If a version
major version
is0
orpatch-version
has a version suffix (such as: pre), this version is considered unstable, such asv0.2.0
,v1.5.0-pre
,v1.1.3-beta
and more about version semantic definitions, please refer to "Semantic Versioning 2.0.0"
In addition to this, Golang can also use some tags and branches to represent a certain version, such as: github.com/tal-tech/go-zero 39540e21d249e91f89d96d015a6e3795cfb2be44
, github.com/tal-tech/go-zero v1.1.6-0.20210303091609-39540e21d249
,
github.com/tal-tech/go-zero@master
Among them, github.com/tal-tech/go-zero v1.1.6-0.20210303091609-39540e21d249
this version is called (pseudo-version) in golang Pseudo-versions
, which does not fully follow the version rules above. The pseudo-version consists of three parts:
- version base prefix (
vX.Y.Z-0
orvX.0.0
), such asv1.1.6-0
- Timestamp: the creation timestamp of the revision, such as
20210303091609
- revision identifier, such as
39540e21d249
Depending on the base prefix, the pseudo-version has three forms:
vX.0.0-yyyymmddhhmmss-abcdefabcdef
: used when there is norelease
versionvX.Y.Z-pre.0.yyyymmddhhmmss-abcdefabcdef
: used when the base version is a pre-release versionvX.Y.(Z+1)-0.yyyymmddhhmmss-abcdefabcdef
release
:vX.Y.Z
used when the version is similar to , suchgithub.com/tal-tech/go-zero v1.1.6-0.20210303091609-39540e21d249
asrelease
the version ofv1.1.5
The pseudo-version does not need to be manually entered, and it will automatically convert it to a pseudo-version when executing some go commands to obtain the code of a commit record version (revision) as a dependency
The
github.com/tal-tech/go-zero v1.1.6-0.20210303091609-39540e21d249
above isgo get github.com/tal-tech/go-zero 39540e21d249e91f89d96d015a6e3795cfb2be44
the result of automatic conversion after executing
version suffix
For forward compatibility, if is major version
upgraded to 2, the module path must specify a version suffix v2
(its value remains consistent with the value major version
in ), and major version
when is less than 2, the version suffix is not allowed.
Let's look at an example. I used this library in the demo/foo
module project miniRedis
, and the library major version
has been upgraded to 2. What if I reference the following version in go.mod?
module github.com/foo
go 1.16
// 正确引入
// require github.com/alicebob/miniredis/v2 v2.14.1
// 错误引入
require github.com/alicebob/miniredis v2.14.1
invalid version: module contains a go.mod file, so major version must be compatible: should be v0 or v1, not v2
The above is the scene when the go mod is used. Let’s take a look at v2.x.x
when (provided that a v1.0.0 version is released first), the module path does not add a version suffix, and it will be used in another module. What effect:
the example module foo
foo
project currently has a release version
v1.0.0
v2.0.1
- …
Projects using modulesbar
- without version suffix
foo
Project directory tree
foo
├── echo
│ └── echo.go
└── go.mod
module path isgithub.com/zsh/foo
module github.com/anqiansong/foo
go 1.16
In bar
project go.mod use v2.0.0
version
require github.com/anqiansong/foo v2.0.0
You will find that the error content is
require github.com/anqiansong/foo: reading https://goproxy.cn/github.com/anqiansong/foo/@v/v2.0.0.info: 404 Not Found
server response: not found: github.com/anqiansong/[email protected]: invalid version: module contains a go.mod file, so major version must be compatible: should be v0 or v1, not v2
If require github.com/zsh/foo v1.0.0
it is possible.
- After adding the version suffix
foo
Project directory tree
foo
├── echo
│ └── echo.go
└── go.mod
module path isgithub.com/zsh/foo/v2
module github.com/anqiansong/foo/v2
go 1.16
In bar
project go.mod use v2.0.1
version
require github.com/anqiansong/foo/v2 v2.0.1
bar
Operating normally
If
major version
you upgradev2
to , if the version is not intended to be forward compatible, and you don’t want to add a version suffix to the module path, you can+incompatible
end .
Other project reference examples arerequire github.com/zsh/foo v2.0.0+incompatible
How to parse the module in the package
The go command first searches the build list for modules prefixed with the package path. For example, if the package is imported example.com/a/b
and the module example.com/a
is in the build list, the go command will check to see example.com/a
if the package b
in . And the directory contains at least one go file, so that it can be considered package
. Generation constraints should not be used for this purpose. If only one module in the build list provides the package, that module is used. go
The command reports an error if no module provides the package, or if two or more modules provide the package . mod=mod
The flag instructs go
the command to try to find new modules providing missing packages, and to update go.mod
and go.sum
. go get
The and go mod tidy
commands do this automatically.
When the go command updates or obtains module dependencies, it will check the GOPROXY
environment variable, GOPROXY
whose value is a comma-separated list of urls, or keywords direct
, off
,
- The specific url separated by commas is the proxy address, which will tell
go
the command to initiate a connection with this value direct
: Specify module dependencies to obtain through the version control systemoff
: Indicates not trying to connect to get the module
If a specific url is GOPROXY
set , assuming that go
the command is looking for one github.com/tal-tech/go-zero/zrpc
, package
the go
command will search for the module in parallel
github.com/tal-tech/go-zero/zrpc
github.com/tal-tech/go-zero
github.com/tal-tech
github.com
If one or more of them match the content github.com/tal-tech/go-zero/zrpc
that satisfies , take the longest module
one as the dependency. After finding the appropriate module and version, go
the command will fill in the go.mod
and go.sum
files require
. If the parsed module
is not actively introduced by the main module , a comment will be added after the value require
of // direct
, and if none of them match, an error will be reported; if GOPROXY
there are multiple url proxies, if the previous one fails, the above steps will be executed to the subsequent proxies in turn.
go.mod file
The identification of a (module project) is to contain a text file coded as and named module
in its root directory . The content in the file is oriented . Each line contains an instruction, and each line consists of a and , like:UTF-8
go.mod
go.mod
行
关键字
参数
module github.com/anqiansong/foo
go 1.16
require github.com/tal-tech/go-zero
require github.com/tal-tech/go-queue
replace go.etcd.io/etcd => go.etcd.io/etcd v0.0.0-20200402134248-51bdeb39e698
retract [v1.0.0, v1.0.1]
Of course, content with the same keyword can be separated and composed with 关键字
+ block
, like:
module github.com/anqiansong/foo
go 1.16
require (
github.com/tal-tech/go-zero
github.com/tal-tech/go-queue
)
replace go.etcd.io/etcd => go.etcd.io/etcd v0.0.0-20200402134248-51bdeb39e698
retract [v1.0.0, v1.0.1]
go.mod
It is machine-writable, like executing some commands (such as: go get
, go mod edit
) may automatically update go.mod
the file .
module components
When parsing the contents of go.mod
the file , it is parsed as
空白符
: contains spaces (U+0020), tabs (U+0009), carriage returns (U+000D) and line feeds (U+000A)注释
: Comments only support single-line comments//
标点
: The punctuation marks are(
,)
,,
,=>
关键字
:go
、require
、replace
、exclude
、retract
标识符
: A character sequence空白符
consisting , such as module path, semantic version字符串
: The interpreted string wrapped in English double quotation marks"
(U+0022) or<
the original string wrapped in (U+0060). Such as"github/com/tal-tech/go-zero"
, ``
标识符
字符串
andgo.mod
can be replaced in syntax
module syntax lexical
go.mod
Extended Backus-Naur Form
Grammars are defined via (EBNF normal form), like
GoMod = { Directive } .
Directive = ModuleDirective |
GoDirective |
RequireDirective |
ExcludeDirective |
ReplaceDirective |
RetractDirective .
module
instruction
module
The keyword defines the module path of the main module go.mod
, and there is only one module
specified in the file.
Grammar rules:
ModuleDirective = "module" ( ModulePath | "(" newline ModulePath newline ")" newline .
Example:
module github.com/tal-tech/go-zero
go
instruction
go
The keyword module
defines the Go language version that is expected to be used. The version must be a valid Go version (it can be understood as conforming to version
the rules, or it can be understood as a version that has been released by Go)
go
After the version is defined by the keyword , the compiler knows which go version should be used to compile the package. In addition, go
the keyword definition version can also be used to enable some features of go
the command , such as whether to automatically start vendoring in the version 1.14
and later .
Grammar rules:
GoDirective = "go" GoVersion newline .
GoVersion = string | ident . /* valid release version; see above */
Example:
go 1.16
require
instruction
require
Declare the minimum version of module dependencies. After require
specifying the version, go
related commands will load dependencies based on this value according to MVS rules.
go
When looking for a dependency, if the dependency is not directly dependent on the main module, // direct
a comment .
Grammar rules:
RequireDirective = "require" ( RequireSpec | "(" newline { RequireSpec } ")" newline ) .
RequireSpec = ModulePath Version newline .
Example:
module github.com/tal-tech/go-zero
go 1.16
require (
golang.org/x/crypto v1.4.5 // indirect
golang.org/x/text v1.6.7
)
excule
instruction
excule
The specified version in the content will be ignored. go 1.16
After , exclude
the specified module will be ignored. go 1.16
Before , if require
the module of is exclude
specified , it will list and obtain the changed exclude
version.
Grammar rules:
ExcludeDirective = "exclude" ( ExcludeSpec | "(" newline { ExcludeSpec } ")" ) .
ExcludeSpec = ModulePath Version newline .
Example:
module github.com/tal-tech/go-zero
go 1.16
exclude golang.org/x/net v1.2.3
excule (
golang.org/x/crypto v1.4.5
golang.org/x/text v1.6.7
)
replace
instruction
replace
The instruction is used to replace the specified version of the module or the module with other modules or versions. If =>
the left quality specifies a version, replace this version to the target content, otherwise replace all versions of the module to the target content
Grammar rules:
ReplaceDirective = "replace" ( ReplaceSpec | "(" newline { ReplaceSpec } ")" newline ")" ) .
ReplaceSpec = ModulePath [ Version ] "=>" FilePath newline
| ModulePath [ Version ] "=>" ModulePath Version newline .
FilePath = /* platform-specific relative or absolute file path */
Example:
replace golang.org/x/net v1.2.3 => example.com/fork/net v1.4.5
=>
The content on the right can be a valid module path, or a relative or absolute path. If it is a relative or absolute path, the root directory of the path must contain go.mod
the file
Example:
require github.com/foo v1.0.0
replace github.com/foo v1.0.0 => ../bar
retract
Command (new in 1.16)
retract
The content of the statement is used to mark certain versions or a certain version range (closed interval) as withdrawn. Generally, a comment needs to be written before retract
the statement When executing go get
the command, if the version retract
marked , or
in retract
Within retract
ofthe marked , go list -m -versions
and the version will also be hidden when getting the version through .
Grammar rules:
RetractDirective = "retract" ( RetractSpec | "(" newline { RetractSpec } ")" ) .
RetractSpec = ( Version | "[" Version "," Version "]" ) newline .
Example:
// someting wrong
retract v1.0.0
// someting wrong in range of versions => v1.0.0~v1.2.0
retrace [v1.0.0,v1.2.0]
Let's take a look at an example. There are github.com/zsh/retract
already v1.0.0
versions such as and so on. Let's add a line retract
of command to mark
v1.0.0
withdrawal:
// someting wrong
retract v1.0.0
Then release a version as , and then refer to the version inv1.0.1
github.com/zsh/bar
v1.0.0
require github.com/anqiansong/retract v1.0.0
Then execute go get github.com/zsh/[email protected]
, no surprises, you will get a prompt containing something wrong
and prompt to update to v1.0.1
the information
$ go get github.com/anqiansong/[email protected]
go: warning: github.com/anqiansong/[email protected]: retracted by module author: someting wrong
go: to switch to the latest unretracted version, run:
go get github.com/anqiansong/retract@latestgo get: downgraded github.com/anqiansong/retract v1.0.1 => v1.0.0
Get github.com/zsh/retract
all module release versions
$ go list -m -versions github.com/anqiansong/retract
github.com/anqiansong/retract v1.0.1
View the results github.com/zsh/[email protected]
of :
-
go get
$ go get github.com/anqiansong/[email protected]
go: warning: github.com/anqiansong/[email protected]: retracted by module author: someting wrong go: to switch to the latest unretracted version, run: go get github.com/anqiansong/retract@latest
-
go list -m -u
$ go get github.com/anqiansong/[email protected]
github.com/anqiansong/retract v1.0.0 (retracted) [v1.0.1]
-
go list -m -versions
$ go list -m -versions github.com/anqiansong/retract
```text
github.com/anqiansong/retract v1.0.1
```
illustrate:
retract
The version of the main module is controlled, not the version of the dependent module.
retract
Other modules of the marked version can still be referenced, but somego
commands willretract
have , as above.
automatic update
Most go
commands . go get
, go mod tidy
command can be used to fix most of these problems. Additionally, -mod=mod
flags can be used on most module-aware commands ( go build
, , go test
etc.) to indicate that go
the command automatically fixes problems ingo.mod
and .go.sum
module perception
Most go commands Module-ware
can GOPATH
be run in either mode or mode. In Module-ware
mode , the go command uses the go.mod file to find version dependencies,
it usually loads packages from the module cache, and downloads the module if it is missing. In GOPATH
mode , the go command ignores module; it looks for dependencies in vendor
the or GOPATH
directories .
As of Go 1.16 go.mod
, Module-ware
the mode is enabled by default regardless of the existence of the file. In earlier versions go.mod
, Module-ware
the mode was enabled when a file existed in the working directory file or any parent directory.
Module-ware
The mode can be controlled via the GO111MODULE environment variable, which can be set to on
, off
orauto
off
:go
The associated command ignoresgo.mod
the file andGOPATH
runs in modeon
:on
or an empty string, the related command will runModule-ware
in modeauto
: If there isgo.mod
a file , it willModule-ware
run in mode. In Go 1.15 and lower versions, this value is the default value.
Some go module related commands
This command must be in Module-ware
mode to be valid
Order | usage | Remark | example |
---|---|---|---|
go list -m | go list -m [-u] [-retracted] [-versions] [list flags] [modules] | View module information | go list -m all |
go mod init | go mod init [module-path] | Initialize and create a go.mod file in the working directory | go mod init demo |
go mod tidy | go mod tidy [-e] [-v] | Organize the go.mod file | go mode tidy |
go clean -modcache | go clean [-modcache] | clear module cache | go clean -modcache |
Proxy
A module proxy is GET
a HTTP
server that supports a response to a request that has no query
parameters and does not even require specific header
information, even if the value is a fixed file system site (eg: file:// URL
).
HTTP
The response status code of the module proxy must contain 200
(OK), 3xx
, 4xx
, 5xx
, 4xx
, 5xx
are considered to be response errors, 404
and 410
indicate that all module requests are unavailable. Note that the contentType of the wrong response should be set to text/plain
, and the character set is utf-8
or us-ascii
.
URLs
go
The command can connect to a proxy server or a version control system by reading GOPROXY
the environment variable configuration, GOPROXY
accepting multiple url values separated by a comma (,) or vertical bar (|), when
separated by an English comma (,), only the response status When the code is 404 or 410, the subsequent proxy address will be tried. If it is separated by a vertical bar (|), any error (including timeout) in http will skip to try the subsequent proxy address. Can also be an direct
or off
keyword.
The following table is a path that a proxy address must implement and has a request response (that is, a proxy server must support the implementation of routing)
$base
For the proxy server address, such as: https://goproxy.cn$module
For module path, such as: github.com/tal-tech/go-zero$version
for the module version
path | describe | example | example result |
$base/$module/@v/list | Return a list of known versions of the given module in plain text, one per line. This list should not include fake versions | curl -X GET https://goproxy.cn/github.com/tal-tech/go-zero/@v/list | v1.0.0 v1.0.1 v1.0.2 v1.0.3 v1.0.4 ... |
type Info struct { Version string // version string Time time.Time // commit time }
</td>
<td>curl -X GET https://goproxy.cn/github.com/tal-tech/go-zero/@v/v1.1.5.info</td>
<td>
<pre>{
“Version”: “v1.1.5”,
“Time”: “2021-03-02T03:02:57Z”
}
module github.com/tal-tech/go-zero
go 1.14
require (
github.com/ClickHouse/clickhouse-go v1.4.3
github.com/DATA-DOG/go-sqlmock v1.4.1
github.com/alicebob/miniredis/v2 v2.14.1
github.com/antlr/antlr4 v0.0.0-20210105212045-464bcbc32de2
…
)
{ "Version": "v1.1.5", "Time": "2021-03-02T03:02:57Z" }
When obtaining the latest version of the module, go
the relevant commands will first request $base/$module/@v/list
the address . If no suitable version is found,
the request $base/$module/@latest
will be obtained and matched to see if it is satisfied. go
The relevant commands will be sorted by release
version , pre-release
version, and pseudo
version.
The $base/$module/$version.mod
and $base/$module/$version.zip
addresses must be provided, because these information can be used go.sum
for .
The downloaded content of the go module is generally stored in $GOPATH/pkg/mod/cache/download
the path , including those downloaded by the version control system.
direct
GOPROXY
If direct
the value is set go
, the module resource will be downloaded from the version control system ( git
, svn
etc.) when the relevant command is executed. Of course, two other environment
variables GOPRIVATE
and GONOPROXY
cooperation are required. For more information about environment variables, please refer to here
module file size constraints
There are a number of restrictions on the content of module zip
files . These constraints ensure that compressed files can be extracted safely and consistently on a wide range of platforms.
A module can be up to 500MiB (whether in compressed or uncompressed form)
go.mod
File requirements are displayed within 16MiB
go.sum
There may be a file go.sum
named , which is directly attached to go.mod. When executing go
related commands to obtain the module,
it will zip
check go.sum
whether the values in the file and are consistent.
go.sum
A value in consists of a module path
, version
and a hash
value, such as:
github.com/anqiansong/retract v1.0.1 h1:jxcsUM/6tvxM7p14/XMeZPFbql5KAAZJfFqiHG+YKxA=
reference documents
- 《Semantic Versioning 2.0.0》
- ["Go Module Official Documentation"](