【Go基础】GOPATH、GOROOT、GOMOD

我们可以输入go env查看我们的go环境变量

GOPATH="/Users/inf/go"
GOROOT="/usr/local/go"
GO111MODULE="auto"

GOPATH

GOPATH 是 Go语言中使用的一个环境变量,它使用绝对路径提供项目的工作目录。

  • 工作目录:一个工程开发的相对参考目录。工作区的概念与工作目录的概念也是类似的。如果不使用工作目录的概念,在多人开发时,每个人有一套自己的目录结构,读取配置文件的位置不统一,输出的二进制运行文件也不统一,这样会导致开发的标准不统一,影响开发效率。

命令行输出我们可以看到go的工作目录GOPATH默认为/Users/xxx/go/

使用GOPATH的工程结构

在 GOPATH 指定的工作目录下,代码总是会保存在 $GOPATH/src 目录下。在工程经过 go buildgo installgo get 等指令后,会将产生的二进制可执行文件放在 $GOPATH/bin目录下,生成的中间缓存文件会被保存在 $GOPATH/pkg 下。

如果需要将整个源码添加到版本管理工具(Version Control System,VCS)中时,只需要添加 $GOPATH/src 目录的源码即可。bin 和 pkg 目录的内容都可以由 src 目录生成。

设置和使用GOPATH

我们可以使用命令

export GOPATH=`pwd`

选择一个目录,在目录中的命令行中执行下面的指令:设置当前目录为GOPATH

