標準庫— 操作源碼之收集go包資訊:go/build

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

標準庫— 操作源碼之收集go包資訊:go/build

在golang標準庫中,有那麼一類包,它們用於處理go項目目錄結構、源碼、文法、基本操作等。一般程式中可能用不到這些包,但在go工具鏈源碼中用到了,之所以學習這些標準庫,是為了更好的看go工具鏈的源碼。首先我們來看收集go包資訊的庫:go/build

一、build包概述



該包文檔中首先介紹了Go Path。如果對該部分還不清楚,可以看下文檔的說明;或者官方其他文檔;或者看 Go項目的目錄結構。

如果你看過go源碼,應該見到過類似這樣的包注釋:+build ignore。這是編譯約束條件(Build Constraints),可以理解為條件編譯。關於這部分的更多內容,稍後詳細介紹。

二、類型和函數


1、ToolDir變數


var ToolDir = filepath.Join(runtime.GOROOT(), "pkg/tool/"+runtime.GOOS+"_"+runtime.GOARCH)

該變數的值是go工具鏈的路徑。6g/6l之類的工具,就在這個路徑下

2、ArchChar函數



獲得架構的字元表示。在之前的文章中介紹過。比如:x86 32bit用8表示;amd64用6表示等。該函數通過傳入goarch,獲得對應的架構字元。如:build.ArchChar(runtime.GOARCH)

3、IsLocalImport函數



判斷是否為“本地匯入“,類似”.”, “..”, “./foo”或者”../foo”。正式項目,一般不建議用本地匯入,使用本地匯入很多人會說找不到包。

4、Context類型



該類型為構建(build)指定上下文環境。比如:當前作業系統、架構、Go根目錄、GOPATH等

該類型除了提供變數成員,還提供了函數成員,如果函數成員是nil,則會使用其他庫提供的函數。

5、Package類型



描述Go包

三、主要類型的方法(包括執行個體化)


1、Context的執行個體化和方法


        var Default Context = defaultContext()

這是預設實現,go build工具使用的就是這個預設實現。Default會使用GOARCH、GOOS、GOROOT和GOPATH環境變數,如果沒設定,則使用安裝runtime中的值。

1)Import方法
        func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Package, error)

匯入一個包,返回Package類型指標。path參數跟在代碼中import path的path一樣。srcDir是源碼所在路徑;而ImportMode類型,build包中提供了兩種:FindOnly和AllowBinary。AllowBinary可以在包源碼不存在的時候,編譯好的包對象檔案直接被引用。

之前,在論壇(關於go的程式碼群組織)中討論過這樣一個問題:go build 的時候,如果依賴的包源碼不存在,編譯不成功,有一個解決辦法是通過go tool 6g這種方式編譯。現在,在你知道了AllowBinary參數之後,應該可以通過修改go工具源碼來解決這個問題。在src/cmd/go目錄中的pkg.go中225有這樣的代碼:
?
www.usr.cc
123 // TODO:After Go 1, decide when topass build.AllowBinary here.// See issue3268 for mistakes to avoid.bp, err := buildContext.Import(path,srcDir, 0)


通過查看Import的源碼,可以知道包安裝的細節,比如安裝到哪裡。

當目錄不包含源碼,如果出錯,則返回NoGoError錯誤。

另外,build包提供了Import方法的一個簡便方法,即:Import函數,預設調用Default的Import方法

2)ImportDir方法


內部實現:return ctxt.Import(“.”, dir, mode)

3)SrcDirs方法

列出GOROOT和GOPATH中的源碼目錄。比如,我沒有設定GOPATH,執行結果如下:
fmt.Println(build.Default.SrcDirs()) // [ c:\Go\src\pkg]

2、Package的執行個體化和方法



Context的Import和ImportDir都會返回Package執行個體(*Package),當然,也可以直接執行個體化。

Package提供了一個方法,判斷一個Package是否是命令,也就是是否是main包
        func (p *Package) IsCommand() bool

3、關於Context和Package的欄位



由於這兩種類型欄位很多,包文檔中每個欄位都有注釋,在此不一一解釋。

四、構建約束(build constraints)



或者叫條件編譯(編譯條件)

1、使用說明



在go源碼中(src/pkg或src/cmd)搜尋+build,發現有不少檔案的開頭有這樣的注釋
+build xxx

構建約束是一行以+build開始的注釋。在+build之後列出了一些條件,在這個條件成立的時,該檔案應該包含在包中(也就是應該被編譯進包檔案),約束可以出現在任何源檔案中,也就是不限於go源檔案。不過,這些條件必須在檔案最頂部(正是代碼的前面,也就是說,+build之前可以有其他注釋),在+build注釋之後,應該有一個空行(這是為了和package doc區分開)。

文法規則:

1)只允許是字母數字或_

2)多個條件之間,空格表示OR;逗號表示AND;歎號(!)表示NOT

3)一個檔案可以有多個+build,它們之間的關係是AND。如:
// +build linux darwin
// +build 386
等價於
// +build (linux OR darwin) AND 386

4)預定義了一些條件:
runtime.GOOS、runtime.GOARCH、compiler(gc或gccgo)、cgo、context.BuildTags中的其他單詞

5)如果一個檔案名稱(不含尾碼),以 *_GOOS, *_GOARCH, 或 *_GOOS_GOARCH結尾,它們隱式包含了 構建約束

6)當不想編譯某個檔案時,可以加上// +build ignore。這裡的ignore可以是其他單詞,只是ignore更能讓人知道什麼意思

更多詳細資料,可以查看go/build/build.go檔案中shouldBuild和match方法。

2、應用執行個體



除了*_GOOS這種預定義的應用,我們看一個實際的應用。

比如,項目中需要在測試環境輸出Debug資訊,一般通過一個變數(或常量)來控制是測試環境還是生產環境,比如:if DEBUG {},這樣在生產環境每次也會進行這樣的判斷。在golang-nuts郵件清單中有人問過這樣的問題,貌似沒有討論出更好的方法(想要跟C中條件編譯一樣的效果)。下面我們採用Build constraints來實現。

    1)檔案清單:main.go logger_debug.go logger_product.go
    2)在main.go中簡單的調用Debug()方法。
    3)在logger_product.go中的Debug()是空實現,但是在檔案開始加上// + build !debug
    4)在logger_debug.go中的Debug()是需要輸出的調試資訊,同時在檔案開始加上// + build debug

這樣,在測試環境編譯的時傳遞-tags參數:go build/install -tags “debug” logger。生產環境:go build/install logger就行了。

對於生產環境,不傳遞-tags時,為什麼會編譯logger_product.go呢?因為在go/build/build.go中的match方法中有這麼一句:
1        if strings.HasPrefix(name, "!") { // negation
2            return len(name) > 1 && !ctxt.match(name[1:])
3        }

也就是說,只要有!(不能只是!),tag不在BuildTags中時,總是會編譯。

完整源碼在github上

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.