官方資料 官方解釋: https://pkg.go.dev/cmd/go#hdr-Build_constraints ,go help buildconstraint 也能看到描述 根據官方描述,go1.16開始建議使用go:build方式,與+build相比更容易被人閱讀。 有關go:build註 ...
官方資料
官方解釋: https://pkg.go.dev/cmd/go#hdr-Build_constraints ,go help buildconstraint
也能看到描述
根據官方描述,go1.16
開始建議使用go:build
方式,與+build
相比更容易被人閱讀。
有關go:build
註釋的解析: src/go/build/build.go#shouldBuild
有關tag匹配規則: src/go/build/build.go#matchTag
下麵是代碼片段
func (ctxt *Context) matchTag(name string, allTags map[string]bool) bool {
if allTags != nil {
allTags[name] = true
}
// special tags
if ctxt.CgoEnabled && name == "cgo" {
return true
}
if name == ctxt.GOOS || name == ctxt.GOARCH || name == ctxt.Compiler {
return true
}
if ctxt.GOOS == "android" && name == "linux" {
return true
}
if ctxt.GOOS == "illumos" && name == "solaris" {
return true
}
if ctxt.GOOS == "ios" && name == "darwin" {
return true
}
if name == "unix" && unixOS[ctxt.GOOS] {
return true
}
if name == "boringcrypto" {
name = "goexperiment.boringcrypto" // boringcrypto is an old name for goexperiment.boringcrypto
}
// other tags
for _, tag := range ctxt.BuildTags {
if tag == name {
return true
}
}
for _, tag := range ctxt.ToolTags {
if tag == name {
return true
}
}
for _, tag := range ctxt.ReleaseTags {
if tag == name {
return true
}
}
return false
}
在源文件src/go/build/syslist.go
中可以找到knownOS
表示tag中可以填寫的OS,以及填寫unix
標簽時匹配的OSunixOS
,還有可填寫的架構knownArch
package build
// 已知的所有OS型號
var knownOS = map[string]bool{
"aix": true,
"android": true,
"darwin": true,
"dragonfly": true,
"freebsd": true,
"hurd": true,
"illumos": true,
"ios": true,
"js": true,
"linux": true,
"nacl": true,
"netbsd": true,
"openbsd": true,
"plan9": true,
"solaris": true,
"windows": true,
"zos": true,
}
// 當使用unix時,在如下這些OS中生效
var unixOS = map[string]bool{
"aix": true,
"android": true,
"darwin": true,
"dragonfly": true,
"freebsd": true,
"hurd": true,
"illumos": true,
"ios": true,
"linux": true,
"netbsd": true,
"openbsd": true,
"solaris": true,
}
// 已知的所有架構
var knownArch = map[string]bool{
"386": true,
"amd64": true,
"amd64p32": true,
"arm": true,
"armbe": true,
"arm64": true,
"arm64be": true,
"loong64": true,
"mips": true,
"mipsle": true,
"mips64": true,
"mips64le": true,
"mips64p32": true,
"mips64p32le": true,
"ppc": true,
"ppc64": true,
"ppc64le": true,
"riscv": true,
"riscv64": true,
"s390": true,
"s390x": true,
"sparc": true,
"sparc64": true,
"wasm": true,
}
BuildTags
BuildTags
是編譯命令時-tags
的參數列表,根據go help build
描述-tags
為逗號分隔字元串,相容舊版空格分隔字元串,具體代碼: src/cmd/go/internal/work/build.go#tagsFlag
因此go build -tags "a,b,c"
這種是新版推薦寫法,go build -tags "a b c"
這種是舊版相容寫法
ToolTags
ToolTags
是初始化時的工具標簽,源碼位置 src/cmd/go/internal/work/init.go#ToolTags
在源碼中我看到ToolTags
可以是race
,msan
,asan
,分別對應go build -race
,go build -msan``go build -asan
,這三種編譯參數。最常見的就是race
用來檢查程式是否存在競態。
ReleaseTags
ReleaseTags
是go發佈版本標簽,源碼: src/go/build/build.go#ReleaseTags
根據相關註釋發現ReleaseTags
最後一個值被認為是當前在用版本。根據這個標簽的源碼我們發現當使用//go:build go1.18
的xxx.go文件時,使用大於等於go1.18版本的go取編譯都會匹配成功,也就是說使用go1.19去編譯//go:build go1.18
的文件也是會成功的。
編譯優化
- 很多人都知道
C
語言可以在代碼裡面加上條件編譯,認為Go
只能基於文件進行條件編譯,畢竟一個//go:build xxx
將影響一個文件是否能被編譯,以及文件命名格式也是影響整個文件是否被編譯。 - 如何做到在某個代碼塊裡面嵌入條件編譯呢?實際上
Go
源碼已經有相關方案,可以參考 src/internal/race
race.go
內容如下
//go:build race
// +build race
package race
const Enabled = true
norace.go
內容如下
//go:build !race
// +build !race
package race
const Enabled = false
然後就會在源碼中找到大量 if race.Enabled {
,這種代碼,大家都知道執行go build -race
時race.Enabled = true
那麼這部分判斷就會執行,否則就不會執行。
我的問題是如果每次運行時都進行這些if
判斷雖然損耗不了多少性能但卻非常不優雅。但實際上Go
會在編譯時檢查確定的判斷,當判斷為false
時這部分代碼都會被優化掉,不會編譯到可執行程式中。
驗證編譯優化
package main
const enable = false
func main() {
if enable {
println("hello word")
}
}
執行go tool compile -S main.go > a
package main
const enable = true
func main() {
if enable {
println("hello word")
}
}
執行go tool compile -S main.go > b
然後比較a,b的結果,可以明顯看到當const enable = false
時println("hello word")
裡面的常量字元串都不會編譯到可執行程式中,所以我們可以放心使用編譯優化這個功能完成條件編譯。那些編譯時就能計算出結果的if
表達式大家可以放心編寫相關邏輯,這個if
是絕對不會在運行時去執行的。
只是麻煩的是代碼中出現的函數,在兩份條件編譯文件裡面都必須有聲明,可以參考race.go
,norace.go
這兩個文件的寫法。
總結
有關條件編譯的用法網上有很多資料,所以我這裡主要研究條件編譯原理,以及條件可以填寫的所有值,和一些特殊的規則,這樣在我編寫相關條件時可以更加的心應手
作者:janbar 出處:https://www.cnblogs.com/janbar 本文版權歸作者和博客園所有,歡迎轉載,轉載請標明出處。喜歡我的文章請 [關註我] 吧。 如果您覺得本篇博文對您有所收穫,可點擊 [推薦] 並 [收藏] ,或到右側 [打賞] 里請我喝杯咖啡,非常感謝。