该指令中的 pwd 将输出当前的目录,使用反引号`将 pwd 指令括起来表示命令行替换,也就是说,使用 `pwd` 将获得 pwd 返回的当前目录的值。例如,假设你的当前目录是“/Users/xxx/go”,那么使用pwd将获得返回值“/Users/xxx/go”。

使用 export 指令可以将当前目录的值设置到环境变量 GOPATH中。

网上建议大家无论是使用命令行或者使用集成开发环境编译 Go 源码时,GOPATH 跟随项目设定。在 Jetbrains 公司的 GoLand 集成开发环境(IDE)中的 GOPATH 设置分为全局 GOPATH 和项目 GOPATH,如下图所示


Global GOPATH 代表全局 GOPATH,一般来源于系统环境变量中的 GOPATH;Project GOPATH 代表项目所使用的 GOPATH,该设置会被保存在工作目录的 .idea 目录下,不会被设置到环境变量的 GOPATH 中,但会在编译时使用到这个目录。建议在开发时只填写项目 GOPATH,每一个项目尽量只设置一个 GOPATH,不使用多个 GOPATH 和全局的 GOPATH。

GOROOT

GOROOT就是我们Go语言的安装路径。我这里是/usr/local/go
打开这个文件夹,同样可以看到



src, bin, pkg三个文件夹,
标准的Go语言代码库中包含了大量的包,并且在安装 Go 的时候多数会自动安装到系统中。我们可以在 $GOROOT/src/pkg 目录中查看这些包。当我们 import内置包的时候,并不需要额外安装,当程序运行时,会先去GOROOT下找相应的包来运行。

我们可以在其他随便一个文件夹下运行下运行mian.go
比如我新建了一个hello文件夹,


//main.go
package main
 ​
 import "fmt"
 ​
 func main() {
     fmt.Println("Hello World")
 }

会成功输出Helo World,go run其实帮你将程序进行编译并生成可执行文件,而编译文件和执行文件实际上存在在一个暂存资料夹里面,当运行完这个程序就会自动删除。该指令可以相乘类似直译的方式运行,而不需要其他任何环境设定。
但如果
要引入hello.go,或者import 某个Github上的包,就会报错

import (
     "hello"
    )
 ​
 func main() {
    test1()
 }
// main.go:10:3: cannot find package "hello" in any of:
// /usr/local/go/src/hello (from $GOROOT)
// /Users/inf/go/src/hello (from $GOPATH)

1、 当执行golang程序,需要获取import的包时,编译器回先去GOROOT路径下的src文件夹找有没有我们在程序中import的包
2、如果在GOROOT下没有找到,就会去GOPATH下src下找这个包

所以只要GOROOT跟GOPATH下都没找到包的话就会报错

go run, go build, go install

go run

go run 编译并直接运行程序,它会产生一个临时文件(但不会生成 .exe 文件),直接在命令行输出程序执行结果,方便用户调试,产生执行结果后就会自动删除。

go build

go build 用于测试编译包,主要检查是否会有编译错误,如果是一个可执行文件的源码(即是 main 包),就会直接生成一个可执行文件。

go build main.go

这样会在当前目录下产生一个名称为mian的可执行文件。也可以在build后面写专门的项目名称,执行该命令会自动在当前文件夹下找package为mian,并且有main function的go文件,再编译成可执行文件



也可以使用下面的命令指定build出来的可执行文件放在哪里

go build -o bin/main src/demo/main.go

-o后面的第一个参数表示生产的可执行文件的路径以及名称,第二个参数代表要编译的go文件的路径。
按照惯例,GOPATH下bin文件夹存放build出来的可执行文件。

go build有个缺点就是每次编译go文件比较没有效率,当项目架构越来越大build的速度也越来越慢。

go install

go install 的作用有两步:第一步是编译导入的包文件,所有导入的包文件编译完才会编译主程序;第二步是将编译后生成的可执行文件放到 bin 目录下($GOPATH/bin),编译后的包文件放到 pkg 目录下($GOPATH/pkg)。

go install 做两件事情,

  • 将package编译成.a file
  • 如果是main 包则编译成可执行文件

有了第一项功能,下次编译时候就不会将包的程序码重新编译,而是直接用编译好的.a file。而.a file就位于GOPATH/pkg里面。

来看一个例子
GOPATH/src下新建两个项目mypkg和mytest,分别新建两个go文件



mypkg.go

package mypkg
 ​
 import "fmt"
 ​
 func MyFunc() {
     fmt.Println("MyFunc")
 }

mytest.go

package main
 ​
 import (
     "mypkg"
 )
 ​
 func main() {
     mypkg.MyFunc()
 }

mytest.go中用了import了mypkg的包,而可以通过install指令将mypkg编译成.a file

go install mypkg

可以发现在GOPATH/darwin_amd64/mypkg.a有该文件
darwin_amd64是由GOOS和GOARCH两个环境变量所组合合成的

GOPATH缺点

当我们的第三方包不是官方库时都要放在GOPATH/src下才可以使用

我们通常使用go get指令来获取第三方的包

go get github.com/gin-gonic/gin

go get 最长用在当我们想用别人公开在github上的包,可以帮我们从网上clone到GOPATH/src下。
是不是听起来很方便?会让src下的项目变得很复杂,除了有自己的项目还有其他第三方库的项目。
在如果,我们的不同的项目采用的第三方库是不同的版本怎么办,go1.11以前是要设顶多组不同的GOPATH,虽然go社区也有开发相对应的包管理工具,如Vender,Dep来结局该问题,但它们都不是官方的。

GOMOD

Go Modules很像java的maven,将第三方的库放在本地的空间,但它不是自动的下载包的
如下命令开启和关闭go mod

go env -w GO111MODULE=on 打开

go env -w GO111MODULE=off 关闭

GO111MODULE有三个不同的值

  • auto

    • 当存在 go.mod 文件时或处于 GOPATH 外, 其行为均会等同于于 GO111MODULE=on。这意味着在 Go 1.13 及之后的版本你可以将所有的代码仓库均存储在 GOPATH 下。
    • 当处于 GOPATH 内且没有 go.mod 文件存在时其行为会等同于 GO111MODULE=off。
  • on
    即使项目在您的 GOPATH 中,GO111MODULE = on 仍将强制使用 Go 模块。需要 go.mod 正常工作

  • off
    强制 Go 表现出 GOPATH 方式,即使在 GOPATH 之外。

下载下来的第三方库在哪呢?其实就在GOPATH/pkg/mod文件夹里面

接下来就是和maven很像的操作了
src下新建一个文件夹modtest
该文件夹下执行

go mod init 

可填可不填,不填的话就是采用项目文件夹的名称,执行后会出现一个go.mod的文件

module modtest

go 1.15

go.mod 提供了module, require、replace和exclude 四个命令

module 语句指定包的名字(路径)
require 语句指定的依赖项模块,默认最新版,可以指定版本号
replace 语句可以替换依赖项模块
exclude 语句可以忽略依赖项模块
还有个go 命令定义go语言的版本

添加一个,假设我要引入github.com/gin-gonic/gin v1.5.0这个包

module modtest

go 1.15

require github.com/gin-gonic/gin v1.5.0

在执行

go mod download

会发现当前文件夹下多了个go.sum的文件,该文件基本上用来记录包版本的关系,不怎么需要理会。需要的包装在GOPATH/pkg/mod文件夹下

之后运行

go run main.go
GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.

[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
 - using env:   export GIN_MODE=release
 - using code:  gin.SetMode(gin.ReleaseMode)

[GIN-debug] Environment variable PORT is undefined. Using port :8080 by default
[GIN-debug] Listening and serving HTTP on :8080

这个就是在local 8080 port开启一个web server~

当然也可以不执行go mod download而直接运行go build或者go install也会自动下载包
还有一种方法可以直接下载

使用go get命令

go get github.com/gin-gonic/[email protected]

或者require指定版本,执行go get指令。和download是一样的。
只要有开启gomod功能,go get就不会再src下放package,而是会放在/pkg/mod里面,并且mod会写好引入。也就不需要go mod download了

你可能感兴趣的:(【Go基础】GOPATH、GOROOT、GOMOD)