golang的 GOPATH和vendor的搜索关系

栏目: Go · 发布时间: 6年前

内容简介:golang的 GOPATH和vendor的搜索关系基本规则例子1:完全自包含项目

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为止。

以上所述就是小编给大家介绍的《golang的 GOPATH和vendor的搜索关系》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

深入浅出MFC (第二版)

深入浅出MFC (第二版)

侯俊杰 / 华中科技大学出版社 / 2001-1 / 80.00元

《深入浅出MFC》分为四大篇。第一篇提出学习MFC程序设计之前的必要基础,包括Widnows程序的基本观念以及C++的高阶议题。“学前基础”是相当主观的认定,但作者是甚于自己的学习经验以及教学经验,其挑选应该颇具说服力。第二篇介绍Visual C++整合环境开发工具。此篇只是提纲挈领,并不企图取代Visual C++使用手册;然而对于软件使用的老手,此篇或已足以帮助掌握Visual C++整合环境......一起来看看 《深入浅出MFC (第二版)》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具