参考:

  1. 使用interface化解一场因操作系统不同导致的编译问题
  2. Bug-resistant build constraints — Draft Design

构建约束

Go 语言的构建约束(Build Constraints)是一种条件编译机制,允许开发者根据不同的构建条件编译不同的代码文件或代码块。这种机制在以下场景特别有用:

  • 为不同操作系统编写特定代码
  • 创建功能开关
  • 构建不同版本的程序(如社区版/专业版)
  • 处理平台特定的依赖

使用方式

编译标签(build tag)

  1. 在源码文件顶部添加 (在所有代码之前),来决定文件是否参与编译
  2. 与其他注释之间需要存在一个空行

常用预定义约束条件

约束条件说明
linuxLinux 系统
darwinmacOS 系统
windowsWindows 系统
amd6464位 x86 架构
armARM 架构
38632位 x86 架构
arm6464位 ARM 架构
cgo启用 CGO
race启用竞态检测
test测试模式
prod生产环境(自定义)
debug调试模式(自定义)

语法

  1. 以下是 Go 1.17 之后新版构建约束语法:

    1BuildLine      = "//go:build" Expr
    2Expr           = OrExpr
    3OrExpr         = AndExpr   { "||" AndExpr }
    4AndExpr        = UnaryExpr { "&&" UnaryExpr }
    5UnaryExpr      = "!" UnaryExpr | "(" Expr ")" | tag
    6tag            = tag_letter { tag_letter }
    7tag_letter     = unicode_letter | unicode_digit | "_" | "."
    
    1&& 表示:AND
    2|| 表示:OR
    3! 表示:NOT
    4() 表示:分组
    
    1//go:build linux && amd64
    
  2. 旧语法(向后兼容)

    1空格表示:AND
    2逗号表示:OR
    3!表示:NOT
    4换行表示:AND
    
    1// +build linux,amd64
    

构建命令示例

1//go:build dog
2
3package main
4
5func sum(a, b int) int {
6	return a + b
7}
1//go:build !dog
2
3package main
4
5func sum(a, b int) int {
6	return a + b
7}
  • 当使用 go buildgo build !dog 时,编译的是第二个文件
  • 当使用 go build tags dog 时,编译的是第一个文件

编译器根据 tag 标识,有选择性的加载对应文件进行编译

 1# 构建 Linux 版本
 2go build -tags linux
 3
 4# 构建生产版本
 5go build -tags prod
 6
 7# 构建带调试信息的 Windows 版本
 8go build -tags "windows debug"
 9
10# 构建测试版本带竞态检测
11go test -race -tags test

文件后缀

文件名模式等效构建约束
*_linux.go// +build linux
*_windows_amd64.go// +build windows,amd64
*_test.go// +build test

Go源码中 os 包的Linux、windows实现:

1src/runtime/os_linux.go
2src/runtime/os_linux_arm.go
3src/runtime/os_linux_arm64.go
4src/runtime/os_windows.go
5src/runtime/os_windows_arm.go
6src/runtime/os_windows_arm64.go

注意事项

  1. 构建约束注释后必须有一个空行
  2. 当使用文件命名约定时,显式的构建约束会覆盖命名约定
  3. 构建约束不会影响导入的包,只会影响当前文件的编译