封尘网

让学习成为一种习惯!

Linux系统安装Go1.11首次使用modules

因为最近都在研究Golang,而且从关注时的1.8到现在1.11已经更新好几个版本了。

Go 1.8版本中,如果开发者没有显式设置GOPATH,Go会赋予GOPATH一个默认值(在linux上为$HOME/go)。虽说不用再设置GOPATH,但GOPATH还是事实存在的,它在go 工具链中依旧发挥着至关重要的作用。

在1.10版本前当执行go get获取第三方代码包的时候,默认会放存放在$GOPATH/src下面。

而我们在代码里通过import导入包的时候,就按照import path去$GOPATH/src搜索相应的package。

在1.11的变化中加入的新功能modules “包依赖管理”,用起来比之前的dep更好用了。这里做一个简单的记录和测试;

系统环境:CentOS release 6.5 (Final) 2.6.32-431.el6.x86_64

Golang下载地址:https://dl.google.com/go/go1.11.linux-amd64.tar.gz

安装:

wget https://dl.google.com/go/go1.11.linux-amd64.tar.gz
tar xf go1.11.linux-amd64.tar.gz -C /opt

添加环境变量:[这里直接不配置GOPATH路径了,在linux上为$HOME/go,我使用root用户,所以目录为/root/go]

vim /etc/profile 加入以下三行到文件最后面

export GO111MODULE=on 
export GOROOT=/opt/go 
export PATH=$PATH:$GOROOT/bin

说明:export GO111MODULE=on是Go1.11中使用modules的一个开关,就是没有强制直接使用modules工具,毕竟也是新出来的;它有三个值auto、on、off;默认为auto,如果为空就是关闭,因为要使用它所以我直接在全局中加入此参数;

使配置生效;

source /etc/profile

查看当前的Go env

[root@nginx-web opt]# go env 
GOARCH="amd64" 
GOBIN="" 
GOCACHE="/root/.cache/go-build" 
GOEXE="" 
GOFLAGS="" 
GOHOSTARCH="amd64" 
GOHOSTOS="linux" 
GOOS="linux" 
GOPATH="/root/go"     //默认没有配置在这里,不同系统及用户不同 
GOPROXY="" 
GORACE="" 
GOROOT="/opt/go" 
GOTMPDIR="" 
GOTOOLDIR="/opt/go/pkg/tool/linux_amd64" 
GCCGO="gccgo" 
CC="gcc" 
CXX="g++" 
CGO_ENABLED="1" 
GOMOD="" 
CGO_CFLAGS="-g -O2" 
CGO_CPPFLAGS="" 
CGO_CXXFLAGS="-g -O2" 
CGO_FFLAGS="-g -O2" 
CGO_LDFLAGS="-g -O2" 
PKG_CONFIG="pkg-config" 
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build055060734=/tmp/go-build"

初始化一个mod环境,这里后面跟的是一个mod(modules)名称,名称可以随意。但是不能存在相同名字的。

[root@nginx-web demo]# go mod init goDataTest 
go: creating new go.mod: module goDataTest

如果再次执行上面命令就有以下提示:[已经存在]

[root@nginx-web demo]# go mod init goDataTest 
go mod init: go.mod already exists

查看当前目录下只有一个go.mod文件,而文件只有一行 goDataTest 就是我们定义的module名称。

[root@nginx-web demo]# cat go.mod  
module goDataTest

接下来在当前目录下创建一个dbtest.go文件,内容如下:


package main 
import ( 
    "database/sql" 
    "fmt" 
    _ "github.com/go-sql-driver/mysql" 
) 
func main() { 
    db, err := sql.Open("mysql", "dba:123456@tcp(10.0.10.110:3306)/test?charset=utf8") 
    //处理异常 
    if err != nil { 
        panic(err) 
    } 
    defer db.Close() 

    //查询数据 
    rows, err := db.Query("select * from users") 
    for rows.Next() { 
        var ( 
            id       int 
            username string 
            fullname string 
            password string 
            email    string 
            group_id int 
        ) 
        //查询上面的所有 
        err = rows.Scan(&id, &username, &fullname, &password, &email, &group_id) 
        fmt.Println(id, username, fullname, password, email, group_id) 
    } 
}

