Menu

01.3. Go 命令

Go 命令

Go 语言自带有一套完整的命令操作工具,你可以通过在命令行中执行 go 来查看它们:

图1.3 Go命令显示详细的信息

这些命令对于我们平时编写的代码非常有用,接下来就让我们了解一些常用的命令。

go build

这个命令主要用于编译代码。在包的编译过程中,若有必要,会同时编译与之相关联的包。

  • 如果是普通包,就像我们在 1.2 节中编写的 mymath 包那样,当你执行 go build 之后,它不会产生任何文件。如果你需要在 $GOPATH/pkg 下生成相应的文件,那就得执行 go install

  • 如果是 main 包,当你执行 go build 之后,它就会在当前目录下生成一个可执行文件。如果你需要在 $GOPATH/bin 下生成相应的文件,需要执行 go install,或者使用 go build -o 路径/a.exe

  • 如果某个项目文件夹下有多个文件,而你只想编译某个文件,就可在 go build 之后加上文件名,例如 go build a.gogo build 命令默认会编译当前目录下的所有 go 文件。

  • 你也可以指定编译输出的文件名。例如 1.2 节中的 mathapp 应用,我们可以指定 go build -o astaxie.exe,默认情况是你的package 名(非 main 包),或者是第一个源文件的文件名(main 包)。

    (注:实际上,package 名在 Go 语言规范 中指代码中 “package” 后使用的名称,此名称可以与文件夹名不同。默认生成的可执行文件名是文件夹名。)

  • go build 会忽略目录下以 _. 开头的 go 文件。

  • 如果你的源代码针对不同的操作系统需要不同的处理,那么你可以根据不同的操作系统后缀来命名文件。例如有一个读取数组的程序,它对于不同的操作系统可能有如下几个源文件:

    array_linux.go
    array_darwin.go
    array_windows.go
    array_freebsd.go

    go build 的时候会选择性地编译以系统名结尾的文件(Linux、Darwin、Windows、Freebsd)。例如 Linux 系统下面编译只会选择array_linux.go 文件,其它系统命名后缀文件全部忽略。

参数的介绍

  • -o 指定输出的文件名,可以带上路径,例如 go build -o a/b/c
  • -i 安装相应的包,编译 + go install
  • -a 更新全部已经是最新的包的,但是对标准包不适用
  • -n 把需要执行的编译命令打印出来,但是不执行,这样就可以很容易的知道底层是如何运行的
  • -p n 指定可以并行可运行的编译数目,默认是 CPU 数目
  • -race 开启编译的时候自动检测数据竞争的情况,目前只支持 64 位的机器
  • -v 打印出来我们正在编译的包名
  • -work 打印出来编译时候的临时文件夹名称,并且如果已经存在的话就不要删除
  • -x 打印出来执行的命令,其实就是和 -n 的结果类似,只是这个会执行
  • -ccflags 'arg list' 传递参数给 5c, 6c, 8c 调用
  • -compiler name 指定相应的编译器,gccgo 还是 gc
  • -gccgoflags 'arg list' 传递参数给 gccgo 编译连接调用
  • -gcflags 'arg list' 传递参数给 5g, 6g, 8g 调用
  • -installsuffix suffix 为了和默认的安装包区别开来,采用这个前缀来重新安装那些依赖的包,-race 的时候默认已经是 -installsuffix race,大家可以通过 -n 命令来验证
  • -ldflags 'flag list' 传递参数给 5l, 6l, 8l 调用
  • -tags 'tag list' 设置在编译的时候可以适配的那些 tag,详细的 tag 限制参考里面的 Build Constraints

go clean

这个命令是用来移除当前源码包和关联源码包里面编译生成的文件。这些文件包括

_obj/            旧的 object 目录,由 Makefiles 遗留
_test/           旧的 test 目录,由 Makefiles 遗留
_testmain.go     旧的 gotest 文件,由 Makefiles 遗留
test.out         旧的 test 记录,由 Makefiles 遗留
build.out        旧的 test 记录,由 Makefiles 遗留
*.[568ao]        object 文件,由 Makefiles 遗留

