0%

golang 基础 - go的环境变量

1.三个环境变量

刚接触go的时候很头疼,一下子需要我配置三个环境变量,这三个环境变量看起来很让人头疼,感觉起来三个环境变量的意思大致,区分度不高,这三个环境变量也就是 GOROOTGOPATHGOBIN。这里简单介绍一下。

  • GOROOT:Go 语言安装根目录的路径,也就是 GO 语言的安装路径。
  • GOPATH:若干工作区目录的路径。是我们自己定义的工作空间。
  • GOBIN:GO 程序生成的可执行文件(executable file)的路径。

其中最让人头疼的就是这个GOROOT,看起来似是而非的感觉,那么GOPATH 有什么意义吗?

这里可以把 GOPATH 简单理解成 Go 语言的工作目录,它的值是一个目录的路径,也可以是多个目录路径,每个目录都代表 Go 语言的一个工作区(workspace)。

我们需要利于这些工作区,去放置 Go 语言的源码文件(source file),以及安装(install)后的归档文件(archive file,也就是以“.a”为扩展名的文件)和可执行文件(executable file)。

这个GOPATH 其实很重要,为什么这么说呢?

因为Go 语言项目在其生命周期内的所有操作(编码、依赖管理、构建、测试、安装等)基本上都是围绕着 GOPATH 和工作区进行的。


2.拓展GOPATH

2.1 Go如何组织源码

在编写代码的过程中,我们肯定的是不只有一两个文件,随着项目的不过扩增,肯定文件会越来越多的,这就涉及到如何组织管理这些源码的问题了,在Java中我们使用的是import 包的方式,而包里面还有各种子包,于是就是形成一种了循环嵌套的源码框架了,看起来也简单明了,其实Go语言也是差不多,他也是以代码包为基本组织单位的,而且在文件系统中,这些代码包其实是与目录一一对应的。由于目录可以有子目录,所以代码包也可以有子包。

Go也是一样的使用import方式的,具体方式就是:

1
import "github.com/labstack/echo"

如果需要引用多个文件的话该如何使用呢?

1
2
3
4
5
6
7
8
9
10
11
import (
"bytes"
"encoding/binary"
"encoding/gob"
"encoding/json"
"fmt"
"log"
"strconv"

"github.com/recoilme/slowpoke"
)

这里随便给出一个示例,可以看见如果需要包含多个子包是使用import() 的方式,在工作区中,一个代码包的导入路径实际上就是从 src 子目录,到该包的实际存储位置的相对路径。

这是怎么理解呢?我们可以看看在windows下面的GOPATH的截图:

GOPATH目录路径

进入GOPATH中的src目录下可以看见:

D:\GOPATH\src

我们再进入github.com,发现如下,这些都是我在浏览Go相关项目下自动导入或者我手动导入的一些github包。

D:\GOPATH\src\github.com

大概个源码组织结构如上,让我比较吃惊的是,居然可以直接导入github包中的内容???真是前所未见,这样一来速度会快吗?如果网络不好的话,岂不是一直都会编译不过吗?真是各种疑问了,以后再回头看看会不会有新的发现。

在浏览项目的过程中,我发现让我十分心急的一点就是,编译过程中需要导很多github的包,又因为特色的问题,网络速度上不去,有些包还被墙掉(比如:golang.org下面的文件几乎都导不进来),还好golang.org将他们的镜像上传到github上面,可以通过github上面的包下载到本地,再根据路径名进行配置好,这样方可通过。

这样一来,也太麻烦了点,和之前使用C、Java、Python的感觉都完全不一样,这也是让我比较吃惊的一点,居然为了通过一个文件的编译,要手动下载好几个包文件。

总的来说,Go 语言源码的组织方式就是以环境变量 GOPATH、工作区、src 目录和代码包为主线的。一般情况下,Go 语言的源码文件都需要被存放在环境变量 GOPATH 包含的某个工作区(目录)中的 src 目录下的某个代码包(目录)中。


2.2 归档文件

上面的GOPATH路径下,我们已经了解到了,源码文件通常会被放在某个工作区的 src 子目录下。我们注意到除了src,还有另外一个文件夹是pkg,欸,这就有点意思,这个pkg是什么东西?

GOPATH目录路径

Go 语言源码在安装后如果产生了归档文件(以“.a”为扩展名的文件),就会放进该工作区的 pkg 子目录;如果产生了可执行文件,就可能会放进该工作区的 bin 子目录。

归档文件在Linux下就是扩展名是.a的文件,也就是archive文件。写过C程序的朋友都知道,这是程序编译后生成的静态库文件。

这里讲讲归档文件存放的具体位置和规则。

源码文件会以代码包的形式组织起来,一个代码包其实就对应一个目录。安装某个代码包而产生的归档文件是与这个代码包同名的。

放置它的相对目录就是该代码包的导入路径的直接父级。比如,一个已存在的代码包的导入路径是

1
github.com/dongxiem/xxx

