命令介绍

go 语言自带了一些命令行命令,熟悉这些命令对开发有一定的好处。

可以使用 gogo help 查看

往下看,有

故我们可以使用 go help cmd_name 命令查看具体的命令,如 go help build

也可以直接查看 官方文档, 下面我们来讲解一些常用的命令,主要参考官方文档和使用实际的例子来说明

go build

使用 go help build 查看详情或者直接在官方文档查看,为了方便,这里统一使用官方文档,而不使用截图

介绍

go build 只会编译 main 包下的 main 文件。我们知道 go 的入口文件是 main 包,入口函数是 main 函数,故 go build 编译也只会从这里开始编译,如果在其他包,或者 main 包下没有 main 函数,要么得不到结果,要么报错。

go build 编译生成的二进制文件在当前目录。

go build 命令用于编译 package 和依赖包。但是仅仅用于编译,并没有 install,比如常用的 tldr 命令,这是用 go 编写的命令行提示工具,使用 go build 命令只是编译得到了结果,并没有安装到 pc 中; 同时也没有 run, 编译得到了一个二进制文件,根据平台不同得到的结果不同,在 win 下是 exe 文件,在 Linux 下则是个无后缀的二进制文件。

这里我们使用一个简单的例子

.
├── go.mod
├── go.sum
└── main.go

go.mod 和 go.sum 文件是 mod 包管理工具产生的,不用管。在 main.go 中

package main

import "fmt"

func main() {
	fmt.Println("Hello World")
}

然后我们进入项目所在目录,我们这里给项目取为 gee, 目录是 $GOPATH/src/gee, 进入此目录后,使用 go build main.go 命令,可以看到得到了一个 main 文件,我们可以使用 ./main 命令执行这个二进制文件,会发现输出了 Hello World, 说明我们成功了。

使用

查看文档,我们发现

go build [-o output] [-i] [build flags] [packages]

我们发现有几个参数, o, i, falgs, packages

其中每个都不是必选的,packages 是包名,如果我们不加包名,那么会自动编译当前目录下的 main 函数,当然此包需要是 main 包且有 main 函数。

我们知道 go 只 package 是以目录为单位的,一个 directory 下都是一个目录,故 packages 参数可以为目录下的 main 函数所在文件,也可以是目录名。如果是文件,则默认生成的二进制文件就是这个文件名,如果是目录名或不加,这默认是目录名,如果是顶级目录,则默认是项目名,下面我们来举个例子

.
├── app
│   └── num.go
├── cmd
│   └── main.go
├── go.mod
├── go.sum
└── main.go

这个项目名 gee,有两个 main 包,根目录下的 main.go 和 cmd 目录。一个公共包,即 app。

现在我们在 $GOPATH/src/gee 目录下使用 go build, 根据上面的分析,我们会得到一个名为 gee 的二进制文件,这个文件就是编译 main.go 得到的。如果 main.go 中使用了其他包的函数,则同时编译这些依赖包。

现在我们仍然在此目录,使用命令 go build main.go, 我们会得到一个名为 main 的二进制文件,此文件也是编译 main.go 得到的。

现在我们进入 cmd 目录。使用 go build,我们会得到一个 名为 cmd 的二进制文件。

现在我们仍在此目录,使用 go build main.go 我们会得到一个 名为 main 的二进制文件。

现在我们进入 app 目录,使用 go build, 得不到任何文件。使用 go build num.go, 也得不到任何文件。

如果我们想要自定义输出的二进制文件名字,可以使用 o 参数,o 参数即 output 的缩写,容易理解,如 go build -o hah main.go, 我们就会得到 hah 文件。

如果我们使用的包是网络上的,如使用了 github 上的末个包,那么我们可以使用先安装依赖,或者直接使用 i 参数,先下载好依赖包,再编译。i 即 install 的缩写,容易理解,如 go build -i main.go

当我们对 main 包里的函数写测试文件时,测试文件也是 main 包下的,而 go build 命令会自动忽略测试文件,也就是 _test.go 文件。

go install

