這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
Go語言有一個不(奇)錯(葩)的設計,就是build constraints(構建約束)。可以在源碼中通過注釋的方式指定編譯選項,比如只允許在linux下,或者在386的平台上編譯啊之類的;還可以通過檔案名稱來約束構造,比如xxxx_linux.go,就是只允許在linux下編譯,xxx_windows_amd64.go就是只允許在windows x64下編譯。
構建約束可以在很多檔案中使用,不單單是GO檔案。但是必須要注意的是,通過注釋實施構建約束的話,比如要放在檔案的開頭,要優先於空行或和其他注釋之前。也就是說必須在package語句的前面寫。這就有個很蛋疼的檔案,因為GO的godoc是可以提取代碼中的注釋然後轉換為文檔的。在package語句之前寫的注釋會被認為是包層級的注釋。而構建約束又在所有注釋之前,那麼為了區分包層級的注釋,就要在構建約束與包層級的注釋之間添加空行進行區分。(這個設計看上去不得不承認很囧)。
通過注釋實施的構建約束還可以進行邏輯表達。就是and, or之類的語義。GO的官方是這麼定義的:如果構建約束中有空格,那麼就是OR關係,如果是逗號分隔,那麼就是AND關係。!表示not。比如
// +build linux,386 darwin,!cgo
就是表示(linux AND 386) OR (darwin AND (NOT cgo))
而且GO還支援多行的構建約束,多行之間是AND關係,比如
// +build linux darwin
// +build 386
就是表示(linux OR darwin) AND 386
GO官方還定義了常用的一些約束
- 限制目標作業系統,也就是要和runtime.GOOS一致
- 限制目標架構平台,也就是要和runtime.GOARCH一致
- GC或者GCCGO等編譯器支援的約束
- cgo約束,也就是說如果支援cgo的話,就可以參與編譯
- go1.1,表示從go1.1開始向前相容
- go1.2,表示從1.2開始向前相容
- go.13,表示從1.3開始向前相容
- 自訂的約束
如果你想臨時讓某個檔案不參與編譯,可以添加註釋約束下: // +build ignore
通過注釋來實現構建約束有點蛋疼,而且GO官方定義裡還表示可以自訂約束,那麼可以用來幹嘛?學GO的人都知道GO內建了單元測試的架構,跑跑一般的單元測試還是非常嗨皮的,但是如果要做一些簡單的整合測試就令人拙計了,因為go test預設就是跑最基本的單元測試。那麼怎麼只執行整合測試的代碼呢?其實就可以通過構建約束來實施。比如我們在整合測試的GO檔案中加上 // +build integration 然後運行命令 go test –tags=”integration”就可以只運行我們的整合測試代碼了。
雖然通過注釋的方式對構建進行了約束,但是檔案名稱的構建約束反而讓人覺著很不錯呢,至少在工程裡看著一目瞭然。檔案名稱首碼只要含有_GOOS, _GOARCH, _GOOS_GOARCH的就可以了。比如xxx_linux.go yyy_windows_amd64.go , zzzz_386.s等等。