Go 知识点(18)— 条件编译(编译标签、文件后缀)

1. 条件编译

Go 能根据所处环境选择对应的源码进行编译。让编译器只对满足条件的代码进行编译,将不满足条件的代码舍弃,这就叫做条件编译。

Go 中,也称之为 Build Constraints 编译约束,添加编译约束的以下 2 种:

  • 编译标签(build tag
  • 文件后缀

2. 编译标签

​编译标签是一种通过在源码文件顶部添加注释,来决定文件是否参与编译的约束方式。其格式如下:

// +build <tags>

注意:// +build 的下一行必须是空行,否则会被解析为包注释。

// +build linux

// main package comment
package main

Go 语言在构建一个包的时候会读取这个包里的每个源文件并且分析编译标签,这些标签决定了这个源文件是否参与本次编译。

tags 说明:

  • 以空格分开表示 OR
  • 以逗号分开表示 AND
  • ! 表示 NOT
  • 一个文件可以有多个 +build 构建标记,它们之间的关系是逻辑 的关系

标签可以指定为以下内容:

  • 操作系统,环境变量中 GOOS 的值,如:linuxdarwinwindows等;
  • 操作系统的架构,环境变量中 GOARCH的值,如:amd64x86i386 等;
  • 使用的编译器,gc 或者 gccgo
  • 是否开启 CGOcgo
  • go版本号:比如 Go Version 1.1go1.1Go Version 1.12 版本为 go1.12 以此类推。

其它自定义标签,通过 go build -tags 指定的值。

使用示例:

  • 编译条件为 (linux AND 386) OR (darwin AND (NOT cgo))
// +build linux,386 darwin,!cgo

  • 多个编译约束,比如条件为 (linux OR darwin) AND amd64
// +build linux darwin

// +build amd64

  • 也可以使用 ignore 标签将一个文件从编译中排除。
// +build ignore

  • linux 或者 windows amd64
// +build linux windows,amd64

package main

多个 +build 构建标记一般分成每行一个 +build 构建标记。

Gin 框架中,也较多地使用了编译标签,例如 internal/json 目录,这个目录目前只有 json 包。在 json 包中,这个包的两个文件分别都使用了标签 jsoniter

jsoniter.go 内容

// Copyright 2017 Bo-Yi Wu.  All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.

// +build jsoniter

package json

import "github.com/json-iterator/go"

var (
    json = jsoniter.ConfigCompatibleWithStandardLibrary
    // 通过函数值,Marshal 等函数都由 Gin 下的 json 包导出
    Marshal = json.Marshal
    Unmarshal = json.Unmarshal
    MarshalIndent = json.MarshalIndent
    NewDecoder = json.NewDecoder
    NewEncoder = json.NewEncoder
)

json.go 内容

// Copyright 2017 Bo-Yi Wu.  All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.

// +build !jsoniter

package json

import "encoding/json"

var (
    // 通过函数值,Marshal 等函数都由 Gin 下的 json 包导出
    Marshal = json.Marshal
    Unmarshal = json.Unmarshal
    MarshalIndent = json.MarshalIndent
    NewDecoder = json.NewDecoder
    NewEncoder = json.NewEncoder
)

Gin使用 encoding/json作为默认的 json包,但可以通过从其他标签构建来改变它。

$ go build -tags=jsoniter .

上述命令表示使用 jsoniter.go 文件来编译生成可执行文件。

$ go build -tags=go_json .

Gin 框架编译时,可以通过编译标签自由选择性编译。编译时如果指定 -tags=jsoniter,则会选择 jsoniter.go 进行编译,默认情况下一般都没有指定这个标签,所以使用的是标准库的 json 包。

由于第三方包 jsoniter 性能上要优于标准库的 json 包,而且这个包提供 100% 与标准库 json 包兼容选项,加上主要函数签名一致,所以 Gin 这里特意封装了新的 json 包,通过编译标签,程序编译时很容易根据实际标签来选择具体实现的代码包。

3. 文件后缀

除了编译标签,第二种添加编译约束的方法是通过源码文件的文件名实现的,这种方案比构造标签方案更简单。编译器也会根据文件后缀来自动选择编译文件:

$filename_$GOOS.go
$filename_$GOARCH.go
$filename_$GOOS_$GOARCH.go
  • $filename: 源文件名称;
  • $GOOS: 表示操作系统,从环境变量中获取;
  • $GOARCH: 表示系统架构,从环境变量中获取;

后缀的顺序记住不要颠倒,后缀中同时出现系统和架构名时,需要保持$filename_$GOOS_$GOARCH.go 的顺序。

标准库 os 源代码的部分截图:
标准库

构建标签和文件名后缀在功能上是重叠的,根据需要选择合适的就行。

参考:
https://mp.weixin.qq.com/s?__biz=MzAxNzY0NDE3NA==&mid=2247489316&idx=2&sn=5b556235a63781c852e490da67823f7d&chksm=9be338c5ac94b1d376f94b3d8990ec8062cae9745f1d1e0314b116d6003b48e8bbd72701b249&scene=126&&sessionid=1642228531#rd

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wohu007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值