接下来就是build代码就好了。[这么简单?之前还要先下载依赖包才可以],此时执行go build dbtest.go 会提示需要的包不存在,无法build。

[root@nginx-web demo]# go build dbtest.go  
build goDataTest: cannot find module for path github.com/go-sql-driver/mysql

需要先下载完第三方包后build才能成功。

现在使用代理即可完帮助代码自动下载相应的包:

关于 $GOPROXY

当我们使用go的时候,go默认会直接从代码库中去下载所需的相关依赖,GOPROXY 这个环境变量可以让我们控制自己从哪里去下载源代码,如果 GOPROXY 没有设置,go 会直接从代码库下载相关依赖代码。如果你像下面这样设置了这个环境变量,那么你就会通过 goproxy.io下载所有的源代码。

export GOPROXY=https://goproxy.io

你可以通过置空这个环境变量来关闭,export GOPROXY=

如果要开机、全局生效的就要在/etc/profile中也加入即可。

查看当前系统中的变量,这里过滤GO的配置

[root@nginx-web ~]# export|grep "GO" 
declare -x GO111MODULE="on" 
declare -x GOPROXY="https://goproxy.io" 
declare -x GOROOT="/opt/go"

见证奇迹的时候了,直接build上面的dbtest.go 代码,效果如下:

可以看到,它自动会下载导入的第三方包,并标记了所下载的版本,之前的go get 方法并不清楚包的版本,这里就有记录了。

如果我指定版本呢?直接修改go.mod文件中的1.4.0为1.3.0[此版本必须存在,可以参考github上的URL记录]

再次执行build时,可以看到如下效果,它又下载了1.3.0的包了。

[root@nginx-web demo]# go build dbtest.go  
go: finding github.com/go-sql-driver/mysql v1.3.0 
go: downloading github.com/go-sql-driver/mysql v1.3.0

查看默认的GOPATH路径,$HOME/go发现已经下载了两个包了。

再次试验,复制一份demo 并改名为demo1,并把目录下的go.mod 和go.sum文件删除,只保留一个dbtest.go代码文件即可;再次初始化一个.mod文件,这里名字为demo1

cd demo1 
go mod init demo1

看图:它默认是使用latest版本的;仔细对比后面的h1的值会发现是包一样的;

go list -m输出的信息被称为 build list ,也就是构建当前module所要构建的所有相关package(及版本)的列表。

[root@nginx-web demo1]# go list -m -json all 
{ 
    "Path": "demo1", 
    "Main": true, 
    "Dir": "/test/demo1", 
    "GoMod": "/test/demo1/go.mod" 
} 
{ 
    "Path": "github.com/go-sql-driver/mysql", 
    "Version": "v1.4.0", 
    "Time": "2018-06-03T12:45:54Z", 
    "Dir": "/root/go/pkg/mod/github.com/go-sql-driver/mysql@v1.4.0", 
    "GoMod": "/root/go/pkg/mod/cache/download/github.com/go-sql-driver/mysql/@v/v1.4.0.mod" 
}

其实此时哪怕把go.mod和go.sum删除了也可以正常build,那时因为系统已经下载回来对应的包了,所以删除也可以,但是删除了并不方便对代码的依赖和管理,毕竟版本的变化可能造成其它的问题。

修改版本,不如我直接vim修改快,而且还要注意这个”@”来接连版本号,替换配置文件中的空格.


[root@nginx-web demo1]# go mod edit -require=github.com/go-sql-driver/mysql@v1.3.0 
[root@nginx-web demo1]# cat go.mod  
module demo1 

require ( 
    github.com/go-sql-driver/mysql v1.3.0 
    google.golang.org/appengine v1.1.0 // indirect 
)

对于go1.11版本也只是简单的试用了一下,感觉还是错,如果没有那个代理的话,那么这个modules在国内是用不上了,因为无法自动去下载代码中导入的包。

在使用Gosublime插件[我是在ubuntu系统中遇到]时可能提示未检查到GOPATH的问题,如果遇到这情况就配置一个GOPATH变量到/etc/profile中;

export GOPATH=/root/go

如果需要导入本地包时,在import里带上项目的名字,例如: