官方资料
官方解释: 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
}
在源文件go/build/syslist.go
中可以找到knownOS
表示tag中可以填写得OS,以及填写unix
标签时匹配的OSunixOS
,还有可填写的架构knownArch
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
这两个文件的写法。
总结
有关条件编译的用法网上有很多资料,所以我这里主要研究条件编译原理,以及条件可以填写的所有值,和一些特殊的规则,这样在我编写相关条件时可以更加的心应手
.qm_point{color:#6DA47D;font-size:18px}.qm_a{color:#0000FF}
作者:janbar
出处:https://www.cnblogs.com/janbar
本文版权归作者和博客园所有,欢迎转载,转载请标明出处。喜欢我的文章请 [关注我] 吧。
如果您觉得本篇博文对您有所收获,可点击 [推荐] 并 [收藏] ,或到右侧 [打赏] 里请我喝杯咖啡,非常感谢。
来源:https://www.cnblogs.com/janbar/p/16976563.html
本站部分图文来源于网络,如有侵权请联系删除。