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

news/2025/2/19 17:01:38/

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,amd64package 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 jsoniterpackage jsonimport "github.com/json-iterator/go"var (json = jsoniter.ConfigCompatibleWithStandardLibrary// 通过函数值,Marshal 等函数都由 Gin 下的 json 包导出Marshal = json.MarshalUnmarshal = json.UnmarshalMarshalIndent = json.MarshalIndentNewDecoder = json.NewDecoderNewEncoder = 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 !jsoniterpackage jsonimport "encoding/json"var (// 通过函数值,Marshal 等函数都由 Gin 下的 json 包导出Marshal = json.MarshalUnmarshal = json.UnmarshalMarshalIndent = json.MarshalIndentNewDecoder = json.NewDecoderNewEncoder = json.NewEncoder
)

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

  • jsoniter
$ go build -tags=jsoniter .

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

  • go_json
$ 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


http://www.ppmy.cn/news/603114.html

相关文章

Go 知识点(19)— Go 语言中的野指针

野指针是一种指向内存位置是不可知的指针&#xff0c;一般是由于指针变量在声明时没有初始化所导致的。在 Go语言中&#xff0c;布尔类型的零值为 false&#xff0c;数值类型的零值为 0&#xff0c;字符串类型的零值为 ""&#xff0c;而指针、切片、映射、信道、函数…

Gin 框架学习笔记(01)— 自定义结构体绑定表单、绑定URI、自定义log、自定义中间件、路由组、解析查询字符串、上传文件、使用HTTP方法

要实现一个 API 服务器&#xff0c;首先要考虑两个方面&#xff1a;API 风格和媒体类型。Go 语言中常用的 API 风格是 RPC 和 REST&#xff0c;常用的媒体类型是 JSON、XML 和 Protobuf。在 Go API 开发中常用的组合是 gRPCProtobuf 和 RESTJSON。 1. 安装 Gin是一个用 Go&am…

Gin 框架学习笔记(02)— 参数自动绑定到结构体

参数绑定模型可以将请求体自动绑定到结构体中&#xff0c;目前支持绑定的请求类型有 JSON 、XML 、YAML 和标准表单 form数据 foobar&boobaz 等。换句话说&#xff0c;只要定义好结构体&#xff0c;就可以将请求中包含的数据自动接收过来&#xff0c;这是 Gin 框架非常神奇…

Gin 框架学习笔记(03)— 输出响应与渲染

在 Gin 框架中&#xff0c;对 HTTP 请求可以很方便有多种不同形式的响应。比如响应为 JSON 、 XML 或者是 HTML 等。 ​ Context 的以下方法在 Gin 框架中把内容序列化为不同类型写入到响应主体中。 // HTML 呈现指定文件名的 HTTP 模板。 // 更新 HTTP 状态代码并将 Content…

Redis 笔记(07)— sorted set 类型(添加、删除有序集合元素、获取分数范围内成员、按score排序、返回集合元素个数)

zset 可能是 Redis 提供的最为特色的数据结构&#xff0c;一方面它是一个 set&#xff0c;保证了内部 value 的唯一性&#xff0c;另一方面它可以给每个 value 赋予一个 score&#xff0c;代表这个 value 的排序权重。它的内部实现用的是一种叫做「跳跃列表」的数据结构。 zse…

Redis 笔记(08)— 事务(一次执行多条命令、命令 watch/multi/exec/discard、错误处理)

1. 事务概念 Redis 中的事务 &#xff08;transaction&#xff09;是一组命令的集合。事务同命令一样是 Redis 的最小执行单位&#xff0c;一个事务中的命令要么都执行&#xff0c;要么都不执行。事务的原理是先将属于一个事务的命令发送给 Redis&#xff0c;然后再让 Redis 依…

Redis 笔记(09)— 过期时间 expire(设置、查询、取消过期时间)

1. 设置过期时间 Redis 使用 expire 命令设置一个键的过期时间&#xff0c;到时间后 Redis 会自动删除它。expire 命令的使用方法为 expire key seconds其中 seconds 表示键的过期时间&#xff0c;单位为秒且必须是整数&#xff0c;最小单位是 1 秒&#xff0c;expire 命令格…

Nova中 Vitalik R1CS例子 的 folding scheme

1. 引言 前序博客有&#xff1a; Nova代码解析Spartan中 Vitalik R1CS例子 SNARK证明基本思路rank-1 constraint system R1CS 其中 F ( x ) x 3 x 5 F(x)x^3x5 F(x)x3x5&#xff0c;注意其中 x , y x,y x,y均为public input/output。以连续调用两次为例&#xff0c;代码见…