在讲解此命令前,我们先了解一下 $GOPATH 这个环境变量,这个目录是工作目录,也就是说平时写代码时就用的这个目录,这个目录下一般有三个子目录

.
├── bin
├── pkg
├── src

分别是 binary,package,source 的缩写,我们容易理解它们的意思。

binary 即二进制,也就是说可执行文件,一般用于放系统使用的工具,如使用 go 命令装了一个命令行工具 tldr,那么可执行文件就放在这个目录,然后在系统上配置好环境变量,就可以直接使用这个工具。既然是可执行文件,那么编写源码的时候就需要有 main 包 和 main 函数,所以这里放置编译 main 包 main 函数后的文件。

package 即包,也就是库文件,这里同样放置二进制可行性文件,但是不同于 bin 目录下放置工具,这里放置一些公共文件,也就是供其他文件使用的库文件。所以编写源码时没有 main 包 main 函数,如我们常用的 github 下许多库文件就放在这个目录。

source 即源码,所以这个目录用于放置我们实际的项目文件。

介绍

现在我们已经知道了这些目录的意义,那么对于 go install 目录就比较容易理解了。

go install 用于编译和安装包。我们已经知道编译是怎么一回事,所以 go install 就是在 go build 的基础上,再安装包,安装的意思就是把可行性文件放置到特定目录再配置环境变量。所以 go install 就是先编译后,再把二进制文件移动到特定目录。

go install 编译后的文件在特定目录。我们知道项目有 入口函数和没有如何函数两种类型,同样的,对于这两种情况移动到的目录也不同。没有入口函数的移动到 $GOPATH/pkg 目录,有入口函数的移动到 $GOPATH/bin 目录。

使用

go install [-i] [build flags] [packages]

查看文档发现 go install 的使用和 go build 大部分都是相似的,只是不能使用 o 参数自定义输出。我们来举个实例

仍然是 gee 项目

.
├── app
│   └── num.go
├── cmd
│   └── main.go
├── go.mod
├── go.sum
└── main.go

在 cmd 目录,使用 go install, 然后查看结果

cd $HOME/go/bin && ls

会发现 cmd 文件

在 app 目录,使用 go install,然后查看结果

 cd $HOME/go/pkg/linux_amd64 && ls

会发现一个 gee/app.a 文件

如果函数中使用了其他库文件,也可以加上 i 参数安装库文件。

go get

介绍

go get 使用代码管理工具,拉取,编译,安装远程包。代码管理工具用于下载代码,然后使用 go install 命令编译和安装包。如果使用 git 的话,就类似于使用 git clone 再 go install。

不同站点使用的代码管理工具不同。常使用的 github 和 google code 都是使用的 git 作为代码管理工具。所以在拉去包前需要先安装好代码管理工具。

远程包的路径格式。远程包都有一个标准格式,如下

github.com/golang/go@v1.6.3

网站域名:代码托管的网站,如 github.com
作者或机构:这个项目的归属,如 golang
项目名: 这个项目的名字,如 go
版本号: 默认拉取最新版本,所以也可以用于更新库文件,如果要指定版本,则格式为 @v+本版号,如 @v1.6.3

mod 开启时,go get 的下载路径为 $GOPATH/pkg/mod, 当 mod 关闭时,go get 的下载路径为 $GOPATH/src。

使用

go get [-d] [-t] [-u] [-v] [-insecure] [build flags] [packages]

packages 参数是必须的。也就是我们刚介绍的远程包的路径。如我们要拉去常用的 gin 框架,那么我们可以使用

go get github.com/gin-gonic/gin

然后查看

ls /home/edte/go/pkg/mod/github.com/gin-gonic

得到 gin@v1.6.3,则拉取成功。

也可以指定版本号

go get github.com/gin-gonic/gin@v1.6.2
ls /home/edte/go/pkg/mod/github.com/gin-gonic

得到 gin@v1.6.2gin@v1.6.3

  • 如果拉取过慢的话,可以自己设置好代理,或者使用官方的代理
go env -w GOPROXY=https://goproxy.cn,direct
  • 如果想要知道拉取的进度的话,可以使用 v 参数,v 是 ?的缩写。
go get -v github.com/gin-gonic/gin

就能看到进度

github.com/gin-gonic/gin/internal/bytesconv
github.com/gin-gonic/gin/internal/json
github.com/gin-gonic/gin/binding
github.com/gin-gonic/gin/render
github.com/gin-gonic/gin
  • 如果我们只想下载而不编译安装,那么可以加上 d 参数,d 是 download 的缩写,比较容易理解。

go get -v -d github.com/gin-gonic/gin

然后查看

ls /home/edte/go/pkg/mod/github.com/gin-gonic

gin@v1.6.3 则拉取成功,然后进入会发现并没有编译,但是直接使用 go get 拉取时也没有编译,故这里看不出区别,因为 gin 包是个没有可执行文件的项目,如果拉取那些有可执行文件的项目,使用 go get 才会编译。

go run

介绍

go run 编译并运行 main 包。go run 先编译 main 包下的 main 函数,然后运行这个文件。

go run 没有产生可执行文件。使用 go build 命令时会在当前目录生成可执行文件,而使用 go run 没有生成可执行文件。如果想要知道编译的过程,我们知道 go 是传统的编程语言,有 编写-编译-链接-运行 这个过程,所以在编译的过程会产生临时文件,go build 就到链接,而 go run 则到运行。可以使用 work 参数,这个参数会输出临时目录的路径。

使用

go run [build flags] [-exec xprog] package [arguments...]

package 参数是必须的,即是具体的入口函数所在的文件路径。我们举个例子

//main.go

package main

import "fmt"

func main() {
	fmt.Println("Hello World")
}

使用 go run main.gogo run /gee/main.go 会得到结果 Hello World

  • 如果要查看过程,则可以加上 v 参数
go run -v main.go
  • 如果要查看临时目录的路径,则加上 work 参数
go run -work main.go

会得到

WORK=/tmp/go-build409560032
Hello World

我们会发现临时目录是 /tmp/go-buildxxx

  • 如果需要使用命令行参数,那么直接在 package 后加上即可,即 arguments 参数
package main

import (
	"fmt"
	"os"
)

func main() {
	fmt.Println(os.Args)
}

查看 os.Args 源码

var Args []string

发现 Args 是个 string 切片,第一个元素是文件的路径

go run main.go hhh

会得到

[/tmp/go-build246132840/b001/exe/main hhh]

go mod

介绍

由于 go 的包管理早期非常糟糕,也比较复杂,这里只简单介绍一下早期其他的包管理。

  • 在 1.5版本前,所以依赖包都放在 GOPATH 下,没有版本控制。如果两个项目依赖不同版本的包,这时候就容易出现兼容问题。为了解决这个问题,早期一般使用多个 GOPATH 来控制依赖,但对于那些相同的依赖管理也非常麻烦。而且多个 GOPATH 也比较让人头疼。
  • 1.5 版本推出了 vender 机制,所谓 vender 机制,也就是在每个项目都有一个 vender 目录,里面存放这个项目的依赖。go build 的时候先到 vender 目录查找依赖,没找到再到 GOPATH 下寻找依赖。这种方式依然让人不爽,一个项目有两个地方存放依赖,那么自然就会引出许多问题。
  • 1.11 版本推出了 modules 机制,即 go mod。mod 机制把所有依赖都放在 $GOPATH/pkg/mod 目录下,里面可以存放着不同版本的依赖。然后在每个项目中都有一个 mod 文件,在这里设置使用的依赖类型和版本。这样迁移项目和管理依赖都方便许多。

使用

首先打开 go mod 需要 设置 GO111MODUL 环境变量,不过最新现在已经默认开启。

使用 go mod help 查看一下 go mod 命令

