golang的 GOPATH和vendor的搜索關(guān)系

golang的 GOPATH和vendor的搜索關(guān)系

基本規(guī)則

    1. 所有的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)目名字作為包名。
    1. 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
    1. 編輯項(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");
}
    1. 編譯項(xiàng)目
[~/myproject]$ unset GOPATH
[~/myproject]$ go build
[~/myproject]$ ls -1
foo.go
main.go
myproject
  1. 直接進(jìn)入項(xiàng)目目錄運(yùn)行 go build,即編譯當(dāng)前包。
  2. 不需要設(shè)置GOPATH值,缺省就是~/go,因?yàn)檫@是一個(gè)自包含項(xiàng)目,不需要引用GOPATH的任何值。
  3. 編譯生成的可執(zhí)行文件名就是項(xiàng)目文件夾名。
  4. 注意當(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é)論是:

    1. 優(yōu)先使用vendor目錄下面的包。
    1. 如果vendor下面沒有搜索到,再搜索GOPATH下面的包。
    1. 要么完整使用vendor下面的包,要么完整使用GOPATH下面的包,不會(huì)混合使用:
      -3.1 假如一個(gè)函數(shù)定義再GOPATH下面的包里,而沒有定義在vendor路徑下的同名包里,那么調(diào)用者就會(huì)報(bào)函數(shù)未定義錯(cuò)誤,因?yàn)檎{(diào)用者如果找到有vendor路徑下面的包,就不會(huì)去找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引用的時(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,那是怎么搜索的呢

  1. 先從src/mydep/mydep1/vendor下面搜索myvendor1。
    找到了,直接使用。
  2. 先從src/mydep/mydep1/vendor下面搜索myvendor。
    發(fā)現(xiàn)沒有找到,那么從上層路徑搜索,即:
  3. 先從src/mydep/vendor下面搜索myvendor。
    找到了,直接使用。
  4. 如果還沒有找到,那么繼續(xù)向上一級(jí)搜索,即
    src/vendor
  5. 如果找到了,則使用;如果還沒有找到,那么繼續(xù)從GOPATH里搜索,直到找到或者失敗。

總結(jié)

  1. 建議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

  1. GOPATH使用分號(hào)(:)隔開的多個(gè)路徑。
    go編譯的時(shí)候會(huì)從GOPATH/src目錄下面搜索import的包。
  2. vender目錄放在源文件目錄同級(jí),下面包含各個(gè)包。
    3.1 vendor的搜索優(yōu)先于GOPATH的搜索。
    3.2 vendor按照路徑深度向外按順序搜索,直到$GOPATH/src/vendor為止。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 定義類的變量后,在類的方法中引用此變量時(shí),寫法為:類名.變量名 代碼如下: class C1(): count =...
    紫米閣閱讀 172評論 0 0
  • 本文主要從1、 ios三種創(chuàng)建方式特點(diǎn),場景。2、再到串行,并行,同步,異步,概念介紹,搭配使用。3、三種方式具體...
    傻啦啦了閱讀 461評論 0 11

友情鏈接更多精彩內(nèi)容