DIR(.exe)        由 go build 产生
DIR.test(.exe)   由 go test -c 产生
MAINFILE(.exe)   由 go build MAINFILE.go 产生
*.so             由 SWIG 产生

我一般都是利用这个命令清除编译文件,然后 github 递交源码,在本机测试的时候这些编译文件都是和系统相关的,但是对于源码管理来说没必要。

$ go clean -i -n
cd /Users/astaxie/develop/gopath/src/mathapp
rm -f mathapp mathapp.exe mathapp.test mathapp.test.exe app app.exe
rm -f /Users/astaxie/develop/gopath/bin/mathapp

参数介绍

  • -i 清除关联的安装的包和可运行文件,也就是通过 go install 安装的文件
  • -n 把需要执行的清除命令打印出来,但是不执行,这样就可以很容易的知道底层是如何运行的
  • -r 循环的清除在 import 中引入的包
  • -x 打印出来执行的详细命令,其实就是 -n 打印的执行版本

go fmt

有过 C/C++ 经验的读者会知道,一些人经常为代码采取 K&R 风格还是 ANSI 风格而争论不休。在 go 中,代码则有标准的风格。由于之前已经有的一些习惯或其它的原因我们常将代码写成 ANSI 风格或者其它更合适自己的格式,这将为人们在阅读别人的代码时添加不必要的负担,所以 go 强制了代码格式(比如左大括号必须放在行尾),不按照此格式的代码将不能编译通过,为了减少浪费在排版上的时间,go 工具集中提供了一个 go fmt 命令它可以帮你格式化你写好的代码文件,使你写代码的时候不需要关心格式,你只需要在写完之后执行 go fmt <文件名>.go,你的代码就被修改成了标准格式,但是我平常很少用到这个命令,因为开发工具里面一般都带了保存时候自动格式化功能,这个功能其实在底层就是调用了 go fmt。接下来的一节我将讲述两个工具,这两个工具都自带了保存文件时自动化 go fmt 功能。

使用 go fmt 命令,其实是调用了 gofmt,而且需要参数 -w,否则格式化结果不会写入文件。gofmt -w -l src,可以格式化整个项目。

所以 go fmt 是 gofmt 的上层一个包装的命令,我们想要更多的个性化的格式化可以参考 gofmt

gofmt 的参数介绍

  • -l 显示那些需要格式化的文件
  • -w 把改写后的内容直接写入到文件中,而不是作为结果打印到标准输出。
  • -r 添加形如 “a[b:len(a)] -> a[b:]” 的重写规则,方便我们做批量替换
  • -s 简化文件中的代码
  • -d 显示格式化前后的 diff 而不是写入文件,默认是 false
  • -e 打印所有的语法错误到标准输出。如果不使用此标记,则只会打印不同行的前 10 个错误。
  • -cpuprofile 支持调试模式,写入相应的 cpufile 到指定的文件

go get

这个命令是用来动态获取远程代码包的,目前支持的有 BitBucket、GitHub、Google Code 和 Launchpad。这个命令在内部实际上分成了两步操作:第一步是下载源码包,第二步是执行 go install。下载源码包的 go 工具会自动根据不同的域名调用不同的源码工具,对应关系如下:

BitBucket (Mercurial Git)
GitHub (Git)
Google Code Project Hosting (Git, Mercurial, Subversion)
Launchpad (Bazaar)

所以为了 go get 能正常工作,你必须确保安装了合适的源码管理工具,并同时把这些命令加入你的 PATH 中。其实 go get 支持自定义域名的功能,具体参见 go help remote

参数介绍:

  • -d 只下载不安装
  • -f 只有在你包含了 -u 参数的时候才有效,不让 -u 去验证 import 中的每一个都已经获取了,这对于本地 fork 的包特别有用
  • -fix 在获取源码之后先运行 fix,然后再去做其他的事情
  • -t 同时也下载需要为运行测试所需要的包
  • -u 强制使用网络去更新包和它的依赖包
  • -v 显示执行的命令

go install

这个命令在内部实际上分成了两步操作:第一步是生成结果文件(可执行文件或者 .a 包),第二步会把编译好的结果移到 $GOPATH/pkg 或者 $GOPATH/bin

参数支持 go build 的编译参数。大家只要记住一个参数 -v 就好了,这个随时随地的可以查看底层的执行信息。

go test

执行这个命令,会自动读取源码目录下面名为 *_test.go 的文件,生成并运行测试用的可执行文件。输出的信息类似

ok   archive/tar   0.011s
FAIL archive/zip   0.022s
ok   compress/gzip 0.033s
...

默认的情况下,不需要任何的参数,它会自动把你源码包下面所有 test 文件测试完毕,当然你也可以带上参数,详情请参考 go help testflag

这里我介绍几个我们常用的参数:

  • -bench regexp 执行相应的 benchmarks,例如 -bench=.
  • -cover 开启测试覆盖率
  • -run regexp 只运行 regexp 匹配的函数,例如 -run=Array 那么就执行包含有 Array 开头的函数
  • -v 显示测试的详细命令

go tool

go tool 下面下载聚集了很多命令,这里我们只介绍两个,fix 和 vet

  • go tool fix . 用来修复以前老版本的代码到新版本,例如 go1 之前老版本的代码转化到 go1,例如 API 的变化
  • go tool vet directory|files 用来分析当前目录的代码是否都是正确的代码,例如是不是调用 fmt.Printf 里面的参数不正确,例如函数里面提前 return 了然后出现了无用代码之类的。

go generate

这个命令是从 Go1.4 开始才设计的,用于在编译前自动化生成某类代码。go generatego build 是完全不一样的命令,通过分析源码中特殊的注释,然后执行相应的命令。这些命令都是很明确的,没有任何的依赖在里面。而且大家在用这个之前心里面一定要有一个理念,这个 go generate 是给你用的,不是给使用你这个包的人用的,是方便你来生成一些代码的。

这里我们来举一个简单的例子,例如我们经常会使用 yacc 来生成代码,那么我们常用这样的命令:

go tool yacc -o gopher.go -p parser gopher.y

-o 指定了输出的文件名, -p 指定了 package 的名称,这是一个单独的命令,如果我们想让 go generate 来触发这个命令,那么就可以在当然目录的任意一个 xxx.go 文件里面的任意位置增加一行如下的注释:

// go:generate go tool yacc -o gopher.go -p parser gopher.y

这里我们注意了,//go:generate 是没有任何空格的,这其实就是一个固定的格式,在扫描源码文件的时候就是根据这个来判断的。

所以我们可以通过如下的命令来生成,编译,测试。如果 gopher.y 文件有修改,那么就重新执行 go generate 重新生成文件就好。

$ go generate
$ go build
$ go test

godoc

在 Go1.2 版本之前还支持 go doc 命令,但是之后全部移到了 godoc 这个命令下,需要这样安装 go get golang.org/x/tools/cmd/godoc

很多人说 go 不需要任何的第三方文档,例如 chm 手册之类的(其实我已经做了一个了,chm 手册),因为它内部就有一个很强大的文档工具。

如何查看相应package的文档呢?
例如 builtin 包,那么执行 godoc builtin
如果是 http 包,那么执行 godoc net/http
查看某一个包里面的函数,那么执行 godoc fmt Printf
也可以查看相应的代码,执行 godoc -src fmt Printf

通过命令在命令行执行 godoc -http=:端口号 比如 godoc -http=:8080。然后在浏览器中打开 127.0.0.1:8080,你将会看到一个 golang.org 的本地 copy 版本,通过它你可以查询 pkg 文档等其它内容。如果你设置了 GOPATH,在 pkg 分类下,不但会列出标准包的文档,还会列出你本地 GOPATH 中所有项目的相关文档,这对于经常被墙的用户来说是一个不错的选择。

其它命令

go 还提供了其它很多的工具,例如下面的这些工具

go version 查看 go 当前的版本
go env 查看当前 go 的环境变量
go list 列出当前全部安装的 package
go run 编译并运行 Go 程序

以上这些工具还有很多参数没有一一介绍,用户可以使用 go help 命令 获取更详细的帮助信息。

本文章首发在 GolangCaff
上一篇 下一篇
讨论数量: 0
发起讨论


暂无话题~