download    download modules to local cache (下载依赖的module到本地cache))
edit        edit go.mod from tools or scripts (编辑go.mod文件)
graph       print module requirement graph (打印模块依赖图))
init        initialize new module in current directory (再当前文件夹下初始化一个新的module, 创建go.mod文件))
tidy        add missing and remove unused modules (增加丢失的module,去掉未用的module)
vendor      make vendored copy of dependencies (将依赖复制到vendor下)
verify      verify dependencies have expected content (校验依赖)
why         explain why packages or modules are needed (解释为什么需要依赖)

现在我们来用实际例子讲解 go mod 的应用。

我们现在知道 GOROOT 是 go 的安装目录,go 的标准库都放在这里。然后我们又知道 GOPATH 是工作目录,子目录 bin, pkg, src 都比较明确。所以建议项目的实际目录就放在 $GOPATH/src 下,这样每个目录的功能都很明显。但是 go mod 现在似乎只支持 $GOPATH/src 目录外,在这个目录仍然到 $GOPATH/src 而不是 $GOPATH/pkg/mod 下寻找依赖。不过实际上我使用也是支持 mod 的,也就是到 $GOPATH/pkg/mod 下寻找,原因我还没有找到。

现在我们在 $GOPATH/src/ 下建立项目 gee

然后使用

go mod init

命令初始化建立 go.mod 文件,现在就开启 mod 支持了。

我们查看一下这个文件 cat go.mod

module gee

go 1.14

这两个我们容易理解,即 gee 模块,和 go 的版本。

现在我们新建一个 main.go 文件

.
└── main.go
package main

import "github.com/gin-gonic/gin"

func main() {
	r := gin.Default()
	r.Run()
}

我们使用了 gin 框架,当然现在是无法使用的,假设我们本地也没有这个库,现在我们需要 go build 或 go run 一下来激发 go mod机制。

go run main.go

我们能够看到日志是在下载 gin 和相关的依赖,然后就 run 起来了。

我们会发现多出了一个 go.sum 文件,cat 一下,发现是相关依赖和对于的 hash 值,平时也用不用管。

现在我们查看一下这个库

ls $GOPATH/pkg/mod/github.com

出现 gin-gonic 这个文件,说明 go mod 机制出发成功了。现在我们再来看一下 go.mod 文件

cat go.mod
module wgwg

go 1.14

require (
    github.com/gin-gonic/gin v1.6.3
)

我们看到出现了一个 require 关键字。require 关键字即此项目的依赖列表。我们可以把 go.mod 文件删除,或者再新建一个项目,同样的使用 gin 框架,然后再 run 一下,我们会发现日志里没有再出现下载库的情况,说明 go mod 是先在本地查找依赖是否存在,如果不存在,再去拉取远程库。

go mod tidy 命令会删除那些没有 import,但是 require 了的包。然后会把 import 了包放到 require 中,然后到 $GOPATH/pkg/mod 中检查这个包是否存在,如果存在,则导入这个包,如果不存在,则拉取这个包。所以这个命令可以用来清楚没有使用的依赖,导入依赖和批量拉取依赖。

  • 如果 go mod 中有些依赖我们没有使用,可以使用
go mod tidy

命令清除没有使用的依赖。

  • 如果我们使用了 go mod ,明明本地也有这个库,但是却无法使用,如在 goland 中 报红,我们同样可以使用
go mod tidy

命令,这个命令会去 $GOPATH/pkg/mod 路径查找。因为虽然使用了 go mod ,但是 go mod 并没有扫描 /pkg/mod 路径,不能获取本地库列表,如果使用 Goland 的话,新建 go mod 文件时,就有一个 Index 弹窗用于扫描目录。

  • 如果我们有些依赖本地没有,想要拉取,可以使用
go mod tidy

命令批量拉取。

我日

  • 如果我们需要拉取特定本版号的包,可以使用 go get 命令。

  • 如果需要拉取所有依赖,可以使用 go mod download 命令

  • 如果拉取速度较慢,可以修改 GOPROXY 设置代理,具体可以看 go env。

  • 如果在一些特殊情况,如没有网络,在本地迁移项目的话,可以把使用 vendor 代替 mod 机制,这样移动项目时直接把依赖移动走了。使用

go mod vendor

