一、go 环境变量
GOROOT
该环境变量的值为Go语言的安装目录。如:
export GOROOT=/usr/local/go
GOPATH
Go语言工作区间集合。如:
export GOPATH=~/golib:~/goproject
GOBIN
存放Go程序可执行文件的目录。如:
export GOBIN=~/gobin
PATH
为了方便使用Go语言命令和Go程序的可执行文件,需要追加其值。如:
export PATH=$PATH:$GOROOT/bin:$GOBIN
二、工作区和GOPATH
工作区结构参考
/home/mxy/golib:
src/
pkg/
bin/
src 目录
主要用来存放源码文件,使用代码包的组织方式。
源码文件说明
源码文件分为命令源码文件、库源码文件、测试源码文件
- 命令源码文件
声明自己属于main代码包、包含无参数声明和结果声明的main函数
被安装后,相应的可执行文件会被存放到GOBIN指向的目录或者<当前工作区目录>/bin下
go build命令安装
- 库源码文件
不具备命令源码文件的两个特征的源码文件
被安装后,相应的归档文件会被存放到<当前工作区目录>/pkg/<平台相关目录> 下
go install 命令安装
- 测试源码文件
不具备命令源码文件的那两个特征的源码文件
名称以_test.go为后缀,其中至少有一个Test或者Benchmark前缀的方法,并且接收一个类型为testing.T或者testing.B的参数。如:
func TestHelloWorld(t *testing.T) {
t.Log("hello world")
}
或者
func BenchmarkTest(b *testing.B) {
b.Log("hello world")
}
pkg目录
用于存放归档文件(名称以.a为后缀的文件)
所有归档文件都会被存放到该目录下的平台相关目录中,同样以代码包为组织形式
平台相关
go包含两个隐藏的环境变量:GOOS 和 GOARCH
以$GOOS $GOARCH为命名方式,如linux_amd64
<工作区目录>/pkg/<平台相关目录>/<一级代码包>/<二级代码包>/<末级代码包>.a
bin目录
用于存放当前工作区中的Go程序的可执行文件
- 当环境变量GOBIN已经有效设置时,该目录被忽略。
2.当GOPATH包含多个工作区的路径时,必须设置GOBIN,否则无法安装Go程序的可执行文件。
三、代码包
代码包规则
一个代码包实际上就是一个由导入路径代表的目录
导入路径就是<工作区目录>/src或者<工作区目录>/pkg/<平台相关目录之下的某段子路径。如:
代码包wondertek.portainer就对应于/home/mxy/golib/src/wondertek.portainer目录,其中/home/mxy/golib是一个工作区目录。
代码包声明和导入
代码包声明语句中的包名称应该是导入路径的最右侧子路径
如:wondertek.portainer/utils,导入时候就是package utils
代码包导入语句中使用的包名应该和其导入路径保持一致,如
声明:
"fmt"
"pipeline"
"os"
"bufio"
导入
import (
"fmt"
"pipeline"
"os"
"bufio"
)
别名导入
导入:
import os2 "os"
使用:
os2.Create(filename)
本地化导入
导入:
import . "os"
使用:
Create(filename)
仅仅初始化
导入:
import _ "os"
代码导入会首先对所有全局变量进行求值,然后再执行所有init函数,
被依赖的先执行。
四、命令简介
go run
内部逻辑:先编译源码文件,然后在运行
go run src/demo/demo.go
go build
安装命令源代码
常用参数
-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'
'-s -w': 压缩编译后的体积
-s: 去掉符号表
-w: 去掉调试信息,不能gdb调试了
-linkshared
链接到以前使用创建的共享库
-buildmode=shared.
-pkgdir dir
从指定位置,而不是通常的位置安装和加载所有软件包。
当使用非标准配置构建时,使用-pkgdir将生成的包保留在单独的位置
-tags 'tag list'
构建出带tag的版本.
-toolexec 'cmd args'
a program to use to invoke toolchain programs like vet and asm.
For example, instead of running asm, the go command will run
'cmd args /path/to/asm <arguments for asm>'.
交叉编译
- Mac 下编译 Linux 和 Windows 64位可执行程序
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build main.go
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build main.go
- Linux 下编译 Mac 和 Windows 64位可执行程序
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build main.go
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build main.go
- Windows 下编译 Mac 和 Linux 64位可执行程序
SET CGO_ENABLED=0
SET GOOS=darwin
SET GOARCH=amd64
go build main.go
SET CGO_ENABLED=0
SET GOOS=linux
SET GOARCH=amd64
go build main.go
GOOS:目标平台的操作系统(darwin、freebsd、linux、windows)
GOARCH:目标平台的体系架构(386、amd64、arm)
交叉编译不支持 CGO(它允许 Go 程序与 C 的类库交互操作),所以要禁用它
上面的命令编译 64 位可执行程序,你当然应该也会使用 386 编译 32 位可执行程序
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 产生
参数介绍
-i 清除关联的安装的包和可运行文件,也就是通过go install安装的文件
-n 把需要执行的清除命令打印出来,但是不执行,这样就可以很容易的知道底层是如何运行的
-r 循环的清除在import中引入的包
-x 打印出来执行的详细命令,其实就是-n打印的执行版本
$ 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
go fmt
格式化命令, go fmt命令,其实是调用了gofmt,而且需要参数-w,否则格式化结果不会写入文件。gofmt -w -l src,可以格式化整个项目
gofmt的参数介绍
-l 显示那些需要格式化的文件
-w 把改写后的内容直接写入到文件中,而不是作为结果打印到标准输出。
-r 添加形如“a[b:len(a)] -> a[b:]”的重写规则,方便我们做批量替换
-s 简化文件中的代码
-d 显示格式化前后的diff而不是写入文件,默认是false
-e 打印所有的语法错误到标准输出。如果不使用此标记,则只会打印不同行的前10个错误。
-cpuprofile 支持调试模式,写入相应的cpufile到指定的文件
go install
用于编译并且安装代码包或者源码文件
安装代码包会在<当前工作区目录>/pkg/<平台相关目录> 下生成归档文件
安装命令源文件会被存放到GOBIN指向的目录或者<当前工作区目录/bin下
go install 不添加参数,处理当前目录
go get
从远程仓库拉取代码
代码会被拉取GOPATH的第一个工作区的src下。
常用参数
-d 只下载,不安装
-fix 下载后,先修正,然后编译安装, 修复老版本兼容
-u 利用网络更新已有的代码包及其依赖, 更新操作
-f 只有在你包含了-u参数的时候才有效,不让-u去验证import中的每一个都已经获取了的,这对于本地fork的包特别有用
-t 同时也下载需要为运行测试所需要的包
-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 generate
和go 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
加入标记-e时,即使参数中包含有不完整的代码包,命令也不会提示错误
代码包结构体中定义的字段很多,但有些时候我们只需要查看其中的一些字段。那要怎么做呢?标记-f可以满足这个需求。如go list -f {{.ImportPath}} xxxx
$ go list -json github.com/portainer/portainer/cli
{
"Dir": "/Users/csp/go/src/github.com/portainer/portainer/cli",
"ImportPath": "github.com/portainer/portainer/cli",
"Name": "cli",
"Target": "/Users/csp/go/pkg/darwin_amd64/github.com/portainer/portainer/cli.a",
"Stale": true,
"StaleReason": "cannot stat install target",
"Root": "/Users/csp/go",
"GoFiles": [
"cli.go",
"defaults.go",
"pairlist.go"
],
"IgnoredGoFiles": [
"defaults_windows.go"
],
"Imports": [
"fmt",
"github.com/portainer/portainer",
"gopkg.in/alecthomas/kingpin.v2",
"os",
"path/filepath",
"strings",
"time"
],
"Deps": [
"bufio",
"bytes",
"context",
"encoding/hex",
"errors",
"fmt",
"github.com/alecthomas/template",
"github.com/alecthomas/template/parse",
"github.com/alecthomas/units",
"github.com/portainer/portainer",
"go/ast",
"go/doc",
"go/scanner",
"go/token",
"gopkg.in/alecthomas/kingpin.v2",
"internal/cpu",
"internal/nettrace",
"internal/poll",
"internal/race",
"internal/singleflight",
"io",
"io/ioutil",
"math",
"math/rand",
"net",
"net/url",
"os",
"path",
"path/filepath",
"reflect",
"regexp",
"regexp/syntax",
"runtime",
"runtime/cgo",
"runtime/internal/atomic",
"runtime/internal/sys",
"sort",
"strconv",
"strings",
"sync",
"sync/atomic",
"syscall",
"text/template",
"text/template/parse",
"time",
"unicode",
"unicode/utf8",
"unsafe",
"vendor/golang_org/x/net/route"
]
}