那么执行命令

1
go install github.com/dongxiem/xxx

这样一来就生成了归档文件,而归档文件的相对目录就是:github.com/dongxiem,其下面的文件名则会有一个:xxx.a

需要注意到的是:归档文件的相对目录与 pkg 目录之间还有一级目录,叫做平台相关目录。

平台相关目录的名称是由 build(也称“构建”)的目标操作系统、下划线和目标计算架构的代号组成的。比如,构建某个代码包时的目标操作系统是 Linux,目标计算架构是 64 位的,那么对应的平台相关目录就是 linux_amd64。

比如我Windows下面的则为:

D:\GOPATH\pkg

但是如果构建某个代码包时的目标操作系统是 Linux,目标计算架构是 64 位的,那么对应的平台相关目录就是 linux_amd64。

其大概的目录架构如下:

GOPATH目录架构


2.3 Go 程序构建与安装过程

我们可以将这块的内容用两条命令进行归纳开来,觉得go get还挺重要的,于是也提及到一下。

2.3.1 go build

对于构建,我们会使用go builid命令对程序进行构建,构建过程会执行编译、打包等操作,这些操作生成的任何文静都会先被保存到某个临时目录中。

如果构建的是库源码文件,那么操作后产生的结果文件只会存在于临时目录中。这里的构建的主要意义在于检查和验证。如果构建的是命令源码文件,那么操作的结果文件会被搬运到源码文件所在的目录中。

关于go build,这里需要注意的是:在运行go build命令的时候,默认不会编译目标代码包所依赖的那些代码包。当然,如果被依赖的代码包的归档文件不存在,或者源码文件有了变化,那它还是会被编译。

这里注意一下两点:

  1. 如果需要强制编译,可以在执行命令的时候加入标记-a。此时,不但目标代码包总是会被编译,它依赖的代码包也总会被编译,即使依赖的是标准库中的代码包也是如此。
  2. 如果不但要编译依赖的代码包,还要安装它们的归档文件,那么可以加入标记-i

那么我们怎么确定哪些代码包被编译了呢?有两种方法。

  1. 运行go build命令时加入标记-x,这样可以看到go build命令具体都执行了哪些操作。另外也可以加入标记-n,这样可以只查看具体操作而不执行它们。
  2. 运行go build命令时加入标记-v,这样可以看到go build命令编译的代码包的名称。它在与-a标记搭配使用时很有用。

2.3.2 go install

对于安装,我们会使用go install命令进行安装,安装操作会先执行构建,然后还会进行链接操作,并且把结果文件搬运到指定目录。

如果安装的是库源码文件,那么结果文件会被搬运到它所在工作区的 pkg 目录下的某个子目录中。如果安装的是命令源码文件,那么结果文件会被搬运到它所在工作区的 bin 目录中,或者环境变量GOBIN指向的目录中。

2.3.3 go get

关于go get,这里也是插讲一下,因为其余Go 源码的安装关系挺大,命令go get会自动从一些主流公用代码仓库(比如 GitHub)下载目标代码包,并把它们安装到环境变量GOPATH包含的第 1 工作区的相应目录中。如果存在环境变量GOBIN,那么仅包含命令源码文件的代码包会被安装到GOBIN指向的那个目录。

其主要的几个参数如下:

  • -u:下载并安装代码包,不论工作区中是否已存在它们。
  • -d:只下载代码包,不安装代码包。
  • -fix:在下载代码包后先运行一个用于根据当前 Go 语言版本修正代码的工具,然后再安装代码包。
  • -t:同时下载测试所需的代码包。
  • -insecure:允许通过非安全的网络协议下载和安装代码包。HTTP 就是这样的协议。

有时候,我们可能会出于某种目的变更存储源码的代码仓库或者代码包的相对路径。这时,为了让代码包的远程导入路径不受此类变更的影响,我们会使用自定义的代码包导入路径。

对代码包的远程导入路径进行自定义的方法是:在该代码包中的库源码文件的包声明语句的右边加入导入注释,像这样:

1
package semaphore // import "golang.org/x/sync/semaphore"

有没有很吃惊,这又和之前使用的一些编程语言不一样了,之前我们使用的一些编程语言例如Java,都是使用了“//”之后后面无论写什么都是不起作用的,起到的是一个注释的作用了,而现在居然还有这种做法,有点意思。

这个代码包原本的完整导入路径是github.com/golang/sync/semaphore。这与实际存储它的网络地址对应的。该代码包的源码实际存在 GitHub 网站的 golang 组的 sync 代码仓库的 semaphore 目录下。而加入导入注释之后,用以下命令即可下载并安装该代码包了:

1
go get golang.org/x/sync/semaphore

而 Go 语言官网 golang.org 下的路径 /x/sync/semaphore 并不是存放semaphore包的真实地址。我们称之为代码包的自定义导入路径。不过,这还需要在 golang.org 这个域名背后的服务端程序上,添加一些支持才能使这条命令成功。