Go语言用例

golang的 GOPATH和vendor的搜索关系

2018-10-13  本文已影响3人  CodingCode

golang的 GOPATH和vendor的搜索关系

基本规则

例子1:完全自包含项目

项目只有一个包,即main包,没有引用其他的包(golang自带的系统包除外)。

[~/myproject]$ cat main.go 
package main

import "fmt"

func main() {
    fmt.Printf("main::main\n");
    foo()
}

[~/myproject]$ cat foo.go 
package main

import "fmt"

func foo() {
    fmt.Printf("main::foo\n");
}
[~/myproject]$ unset GOPATH
[~/myproject]$ go build
[~/myproject]$ ls -1
foo.go
main.go
myproject
  1. 直接进入项目目录运行 go build,即编译当前包。
  2. 不需要设置GOPATH值,缺省就是~/go,因为这是一个自包含项目,不需要引用GOPATH的任何值。
  3. 编译生成的可执行文件名就是项目文件夹名。
  4. 注意当前目录必须是项目文件所在目录,因为go build没有指定目标包,缺省编译当前目录包;如果不是就不行,那得必须按照golang的项目组织规范来组织。
  <goproject>
   |-- src
        |-- myproject
             |-- main.go
             |-- foo.go

然后设置GOPATH=path/to/<goproject>,再运行go build myproject,这样就可以在任何目录下面编译,编译生成的可执行文件就在编译所在的目录下,而不是包源文件所在的目录。

例子2:引用了其他的包

基本规则:

鉴于此,建议golang项目必须严格按照规范的目录结构组织,哪怕是前面这种自包含的项目。

例子3:vendor目录的使用

基本规则:

[~/]$ find <goproject>
<goproject>
<goproject>/src
<goproject>/src/myproject
<goproject>/src/myproject/main.go
<goproject>/src/myproject/vendor
<goproject>/src/myproject/vendor/mydeps
<goproject>/src/myproject/vendor/mydeps/dep1.go

[~/<goproject>]$ cat <goproject>/src/myproject/main.go 
package main

import "fmt"
import "mydeps"

func main() {
    fmt.Printf("main::main\n");
    mydeps.Foo()
}

[~/<goproject>]$ cat <goproject>/src/myproject/vendor/mydeps/dep1.go 
package mydeps

import "fmt"

func Foo() {
    fmt.Println("in mydeps::Foo")
}

例子4:vendor和GOPATH谁优先使用

如果一个包在vendor和GOPATH下面都存在那么谁会优先使用呢。
结论是:

[~/<goproject>]$ find src
src
src/myproject
src/myproject/main.go
src/myproject/vendor
src/myproject/vendor/mydeps
src/myproject/vendor/mydeps/dep1.go
src/mydeps
src/mydeps/dep1.go

包mydeps在vendor目录下面和GOPATH路径下面都存在了,那么main.go引用的时候只会引用vendor下面的mydeps(src/myproject/vendor/mydeps),而忽略GOPATH下面的mydeps包(src/mydeps)。

例子5:vendor的层级搜索

前面提到GOPATH和PATH类似,可以包含多个路径,中间用分号隔开,go在搜索包的时候会按手续从前往后搜搜。那么vendor怎么处理层级关系呢。

规则是:

举例:

[~/<goproject>]$ find ./
./src
./src/myproject
./src/myproject/myproject
./src/myproject/main.go
./src/mydep
./src/mydep/mydep1
./src/mydep/mydep1/mydep.go
./src/mydep/mydep1/vendor
./src/mydep/mydep1/vendor/myvendor1
./src/mydep/mydep1/vendor/myvendor1/myvendor.go
./src/mydep/mydep.go
./src/mydep/vendor
./src/mydep/vendor/myvendor
./src/mydep/vendor/myvendor/myvendor.go

如果src/mydep/mydep1/mydep.go引用了myvendor1和myvendor,那是怎么搜索的呢

  1. 先从src/mydep/mydep1/vendor下面搜索myvendor1。
    找到了,直接使用。
  2. 先从src/mydep/mydep1/vendor下面搜索myvendor。
    发现没有找到,那么从上层路径搜索,即:
  3. 先从src/mydep/vendor下面搜索myvendor。
    找到了,直接使用。
  4. 如果还没有找到,那么继续向上一级搜索,即
    src/vendor
  5. 如果找到了,则使用;如果还没有找到,那么继续从GOPATH里搜索,直到找到或者失败。

总结

  1. 建议golang项目严格按照golang项目组织方式,即使只是一个自包含的项目。
<goproject>
   |-- src
        |-- mainpackage
             |-- XXX.go
             |-- YYY.go
             |-- vendor
        |-- deppackage1
             |-- XXX1.go
             |-- YYY1.go
             |-- vendor
        |-- deppackage2
             |-- XXX2.go
             |-- YYY2.go
             |-- vendor
                 |-- VVV1.go
                 |-- VVV2.go
                 |-- vendor

  1. GOPATH使用分号(:)隔开的多个路径。
    go编译的时候会从GOPATH/src目录下面搜索import的包。
  2. vender目录放在源文件目录同级,下面包含各个包。
    3.1 vendor的搜索优先于GOPATH的搜索。
    3.2 vendor按照路径深度向外按顺序搜索,直到$GOPATH/src/vendor为止。
上一篇 下一篇

猜你喜欢

热点阅读