Golang条件编译介绍
相信熟悉 Golang 的小伙伴不少都知道 条件编译
这个事,最近项目中也可能会用到这个东西。所以特意重新学习下,记录下学习的过程。这样用的时候记不住了,还可以直接过来看自己的笔记。
文章很多内容来源于参考资料,感谢。
1、条件编译简介
1.1、为什么需要条件编译
在实际的项目开发中,我们可能需要根据条件的不同,来编译release和debug版本
代码的需求,也可能需要根据运行环境的不同来编译不同的文件,诸如此类的需求时,我们应该怎么做呢?
这个时候就可以使用 Golang 中的条件编译了,Golang 支持两种条件编译方式:
- 构建标签( Build tags)
- 文件后缀(File suffixes)
1.2、条件编译原理简单介绍
Go使用 go/build包 中定义的标签系统(system of tags
)和命名约定(naming convention
)以及go tool
中的相应支持来允许Go包编译特定代码。
说简单的,就是通过约定好的规定,在执行
go build
选择性地包含或排除代码的机制。注意,go1.17 过后,条件编译的写法和之前有些不同,需要注意一下。
具体的tag
匹配规则可以看go/build/build.go
,不过对于日常使用来说,知道使用的规则即可,无需深入源码。
接下来,我们就一起看看 golang 条件编译的 tag 规则是怎么样的吧。
2、条件编译实现方式
2.1、构建标签( Build tags)
第一种实现条件编译的方法是在源码中插入注释,被称之为构建标签。
构建标签的注释应该尽可能的接近源码文件的顶部位置。
当Go编译一个包时,它会分析包内的每个源码文件并查找构建标签。标签决定了这个源码文件是否被编译。
2.1.1、使用方法
- 构建约束以一行
+build
开始的注释。在+build
之后列出了一些条件,在这些条件成立时,该文件应包含在编译的包中; - 约束可以出现在任何源文件中,不限于go文件;
+build
必须出现在package
语句之前,+build
注释之后应要有一个空行,否则不会生效。
// +build debug
package main
import "fmt"
func main() {
fmt.Println("Hello World!")
}
可以用以下命令构建:
go build -tags "debug"
条件编译的最小单元是以 文件 来进行的。
2.1.2、语法规则
构建约束以一行
+build
开始的注释。在+build
之后列出了一些条件,在这些条件成立时,该文件应包含在编译的包中;约束可以出现在任何源文件中,不限于go文件;
+build
必须出现在package
语句之前,+build
注释之后应要有一个空行。多个条件之间,
空格表示OR;逗号表示AND;叹号(!)表示NOT
。一个文件可以有多个+build,它们之间的关系是
AND
。tag的名称只允许是
字母数字或_
当不想编译某个文件时,可以加上
// +build ignore
。这里的ignore
可以是其他单词,只是ignore
更能让人知道什么意思
2.2、文件后缀(File suffixes)
第二种条件编译的方法是通过源码文件的文件名实现的。这种方案比构造标签方案更简单。
go/build
包的文档有关于命名约定的描述。简单来说,如果文件名包含_$GOOS.go
后缀,那么这个源码文件只会在对应的平台被编译。其他平台会忽略这个文件。另一种约定是_$GOARCH.go
。这两种后缀可以组合起来,但要保证顺序,正确的格式是_$GOOS_$GOARCH.go
,错误的格式是_$GOARCH_$GOOS.go
。
以下是文件名后缀的一些例子:
mypkg_freebsd_arm.go // 只在 freebsd/arm 系统编译
mypkg_plan9.go // 只在 plan9 编译
源码文件光有后缀是不够的,比如如下文件名:
_linux.go
_freebsd_386.go
即使是在linux或freebsd
系统,这两个文件也会被忽略,原因是go/build
包会忽略所有文件名以.
和_
开始的文件。
2.3、额外说明
构建标签和文件后缀如何选择?
我的理解是按照需求颗粒度,如果说,编译条件需要按照系统来进行划分,可以使用文件后缀,否则就选项构建标签,这样颗粒度更小也更加灵活。
构建标签和文件名后缀在功能上是重叠的。比如,一个名为mypkg_linux.go
的文件,再包含构建标签// +build linux
会显得多余。
通常来说,当只有一个特定平台或体系需要指定时,我们选择文件名后缀的方式。比如:
mypkg_linux.go // 只在 linux 系统编译
mypkg_windows_amd64.go // 只在 windows amd 64位 平台编译
相反,如果你的文件需要指定给多个平台或体系使用,或者你需要排除某个特定平台时,我们选择构建标签的方式。比如:
// 在所有类unix平台编译
% grep '+build' $HOME/go/src/pkg/os/exec/lp_unix.go
// +build darwin dragonfly freebsd linux netbsd openbsd
// 在非Windows平台编译
% grep '+build' $HOME/go/src/pkg/os/types_notwin.go
// +build !windows
3、条件编译实战
以下介绍都是基于go 1.18、windows 介绍的
。
3.1、构建标签
一共三个文件,分别是:
-- main.go
-- tag_ignore.go
-- tag_include.go
main.go
package main
import "fmt"
func main() {
fmt.Println("Hello World!")
}
tag_ignore.go
//go:build ignore
// +build ignore
package main
import "fmt"
func init() {
fmt.Println("perform tag_ignore")
}
tag_include.go
//go:build include
// +build include
package main
import "fmt"
func init() {
fmt.Println("perform tag_include")
}
# 未使用 tags 标签
go build .\main.go .\tag_ignore.go .\tag_include.go
生成 main.exe
----------------------------------------------------
# 使用 tags 标签
go build -tags "include"
生成 build_tag.exe
从上面可知未将 tag_ignore.go
编译进二进制文件。
3.2、文件后缀
这里就比较好理解,如果使用的是 goland 当在 windows 上面新建文件名为 tag_linux.go
时,goland 会自动提示 tag_linux.go is ignored by the build tool because of the OS mismatch
。
参考资料:
Golang条件编译介绍的更多相关文章
- golang goroutine 介绍
Goroutine 是用户态自己实现的线程,调度方式遇到IO/阻塞点方式就会让出cpu时间(其实也看编译器的实现,如果TA在代码里面插入一些yield,也是可以的. 反正现在不是抢占式的.) 不能设置 ...
- golang rpc介绍
rpc包提供了通过网络或其他I/O连接对一个对象的导出方法的访问.服务端注册一个对象,使它作为一个服务被暴露,服务的名字是该对象的类型名.注册之后,对象的导出方法就可以被远程访问.服务端可以注册多个不 ...
- <转>年终盘点!2017年超有价值的Golang文章
马上就要进入2018年了,作为年终的盘点,本文列出了一些2017年的关于Go编程的一些文章,并加上简短的介绍. 文章排名不分先后, 文章也不一定完全按照日期来排列.我按照文章的大致内容分了类,便于查找 ...
- Golang适合高并发场景的原因分析
http://blog.csdn.NET/ghj1976/article/details/27996095 典型的两个现实案例: 我们先看两个用Go做消息推送的案例实际处理能力. 360消息推送的数据 ...
- golang面向对象和interface接口
一. golang面向对象介绍 1.golang也支持面向对象编程,但是和传统的面向对象编程有区别,并不是纯粹的面向对象语言.2.golang没有类(class),golang语言的结合体(struc ...
- Golang template和junit xml report转html工具
最近刚好有个task是要用Golang把Junit的XML格式report转换成HTML格式,便学习了Golang的template包. 基于template做的那个junit XML转HTML工具. ...
- C语言条件编译(#if,#ifdef,#ifndef,#endif,#else,#elif)
1.条件编译介绍 条件编译(conditional compiling)命令指定预处理器依据特定的条件来判断保留或删除某段源代码.例如,可以使用条件编译让源代码适用于不同的目标系统,而不需要管理该源代 ...
- Visual Studio Code配置GoLang开发环境
Visual Studio Code配置GoLang开发环境 在Visual Studio Code配置GoLang开发环境 作者:chszs,未经博主允许不得转载.经许可的转载需注明作者和博客主页: ...
- Golang资料集
<Platform-native GUI library for Go> 介绍:跨平台的golang GUI库,支持Windows(xp以上),Unix,Mac OS X(Mac OS X ...
- golang tcp keepalive实践
前文中已经介绍了TCP keep alive的做了详尽说明,本文结合golang,介绍如何使用TCP keep alive. 目前golang net包不提供TCP keep alive 空闲多长时间 ...
随机推荐
- [转帖]兆芯官方的CPU测试成绩,我复现不了
https://baijiahao.baidu.com/s?id=1734998483605483848 下图是兆芯网官上的公开测试成绩,测试对象是3.0GHz的KX-U6880A. 有几个问题: ...
- 物联网浏览器(IoTBrowser)-Web串口自定义开发
物联网浏览器(IoTBrowser)-Web串口自定义开发 工控系统中绝大部分硬件使用串口通讯,不论是原始串口通讯协议还是基于串口的Modbus-RTU协议,在代码成面都是使用System.IO.Po ...
- 京东金融APP-新交互技术“虚拟数字人”赋能世界杯主题营销
作者:平台研发部,智能服务与产品部 距离加文·伍德提出web3.0已经过去8年时间,这8年加文·伍德创建的以太坊大放异彩,同时由web3.0引出的数字人.元宇宙也生根发芽,茁壮成长,带来了非凡的用户体 ...
- 【小实验】golang中的字节对齐
作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu Github 公众号:一本正经的瞎扯 使用golang来调用SIMD指令,发现程序崩溃了: __ ...
- minIO系列文章04---windows下安装及在.netcore使用
一.minio下载与启动 下载后会有一个minio.exe文件,放到指定的目录 在该目录下运行:minio.exe server D:\minio\file 出现如下的提示代码启动动成功: 浏览器中 ...
- vim 从嫌弃到依赖(13)——motion 进阶
在最开始的时候我们介绍了一些vim中的motion 包括如何在字符间.单词间.行间以及多行间移动.·但是motion中的内容可远不止我们介绍的这些,平时用到的也远不止之间介绍的那些. 之所以没有一次介 ...
- Elasticsearch Relevance Engine---为AI变革提供高级搜索能力[ES向量搜索、常用配置参数、聚合功能等详解]
Elasticsearch Relevance Engine---为AI变革提供高级搜索能力[ES向量搜索.常用配置参数.聚合功能等详解] 今天要介绍的 Elasticsearch Relevance ...
- C# 通过VMI接口获取硬件ID
使用C#语言实现通过VMI(虚拟机监控器)接口来获取硬件ID的过程.VMI是一种用于虚拟化环境的接口,用于管理虚拟机和宿主机之间的通信和资源共享.具体实现中,需要通过添加System.Manageme ...
- Delphi实现登录窗体与主窗体的过程
登录窗体: type TfrmLogin = class(TForm) btn1: TButton; procedure btn1Click(Sender: TObject); private { P ...
- mybatis SQL in() 为什么要在 mapper.xml里 用 foreach
结论: 若存在 in () 语句,要使用 #{} 预编译入参的方式,需要在 mapper.xml里 使用 foreach ======================================= ...