golang的 GOPATH和vendor的搜索关系

golang的 GOPATH和vendor的搜索关系

基本规则

    1. 所有的go文件都是必须组织成包的形式,放在相应文件夹下:
    • 1.1 建议包名和文件夹名字相同;虽然也可以不同,但会引发使用误解。
    • 1.2 对于主程序包,也需要放在文件夹下面,注意:
      • 1.2.1 不建议使用main作为文件夹名,虽然这个包名是main。
      • 1.2.2 也不建议使用src作为文件名,尽管这是允许的,但是会引发误解。
      • 1.2.3 建议使用项目名字作为包名。
    1. go build命令如果不带参数,就是build当前包,当前目录所在的包,即当前目录下面的所有go文件。
    • 1.2 如果go build指定了目标包,那么就会从GOPATH路径下面搜索包,如果找不到,就报失败;哪怕当前路径就在目标包里,但是GOPATH没有包含,也会报失败。
    • 1.2 如果GOPATH没有设置,其缺省路径就是$HOME/gp

例子1:完全自包含项目

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

  • 1.新建文件夹,例如myproject。
    mkdir myproject
    1. 编辑项目文件
[~/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");
}
    1. 编译项目
[~/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:引用了其他的包

基本规则:

  • 1.import <package>总是从$GOPATH/src目录下面搜索包,如果找不到就报错。
    • 1.2 并不会从当前目录下面去搜索,也不会从源文件相对目录下面去搜索。
  • 1.GOPATH可以包含多个路径,中间用冒号(:)隔开,就像PATH一样。

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

例子3:vendor目录的使用

基本规则:

  • 1.使用vendor,项目必须严格按照规范的目录结构组织。
    • 1.2 即使像例子1中自包含的项目也不能使用vendor
  • 2.vender需要在原文件下面创建vendor目录,然后把vendor的文件包放入vendor目录即可,在引用的时候不需要指定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下面都存在那么谁会优先使用呢。
结论是:

    1. 优先使用vendor目录下面的包。
    1. 如果vendor下面没有搜索到,再搜索GOPATH下面的包。
    1. 要么完整使用vendor下面的包,要么完整使用GOPATH下面的包,不会混合使用:
      -3.1 假如一个函数定义再GOPATH下面的包里,而没有定义在vendor路径下的同名包里,那么调用者就会报函数未定义错误,因为调用者如果找到有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怎么处理层级关系呢。

规则是:

  • 1.从引用文件所在的vendor路径下面搜索。
  • 2.如果没有找到,那么从上层目录的vendor路径下面搜索。
  • 3.直到src的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为止。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,711评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,079评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,194评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,089评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,197评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,306评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,338评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,119评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,541评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,846评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,014评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,694评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,322评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,026评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,257评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,863评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,895评论 2 351

推荐阅读更多精彩内容

  • 定义类的变量后,在类的方法中引用此变量时,写法为:类名.变量名 代码如下: class C1(): count =...
    紫米阁阅读 115评论 0 0
  • 本文主要从1、 ios三种创建方式特点,场景。2、再到串行,并行,同步,异步,概念介绍,搭配使用。3、三种方式具体...
    傻啦啦了阅读 397评论 0 11