go 命令记录
本文大部分内容来自于网络摘录,如果想要查看原文,请直接通过附录访问
目录
¶概述
Go 有非常多的命令,本文想要将平时使用到的命令都列举在这里,以发方便后续查看
¶go build
命令
¶go build
编译当前目录
如果我们在执行 go build 命令后不跟任何代码包,那么命令将试图编译当前目录所对应的代码包。
上面提出了一个名词:命令码源文件,在 Go 语言的源码文件有三大类,即:命令源码文件、库源码文件和测试源码文件。他们的功用各不相同,而写法也各有各的特点。
¶go build
编译指定目录
另一种编译logging
包的方法是:在任意目录下,通过指定logging
目录做到编译的目的
¶go build
编译指定多个源文件
go build 还可以同时编译指定的多个 Go 源码文件
1 | pineapple-man@localhost:~/golang/goc2p/src$ go build \ |
但是,使用这种方法会有一个限制。作为参数的多个 Go 源码文件必须在同一个目录中。也就是说,如果想用这种方法既编译 logging 包又编译 basic 包是不可能的。但是在需要的时候,那些被编译目标依赖的代码包会被 go build 命令自动的编译。
go build
命令在编译只包含库源码文件的代码包(或者同时编译多个代码包)时,只会做检查行的编译,而不会输出任何结果文件。
另一方面,如果我们编译的多个属于 main 包的源码文件中没有 main 函数的声明,那么就会使编译器立即报出「 未定义 main 函数声明 」的错误并中止编译。也就是说,在我们同时编译多个 main 包的源码文件时,要保证其中有且仅有一个 main 函数声明,否则编译是无法成功的。
如果我们有多个声明为属于 main 包的源码文件,且其中只有一个文件声明了 main 函数的话,那么是可以使用go build
命令同时编译它们的。在这种情况下,不包含 main 函数声明的那几个源码文件会被视为库源码文件。如此编译后的结果文件的名称将会与我们指定的编译目标中最左边的那个源码文件的主文件名相同。
¶额外参数
除了让 Go 语言编译器自行决定可执行文件的名称,还可以自定义输出文件名称。示例如下:
1 | pineapple-man@localhost:~/golang/goc2p/src/basic/pkginit$ go build -o initpkg initpkg_demo.go |
除此之外,还有一些标记不但受到 go build 命令的支持,而且对于后面会提到的 go install、go run、go test 等命令同样是有效的。下表列出了其中比较常用的标记。
标记名称 | 标记描述 |
---|---|
-a | 强行对所有涉及到的代码包(包含标准库中的代码包)进行重新构建,即使它们已经是最新的了。 |
-n | 打印编译期间所用到的其它命令,但是并不真正执行它们。 |
-p n | 指定编译过程中执行各任务的并行数量(确切地说应该是并发数量)。 在默认情况下,该数量等于CPU的逻辑核数。但是在darwin/arm平台(即iPhone和iPad所用的平台)下,该数量默认是1。 |
-race | 开启竞态条件的检测。 不过此标记目前仅在linux/amd64、freebsd/amd64、darwin/amd64和windows/amd64平台下受到支持。 |
-v | 打印出那些被编译的代码包的名字。 |
-work | 打印出编译时生成的临时工作目录的路径,并在编译结束时保留它。在默认情况下,编译结束时会删除该目录。 |
-x | 打印编译期间所用到的其它命令。注意它与-n标记的区别。 |
执行 go build 命令的计算机如果拥有多个逻辑 CPU 核心,那么编译代码包的顺序可能会存在一些不确定性。但是,它一定会满足这样的约束条件:「 依赖代码包 -> 当前代码包 -> 触发代码包 」
¶buildmode
在 go build 和 go install 命令中,我们可以指定 -buildmode 参数来让编译器构建出特定的对象文件。通过命令 go help buildmode,可以看到其支持的选项:
1 | -buildmode=archive |
¶plugin
build the listed main packages,plus all packages that they import,into a Go plugin.Package not named main are ignored
它将 package main 编译为一个 go 插件,并可在运行时动态加载
1 | package main |
随后将其编译成为一个 go 插件
1 | go build -buildmode=plugin -o greeter.so greeter.go |
最终再使用 golang 官方的 plugin 库来载入这个插件
1 | package main |
¶go install
与 go build 命令一样,传给 go install 命令的代码包参数应该以导入路径的形式提供。并且,go build 命令的绝大多数标记也都可以用于 go install 命令。实际上,go install 命令只比 go build 命令多做了一件事,即:安装编译后的结果文件到指定目录
¶安装代码包
如果 go install 命令后跟的代码包中仅包含库源码文件,那么 go install 命令会把「 编译后的结果 」文件保存在源码文件所在工作区的 pkg 目录下。对于仅包含库源码文件的代码包来说,这个结果文件就是将对应的代码包归档文件(也叫静态链接库文件,名称以.a 结尾)
相比之下,我们在使用 go build 命令对仅包含库源码文件的代码包进行编译时,是不会在当前工作区的 src 目录以及 pkg 目录下产生任何结果文件的。结果文件会出于编译的目的被生成在临时目录中,但并不会使当前工作区目录产生任何变化。
实际上,这种提供代码包位置的方式被叫做本地代码包路径方式,也是被所有 Go 命令接受的一种方式,这包括之前已经介绍过的 go build 命令。但是需要注意的是,本地代码包路径只能以目录相对路径的形式呈现,而不能使用目录绝对路径 。请看下面的示例:
1 | pineapple-man@localhost:~/golang/goc2p/src/cnet/ctcp$ go install -v -work ~/golang/goc2p/src/cnet/ctcp |
以目录绝对路径的形式提供代码包位置是不会被 Go 命令认可的。这是由于 Go 认为本地代码包路径的表示只能以./
或../
开始,再或者直接为.
或..
,而代码包的代码导入路径又不允许以/
开始。所以,这种用绝对路径表示代码包位置的方式也就不能被支持了,这个规则适用于所有 go 命令。
¶安装命令源码文件
1 | pineapple-man@localhost:~/golang/goc2p/src$ go install helper/ds/showds.go |
在环境变量 GOPATH 中包含多个工作区目录路径时,我们需要在编译命令源码文件前先对环境变量 GOBIN 进行设置。实际上,这个环境变量所指的目录路径就是命令程序生成的结果文件的存放目录。go install 命令会把相应的可执行文件放置到这个目录中。
由于命令 go build 在编译库源码文件后不会产生任何结果文件,所以自然也不用会在意结果文件的存放目录。在该命令编译单一的命令源码文件或者包含一个命令源码文件和多个库源码文件时,在结果文件存放目录无效的情况下会将结果文件(也就是可执行文件)存放到执行该命令时所在的目录下。因此,即使环境变量 GOBIN 的值无效,我们在执行 go build 命令时也不会见到这个错误提示信息。
而且,在我们为环境变量 GOBIN 设置了正确的值之后,这个错误提示信息仍然可能会出现。这是因为,只有在安装命令源码文件的时候,命令程序才会将环境变量 GOBIN 的值作为结果文件的存放目录。而在安装库源码文件时,在命令程序内部的代表结果文件存放目录路径的那个变量不会被赋值。最后,命令程序会发现它依然是个无效的空值。所以,命令程序会同样返回一个关于「 无安装位置 」的错误。这就引出一个结论,我们只能使用安装代码包的方式来安装库源码文件,而不能在 go install 命令罗列并安装它们。另外,go install 命令目前无法接受标记-o 以自定义结果文件的存放位置。这也从侧面说明了go install 命令不支持针对库源码文件的安装操作。
¶go get
为了分离自己与第三方的代码,我们会设置两个或更多的工作区。我们现在有一个目录路径为/home/pineapple-man/golang/lib 的工作区,并且它是环境变量 GOPATH 值中的第一个目录路径。注意,环境变量 GOPATH 中包含的路径不能与环境变量 GOROOT 的值重复。好了,如果我们使用 go get 命令下载和安装代码包,那么这些代码包都会被安装在上面这个工作区中。我们暂且把这个工作区叫做 Lib 工作区。
另一方面,如果我们想把一个项目上传到 Github 网站(或其他代码托管网站)上并被其他人使用的话,那么我们就应该把这个项目当做一个代码包来看待。其实我们在之前已经提到过原因,go get 命令会将项目下的所有子目录和源码文件存放到第一个工作区的 src 目录下,而 src 目录下的所有子目录都会是某个代码包导入路径的一部分或者全部。也就是说,我们应该直接在项目目录下存放子代码包和源码文件,并且直接存放在项目目录下的源码文件所声明的包名应该与该项目名相同(除非它是命令源码文件)。这样做可以让其他人使用 go get 命令从 Github 站点上下载你的项目之后直接就能使用它。
¶远程导入路径分析
实际上,go get 命令所做的动作也被叫做代码包远程导入,而传递给该命令的作为代码包导入路径的那个参数又被叫做代码包远程导入路径
go get 命令不仅可以从像 Github 这样著名的代码托管站点上下载代码包,还可以从任何命令支持的代码版本控制系统(英文为 Version Control System,简称为 VCS)检出代码包。任何代码托管站点都是通过某个或某些代码版本控制系统来提供代码上传下载服务的。所以,更严格地讲,go get 命令所做的是从代码版本控制系统的远程仓库中检出/更新代码包并对其进行编译和安装。
对于已存在于本地工作区的代码包,除非要求强行更新代码包,否则 go get 命令不会进行重复下载。如果想要强行更新代码包,可以在执行 go get 命令时加入-u 标记。
¶go clean
¶go doc
& godoc
¶go run
go run 命令可以编译并运行命令源码文件。由于它其中包含了编译动作,因此它也可以接受所有可用于 go build 命令的标记。除了标记之外,go run 命令只接受 Go 源码文件作为参数,而不接受代码包。与 go build 命令和 go install 命令一样,go run 命令也不允许多个命令源码文件作为参数,即使它们在同一个代码包中也是如此。