命令会在项目根目录新建 vendor 目录,会把依赖复制到这个目录。

  • 如果使用末个包,但是这个包改名了,这时候想要继续使用原来的包名,又要拉取最新的包。或者使用末个包,但是这个包在原来的地方下载不了,只能到其他地方下载,那么可以使用 replace 关键字

如 goland.org/x/text 包在国内无法下载,但是 github 上有备份,那么可以使用

replace 
	golang.org/x/text v0.3.0 => github.com/golang/text v0.3.0
)

到 github 拉取会当做 goland.org/x/text 包使用。

更多的请看 go mod wiki go blog 关于 mod 系列文章 一篇优秀的文章

go env

go env 命令用于查看和设置 go 环境变量。

go env [-json] [-u] [-w] [var ...]

默认没有参数会以行模式输出所有环境变量,可以输入 go env 查看,由又环境变量比较多,这里只介绍常用的几个。

如果要查看具体的莫个或多个的环境变量,直接在 env 后加上即可,即 var 参数

go env GOPATH GOROOT,我的结果

/home/edte/go
/usr/lib/go

如果想要输出 json 格式的结果,则加上 json 参数

go env -json GOPATH GOROOT

{
        "GOPATH": "/home/edte/go",
        "GOROOT": "/usr/lib/go"
}

如果要删除末个变量,则可以直接设为空字符,或者使用 u 参数,即 unset

go env -u GOBIN

如果要更改末个变量,则需要使用 w 参数,即 write

go env -w GOPROXY=https://goproxy.io,direct

下面是常见的环境变量

  • GOROOT

GOROOT 是刚安装 go 时会遇到的一个环境变量, GOROOT 用于存放 go 的安装路径,如标准库,工具链等就放在这个位置。一般安装 go 时会默认设置,从而无需手动设置,win 下一般在 C:\go,可以使用 go env GOROOT 查看。

  • GOPATH

GOPATH 也是安装 go 时会遇到的一个环境变量,用于存放工作目录。也就是实际工作时用到的目录,我们在 go install 中已经讲解了这个路径的具体作用。这个目录用于存放实际的项目源码以及用到的远程库文件。

  • GOBIN

GOBIN 是默认的一个环境变量,一般不用设置。我们在 go install 中说过,安装可执行程序时,会安装到 $GOPATH/bin 目录,这个目录就是 GOBIN ,我们也可以更改,不过一般不建议改。

  • GOOS 和 GOARCH

go 本身支持交叉编译,也就是可以在一个平台上生成另一个平台的可执行程序。因此需要设置目标操作系统和目标系统架构。GOOS 即 go os ,os 即操作系统,GOARCH 即 go arch,arch 即体系架构。

$ go env -json GOOS GOARCH  
{
        "GOARCH": "amd64",
        "GOOS": "linux"
}

可以看到这两个值默认是本机的。如我们要生成 64 位的 win,使用 go env -w GOOS=windows 设置 os,再使用 go build main.go 就得到了 main.exe,我们知道 exe 是 win 下可执行程序的后缀,故成功了。

如果目标系统是 mac 或 linux ,可以使用 uanme -a 查看,如果是 win ,直接看 32 位还是 64 位即可。

下面是常用的

$GOOS $GOARCH
windows 386
windows amd64
linux 386
linux amd64
linux arm
linux arm64
  • GOPROXY

使用 go mod 管理包拉取依赖时,包服务器一般在国外,拉取速度比较慢,一般我们可以自己设置代理,不过 go mod 官方自带了一个 代理方式,通过修改 GOPROXY 变量即可修改 go mod 拉取的代理。

go env -w GOPROXY=https://goproxy.cn,direct
  • GO111MODULE

GO111MODULE 即 go1.11 版本推出的 go mod 机制。go mod 是最新的一种包管理工具。在 1.12 前 go mod 是默认关闭的,不过 1.13 后便默认开启了

状态 功能
on 打开 go mod
off 关闭 go mod
auto 自动判断是否打开 go mod

最新版一般都是默认打开的,建议不要修改。

go doc

待续

0

1

2