About the go command

Go发行版包含一个名为" go "的命令,该命令可自动执行Go软件包和命令的下载,构建,安装和测试. 本文档讨论了我们编写新命令的原因,它是什么,不是什么以及如何使用它.

Motivation

您可能已经看过早期的Go谈话,在其中Rob Rob Pike开玩笑说,在等待大型Google服务器编译时出现了Go的想法. 这确实是Go语言的动机:构建一种语言,该语言对于构建Google编写和运行的大型软件非常有效. 从一开始就很明显,这种语言必须提供一种方法来清楚地表达代码库之间的依赖关系,因此可以进行程序包分组和显式导入块. 从一开始就很明显,您可能希望使用任意语法来描述要导入的代码; 这就是为什么导入路径是字符串文字.

从一开始,Go的一个明确目标就是能够仅使用源代码本身中的信息来构建Go代码,而无需编写Makefile或许多现代的Makefile替代之一. 如果Go需要一个配置文件来说明如何构建程序,那么Go将会失败.

最初,没有Go编译器,最初的开发重点是构建一个然后编译它的库. 为了方便起见,我们推迟了使用make和编写makefile来构建Go代码的自动化. 当编译涉及Go编译器多次调用的单个程序包时,我们甚至使用了一个程序来为我们编写makefile. 如果您浏览存储库历史记录,则可以找到它.

新的go命令的目的是使我们回到这一理想状态,即Go程序应在编写程序时无需进行配置或其他工作,而无需编写必要的import语句.

Configuration versus convention

实现无配置系统的简单性的方法是建立约定. 该系统仅在遵循这些约定的范围内起作用. 当我们首次启动Go时,许多人发布了必须使用特定的构建工具以特定名称安装在特定位置的软件包才能使用. 这是可以理解的:这就是它在大多数其他语言中的工作方式. 在过去的几年中,我们一直提醒人们有关goinstall命令(现在已由go get代替)及其约定:首先,导入路径以已知方式从源代码的URL派生. 第二,在本地文件系统中存储源的位置是从导入路径以已知方式导出的; 第三,源树中的每个目录对应一个包. 第四,仅使用源代码中的信息构建软件包. 今天,绝大多数软件包都遵循这些约定. 结果,Go生态系统变得更简单,功能更强大.

我们收到了许多请求,以允许程序包目录中的makefile提供一些超出源代码中内容的额外配置. 但这会引入新的规则. 因为我们不接受这样的请求,所以我们能够编写go命令并消除对make或任何其他构建系统的使用.

重要的是要了解go命令不是通用的构建工具. 它无法配置,除了Go软件包之外,它不会尝试构建其他任何内容. 这些是简化假设的重要假设:它们不仅简化了实现,而且更重要的是简化了工具本身的使用.

Go's conventions

go命令要求代码遵循一些关键的,公认的约定.

首先,以已知方式从源代码的URL导出导入路径. 对于Bitbucket,GitHub,Google Code和Launchpad,存储库的根目录由存储库的主URL标识,不带http://前缀. 子目录通过添加到该路径来命名. 例如,Go示例程序是通过运行获得的

git clone https://github.com/golang/example

因此该存储库根目录的导入路径为" github.com/golang/example ". stringutil软件包存储在一个子目录中,因此其导入路径为" github.com/golang/example/stringutil ".

These paths are on the long side, but in exchange we get an automatically managed name space for import paths and the ability for a tool like the go command to look at an unfamiliar import path and deduce where to obtain the source code.

其次,以一种已知的方式从导入路径(特别是$GOPATH/src/<import-path> )派生在本地文件系统中存储源的位置. 如果未设置,则$GOPATH默认为用户主目录中名为go的子目录. 如果$GOPATH设置为路径列表,则go命令将对该列表中的每个目录尝试<dir>/src/<import-path> .

按照约定,这些树中的每一个都包含一个名为" bin "的顶级目录(用于保存编译的可执行文件)和一个名为" pkg "的顶级目录(用于保存可以导入的编译包)以及一个" src "目录. ,用于保存软件包源文件. 强加这种结构使我们能够使所有这些目录树保持独立:编译的表单和源始终彼此靠近.

这些命名约定也使我们可以从目录名称到其导入路径进行反向操作. 正如我们将在下面看到的,此映射对于go命令的许多子命令很重要.

