golang的 GOPATH和vendor的搜索關(guān)系
基本規(guī)則
-
- 所有的go文件都是必須組織成包的形式,放在相應(yīng)文件夾下:
- 1.1 建議包名和文件夾名字相同;雖然也可以不同,但會(huì)引發(fā)使用誤解。
- 1.2 對于主程序包,也需要放在文件夾下面,注意:
- 1.2.1 不建議使用main作為文件夾名,雖然這個(gè)包名是main。
- 1.2.2 也不建議使用src作為文件名,盡管這是允許的,但是會(huì)引發(fā)誤解。
- 1.2.3 建議使用項(xiàng)目名字作為包名。
-
- go build命令如果不帶參數(shù),就是build當(dāng)前包,當(dāng)前目錄所在的包,即當(dāng)前目錄下面的所有g(shù)o文件。
- 1.2 如果go build指定了目標(biāo)包,那么就會(huì)從GOPATH路徑下面搜索包,如果找不到,就報(bào)失??;哪怕當(dāng)前路徑就在目標(biāo)包里,但是GOPATH沒有包含,也會(huì)報(bào)失敗。
- 1.2 如果GOPATH沒有設(shè)置,其缺省路徑就是$HOME/gp
例子1:完全自包含項(xiàng)目
項(xiàng)目只有一個(gè)包,即main包,沒有引用其他的包(golang自帶的系統(tǒng)包除外)。
- 1.新建文件夾,例如myproject。
mkdir myproject - 編輯項(xiàng)目文件
[~/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");
}
- 編譯項(xiàng)目
[~/myproject]$ unset GOPATH
[~/myproject]$ go build
[~/myproject]$ ls -1
foo.go
main.go
myproject
- 直接進(jìn)入項(xiàng)目目錄運(yùn)行 go build,即編譯當(dāng)前包。
- 不需要設(shè)置GOPATH值,缺省就是~/go,因?yàn)檫@是一個(gè)自包含項(xiàng)目,不需要引用GOPATH的任何值。
- 編譯生成的可執(zhí)行文件名就是項(xiàng)目文件夾名。
- 注意當(dāng)前目錄必須是項(xiàng)目文件所在目錄,因?yàn)間o build沒有指定目標(biāo)包,缺省編譯當(dāng)前目錄包;如果不是就不行,那得必須按照golang的項(xiàng)目組織規(guī)范來組織。
<goproject>
|-- src
|-- myproject
|-- main.go
|-- foo.go
然后設(shè)置GOPATH=path/to/<goproject>,再運(yùn)行g(shù)o build myproject,這樣就可以在任何目錄下面編譯,編譯生成的可執(zhí)行文件就在編譯所在的目錄下,而不是包源文件所在的目錄。
例子2:引用了其他的包
基本規(guī)則:
- 1.
import <package>總是從$GOPATH/src目錄下面搜索包,如果找不到就報(bào)錯(cuò)。- 1.2 并不會(huì)從當(dāng)前目錄下面去搜索,也不會(huì)從源文件相對目錄下面去搜索。
- 1.GOPATH可以包含多個(gè)路徑,中間用冒號(hào)(:)隔開,就像PATH一樣。
鑒于此,建議golang項(xiàng)目必須嚴(yán)格按照規(guī)范的目錄結(jié)構(gòu)組織,哪怕是前面這種自包含的項(xiàng)目。
例子3:vendor目錄的使用
基本規(guī)則:
- 1.使用vendor,項(xiàng)目必須嚴(yán)格按照規(guī)范的目錄結(jié)構(gòu)組織。
- 1.2 即使像例子1中自包含的項(xiàng)目也不能使用vendor
- 2.vender需要在原文件下面創(chuàng)建vendor目錄,然后把vendor的文件包放入vendor目錄即可,在引用的時(shí)候不需要指定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誰優(yōu)先使用
如果一個(gè)包在vendor和GOPATH下面都存在那么誰會(huì)優(yōu)先使用呢。
結(jié)論是:
- 優(yōu)先使用vendor目錄下面的包。
- 如果vendor下面沒有搜索到,再搜索GOPATH下面的包。
- 要么完整使用vendor下面的包,要么完整使用GOPATH下面的包,不會(huì)混合使用:
-3.1 假如一個(gè)函數(shù)定義再GOPATH下面的包里,而沒有定義在vendor路徑下的同名包里,那么調(diào)用者就會(huì)報(bào)函數(shù)未定義錯(cuò)誤,因?yàn)檎{(diào)用者如果找到有vendor路徑下面的包,就不會(huì)去找GOPATH下面的包了。
- 要么完整使用vendor下面的包,要么完整使用GOPATH下面的包,不會(huì)混合使用:
[~/<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引用的時(shí)候只會(huì)引用vendor下面的mydeps(src/myproject/vendor/mydeps),而忽略GOPATH下面的mydeps包(src/mydeps)。
例子5:vendor的層級(jí)搜索
前面提到GOPATH和PATH類似,可以包含多個(gè)路徑,中間用分號(hào)隔開,go在搜索包的時(shí)候會(huì)按手續(xù)從前往后搜搜。那么vendor怎么處理層級(jí)關(guān)系呢。
規(guī)則是:
- 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,那是怎么搜索的呢
- 先從src/mydep/mydep1/vendor下面搜索myvendor1。
找到了,直接使用。 - 先從src/mydep/mydep1/vendor下面搜索myvendor。
發(fā)現(xiàn)沒有找到,那么從上層路徑搜索,即: - 先從src/mydep/vendor下面搜索myvendor。
找到了,直接使用。 - 如果還沒有找到,那么繼續(xù)向上一級(jí)搜索,即
src/vendor - 如果找到了,則使用;如果還沒有找到,那么繼續(xù)從GOPATH里搜索,直到找到或者失敗。
總結(jié)
- 建議golang項(xiàng)目嚴(yán)格按照golang項(xiàng)目組織方式,即使只是一個(gè)自包含的項(xiàng)目。
<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
- GOPATH使用分號(hào)(:)隔開的多個(gè)路徑。
go編譯的時(shí)候會(huì)從GOPATH/src目錄下面搜索import的包。 - vender目錄放在源文件目錄同級(jí),下面包含各個(gè)包。
3.1 vendor的搜索優(yōu)先于GOPATH的搜索。
3.2 vendor按照路徑深度向外按順序搜索,直到$GOPATH/src/vendor為止。