第三,源树中的每个目录对应一个包. 通过将目录限制为单个软件包,我们不必创建混合导入路径,该路径首先指定目录,然后指定该目录中的软件包. 另外,大多数文件管理工具和UI都以目录为基本单位工作. 将基本的Go单元(包)绑定到文件系统结构意味着文件系统工具成为Go包工具. 复制,移动或删除软件包与复制,移动或删除目录相对应.

第四,每个软件包仅使用源文件中存在的信息构建. 这使该工具更有可能适应不断变化的构建环境和条件. 例如,如果我们允许进行额外的配置,例如编译器标志或命令行配方,那么每次更改构建工具时,都需要更新该配置; 它也将固有地与特定工具链的使用联系在一起.

Getting started with the go command

最后,快速浏览如何使用go命令. 如上所述,Unix上的默认$GOPATH$HOME/go . 我们将程序存储在那里. 要使用其他位置,可以设置$GOPATH ; 有关详细信息,请参见如何编写Go代码 .

我们首先添加一些源代码. 假设我们要使用codesearch项目中的索引库以及左倾的红黑树. 我们可以使用" go get "子命令进行安装:

$ go get github.com/google/codesearch/index
$ go get github.com/petar/GoLLRB/llrb
$

这两个项目现在都已下载并安装到$HOME/go ,其中包含两个目录src/github.com/google/codesearch/index/src/github.com/petar/GoLLRB/llrb/以及已编译的目录.这些库及其依赖项的软件包(以pkg/ ).

因为我们使用版本控制系统(Mercurial和Git)检出源,所以源树还包含相应存储库中的其他文件,例如相关软件包. " go list "子命令列出了与其参数相对应的导入路径,模式" ./ ./... "表示从当前目录(" ./ ")开始,并找到该目录下的所有软件包(" ... "). ):

$ cd $HOME/go/src
$ go list ./...
github.com/google/codesearch/cmd/cgrep
github.com/google/codesearch/cmd/cindex
github.com/google/codesearch/cmd/csearch
github.com/google/codesearch/index
github.com/google/codesearch/regexp
github.com/google/codesearch/sparse
github.com/petar/GoLLRB/example
github.com/petar/GoLLRB/llrb
$

我们还可以测试这些软件包:

$ go test ./...
?   	github.com/google/codesearch/cmd/cgrep	[no test files]
?   	github.com/google/codesearch/cmd/cindex	[no test files]
?   	github.com/google/codesearch/cmd/csearch	[no test files]
ok  	github.com/google/codesearch/index	0.203s
ok  	github.com/google/codesearch/regexp	0.017s
?   	github.com/google/codesearch/sparse	[no test files]
?       github.com/petar/GoLLRB/example          [no test files]
ok      github.com/petar/GoLLRB/llrb             0.231s
$

如果在未列出路径的情况下调用go子命令,它将在当前目录上运行:

$ cd github.com/google/codesearch/regexp
$ go list
github.com/google/codesearch/regexp
$ go test -v
=== RUN   TestNstateEnc
--- PASS: TestNstateEnc (0.00s)
=== RUN   TestMatch
--- PASS: TestMatch (0.00s)
=== RUN   TestGrep
--- PASS: TestGrep (0.00s)
PASS
ok  	github.com/google/codesearch/regexp	0.018s
$ go install
$

该" go install "子命令会将软件包的最新副本安装到pkg目录中. 因为go命令可以分析依赖关系图,所以" go install "还可以递归地安装此软件包导入但已过期的所有软件包.

注意,由于目录命名约定," go install "能够确定当前目录中软件包的导入路径的名称. 如果我们可以选择保存源代码的目录名称,并且可能不会选择这么长的名称,那会更方便一些,但是这种能力需要工具中的额外配置和复杂性. 输入额外的一两个目录名是为了提高简便性和功能而付出的小代价.

Limitations

如上所述,go命令不是通用构建工具. 特别是,它没有提供在生成过程中生成Go源文件的功能,尽管它确实提供了go generate ,它可以在生成之前自动创建Go文件. 对于更高级的构建设置,您可能需要编写一个makefile(或您选择的构建工具的配置文件)以运行创建Go文件的任何工具,然后将这些生成的源文件检入到存储库中. 软件包作者,这对您来说是更多的工作,但对您的用户而言却要少得多,他们可以使用" go get "而无需获取和构建任何其他工具.

More information

有关更多信息,请阅读如何编写Go代码并参阅go命令文档 .

by  ICOPY.SITE