刘沙河 刘沙河
首页
  • Go语言基础

    • 数据类型
    • 反射
    • Go指针
  • Go语言进阶

    • go泛型
    • go条件编译
    • cgo教程
    • Go协程调度原理及GPM模型
    • Go内存管理
    • Go垃圾回收机制
    • Go语言内存对齐
  • Go语言实现原理

    • channel 实现原理
    • slice 实现原理
    • map 实现原理
    • sync.Mutex 实现原理
    • 乐观锁CAS 实现原理
    • singlefight 实现原理
  • gin框架

    • gin中间件原理
    • gin路由原理
  • gorm

    • GORM介绍和使用
    • GORM_CURD操作指南
  • go测试

    • benchmark基准测试
    • pprof 性能分析
  • python进阶

    • Numpy&Pandas
    • celery分布式任务队列
  • Django

    • Django 常见命令
    • middleware中间件
    • Django缓存系统
    • Django信号系统
    • Django REST Framework
  • Flask

    • Flask基础知识总结
    • Flask-SQLAlchemy
  • 爬虫

    • aiohttp
    • scrapy框架
  • Mysql

    • Mysql存储引擎和索引
    • MySQL主从复制
    • Mysql读写分离
    • 数据库分库分表
    • Mysql锁
    • Mysql事务和MVCC原理
    • 分库分表带来的读扩散问题
  • Redis

    • redis基础和数据类型
    • redis主从架构
    • redis哨兵架构
    • redis集群模式
    • 如何保证缓存和数据库双写一致
    • redis底层数据结构
    • redis分布式锁
  • Elasticsearch

    • es基本概念
    • es基础语法
    • es倒排索引
  • etcd

    • Go操作etcd
    • Raft原理
    • etcd分布式锁
  • kafka

    • 消息队列MQ总结
    • kafka 概述及原理
    • kafka 消费问题记录
    • 零拷贝技术
    • kafka分区规范
  • RabbitMQ

    • rabbitMQ基础
    • Go操作rabbitmq
  • RocketMQ

    • 可靠消息队列 rocketMQ
  • Http&Https

    • http&https
    • TCP和UDP
    • Ping 原理
  • RPC

    • RPC初识
    • grpc初识和实现
  • gRPC

    • grpc 初识
    • grpc 上下文 metadata
    • grpc 健康检查
    • grpc keepalive
    • grpc 命名解析
    • grpc 中间件&拦截器
    • grpc 负载均衡
    • grpc 身份认证
    • grpc 超时重试
    • grpc 链路追踪
    • grpc-gw将gRPC转RESTfu api
    • grpc-gw自定义选项
  • protobuf

    • protobuf 进阶
    • protobuf 编码原理
  • Docker

    • Docker基础
    • Docker常用命令
    • Dockerfile
    • Docker-Compose
    • Docker多阶段构建
    • Docker Config 教程
    • Docker Swarm 教程
    • Docker Stack 教程
    • Docker Buildx 教程
  • k8s

    • k8s 基础概念
    • k8s 集群架构
    • k8s 工作负载
    • Pod 网络
    • Service 网络
    • 外部接入网络
    • 一张图搞懂k8s各种pod
    • k8s 存储抽象
    • mac快速启动k8s
    • 自制申威架构k8s-reloader
  • go-kit

    • go-kit初识
    • go-kit启动http服务
    • go-kit集成gin启动服务
    • go-kit集成grpc和protobuf
    • go-kit中间件
    • go-kit服务注册发现与负载均衡
    • go-kit限流和熔断
    • go-kit链路追踪
    • go-kit集成Prometheus
  • 设计模式

    • 初识设计模式
    • 创建型模式
    • 结构型模式
    • 行为模式
  • 数据结构

    • 时间轮
    • 堆、双向链表、环形队列
    • 队列:优先队列
    • 队列:延迟队列
  • 算法

    • 递归算法
    • 枚举算法
    • 动态规划
    • 回溯算法
    • 分治算法
    • 贪心算法
    • LRU和LFU
    • 一致性哈希

花开半夏,半夏花开
首页
  • Go语言基础

    • 数据类型
    • 反射
    • Go指针
  • Go语言进阶

    • go泛型
    • go条件编译
    • cgo教程
    • Go协程调度原理及GPM模型
    • Go内存管理
    • Go垃圾回收机制
    • Go语言内存对齐
  • Go语言实现原理

    • channel 实现原理
    • slice 实现原理
    • map 实现原理
    • sync.Mutex 实现原理
    • 乐观锁CAS 实现原理
    • singlefight 实现原理
  • gin框架

    • gin中间件原理
    • gin路由原理
  • gorm

    • GORM介绍和使用
    • GORM_CURD操作指南
  • go测试

    • benchmark基准测试
    • pprof 性能分析
  • python进阶

    • Numpy&Pandas
    • celery分布式任务队列
  • Django

    • Django 常见命令
    • middleware中间件
    • Django缓存系统
    • Django信号系统
    • Django REST Framework
  • Flask

    • Flask基础知识总结
    • Flask-SQLAlchemy
  • 爬虫

    • aiohttp
    • scrapy框架
  • Mysql

    • Mysql存储引擎和索引
    • MySQL主从复制
    • Mysql读写分离
    • 数据库分库分表
    • Mysql锁
    • Mysql事务和MVCC原理
    • 分库分表带来的读扩散问题
  • Redis

    • redis基础和数据类型
    • redis主从架构
    • redis哨兵架构
    • redis集群模式
    • 如何保证缓存和数据库双写一致
    • redis底层数据结构
    • redis分布式锁
  • Elasticsearch

    • es基本概念
    • es基础语法
    • es倒排索引
  • etcd

    • Go操作etcd
    • Raft原理
    • etcd分布式锁
  • kafka

    • 消息队列MQ总结
    • kafka 概述及原理
    • kafka 消费问题记录
    • 零拷贝技术
    • kafka分区规范
  • RabbitMQ

    • rabbitMQ基础
    • Go操作rabbitmq
  • RocketMQ

    • 可靠消息队列 rocketMQ
  • Http&Https

    • http&https
    • TCP和UDP
    • Ping 原理
  • RPC

    • RPC初识
    • grpc初识和实现
  • gRPC

    • grpc 初识
    • grpc 上下文 metadata
    • grpc 健康检查
    • grpc keepalive
    • grpc 命名解析
    • grpc 中间件&拦截器
    • grpc 负载均衡
    • grpc 身份认证
    • grpc 超时重试
    • grpc 链路追踪
    • grpc-gw将gRPC转RESTfu api
    • grpc-gw自定义选项
  • protobuf

    • protobuf 进阶
    • protobuf 编码原理
  • Docker

    • Docker基础
    • Docker常用命令
    • Dockerfile
    • Docker-Compose
    • Docker多阶段构建
    • Docker Config 教程
    • Docker Swarm 教程
    • Docker Stack 教程
    • Docker Buildx 教程
  • k8s

    • k8s 基础概念
    • k8s 集群架构
    • k8s 工作负载
    • Pod 网络
    • Service 网络
    • 外部接入网络
    • 一张图搞懂k8s各种pod
    • k8s 存储抽象
    • mac快速启动k8s
    • 自制申威架构k8s-reloader
  • go-kit

    • go-kit初识
    • go-kit启动http服务
    • go-kit集成gin启动服务
    • go-kit集成grpc和protobuf
    • go-kit中间件
    • go-kit服务注册发现与负载均衡
    • go-kit限流和熔断
    • go-kit链路追踪
    • go-kit集成Prometheus
  • 设计模式

    • 初识设计模式
    • 创建型模式
    • 结构型模式
    • 行为模式
  • 数据结构

    • 时间轮
    • 堆、双向链表、环形队列
    • 队列:优先队列
    • 队列:延迟队列
  • 算法

    • 递归算法
    • 枚举算法
    • 动态规划
    • 回溯算法
    • 分治算法
    • 贪心算法
    • LRU和LFU
    • 一致性哈希
  • go语言基础

  • go语言进阶

    • go 泛型
    • go条件编译
      • 编译标签(build tags)
        • 1. //go:build 和 // +build 的区别
        • 2. 使用说明
        • 3. 注意事项
      • 文件后缀
    • 分布式从ACID、CAP、BASE的理论推进
    • go链接参数 ldflags
    • TCP网络连接以及TIME_WAIT的意义
    • Go异常处理
    • Go性能调优 pprof
    • Go语言设计模式
    • Go 切片的截取
    • Go runtime详解
    • go执行外部命令
    • 标准库container三剑客:head、list、ring
    • go与http代理
    • Go内存管理
    • Go垃圾回收机制
    • Go语言中的并发编程
    • Go协程调度原理及GPM模型
    • Go中逃逸现象, 变量+堆栈
    • Go面向对象的思维理解interface
    • Go中的Defer
    • Go和Python中的深浅拷贝
    • Go语言内存对齐
    • 流和IO多路复用
    • 单点Server的N种并发模型汇总
    • 控制goroutine的数量
    • 配置管理库—Viper
    • 高性能日志库zap
    • Go中的Mutex和RWMutex.md
    • sqlx的使用
    • 分布式id 库snowflake和sonyflake
    • sync.Pool 复用对象
    • sync.Once 单例模式
    • sync.Cond 条件变量
    • unsafe.Pointer 和 uintptr
    • go 信号量
    • go语言代码优化技巧
    • go 接口型函数
    • 位运算
    • cgo教程
    • go调用lib和so动态库
  • go语言实现原理

  • gin框架

  • gorm

  • go测试

  • Go语言
  • go语言进阶
bigox
2023-05-17
目录

go条件编译

  • go支持两种条件编译的实现方式

    1. 编译标签(build tags)

      //go:build !windows 和 // +build !windows

    2. 文件后缀

  • 条件编译的应用场景

    1. 平台适配:不同平台的操作系统和 CPU 架构可能有不同的特性和限制,需要针对不同平台编写不同的代码。通过条件编译,可以根据不同平台选择不同的代码进行编译,从而提高程序的性能和稳定性。
    2. 调试信息:在开发和调试过程中,需要添加一些调试信息来辅助开发人员定位问题。但是,在发布版本时这些信息不应该包含在内。使用条件编译,可以在开发和调试阶段包含调试信息,在发布版本中去除这些信息。
    3. 功能开关:有些功能可能只在特定的场景下使用,而在其他场景下不需要。使用条件编译可以根据编译标记开启或关闭这些功能,从而减少程序的代码量和复杂度。
    4. 性能优化:有些代码可能只在特定的环境下才能发挥最优性能。使用条件编译,可以根据编译标记选择不同的代码实现,从而提高程序的性能。

# 编译标签(build tags)

# 1. //go:build 和 // +build 的区别

  • // +build编译条件的注释和package 语句之间一定要隔一行。不然无法识别编译条件,编译条件支持“非”逻辑,比如某个文件在非 windows 环境下编译

  • //go:build是Go 1.17中引入的新的条件编译指令,旨在取代// +build指令,因为新语法带来了一些关键改进:

    • 与其他现有Go指令和pragma的一致性,例如//go:generate
    • 支持标准布尔表达式,例如//go:build foo && bar,而旧的// +build注释的语法不那么直观。例如,AND用逗号// +build foo,bar和或空格// +build foo bar表示
    • 它由go fmt支持,它将自动修复指令在源文件中的错误位置,从而避免常见错误,如在指令和包语句之间不留空行。
  • 在Go 1.N中:

    • 生成将开始优先选择//go:build行进行文件选择。如果文件中没有//go:build,那么任何// +build行仍然适用。
    • 如果Go文件包含//go:build而没有// +build,则构建将不再失败。
    • 如果Go或程序集文件中包含//go:build太晚,则生成将失败。Gofmt将把错位的//go:build和//+build行移到文件中的正确位置。
    • Gofmt将使用与其他Go布尔表达式(所有&&和||运算符周围的空格)相同的规则格式化//go:build行中的表达式。
    • 如果文件只包含// +build行,则gofmt将在其上方添加一个等效的//go:build行。
    • 如果一个文件同时包含//go:build和// +build行,则gofmt将考虑//go:build是真理的来源,并更新// +build行以匹配,从而保持与早期版本的Go的兼容性。Gofmt还将拒绝被认为太复杂而无法转换为// +build格式的//go:build行,尽管这种情况很少见。(注意此项目符号开头的“If”。Gofmt不会将// +build行添加到只有//go:build.的文件中)
    • buildtags签入go vet将添加对//go:build约束的支持。当Go源文件包含具有不同含义的//go:build和// +build行时,它将失败。如果检查失败,可以运行gofmt -w。

# 2. 使用说明

  • 基础语法

    // +build <tag1> <tag2> <tag3> ...
    或者是
    //go:build <tag1> <tag2> <tag3> ...
    
    编译的时候
    go build -tag1 mytag2 mytag3
    
    1
    2
    3
    4
    5
    6
    • <tag> 可以是操作系统、CPU 架构、编译标记等,多个标记之间用空格分隔或者都好分隔。
      • 编译标签由空格分隔的编译选项(options)以”或”的逻辑关系组成
      • 每个编译选项由逗号分隔的条件项以逻辑”与”的关系组成
      • 每个条件项的名字用字母+数字表示,在前面加!表示否定的意思
      • 不同tag域之间用空格区分,他们是OR关系
      • 同一tag域之内不同的tag用都好区分,他们是AND关系
      • 每一个tag都由字母和数字构成,!开头表示条件“非”
    // +build linux darwin
    // +build 386
    
    1
    2
    • 一个源文件里可以有多个编译标签,多个编译标签之间是逻辑”与”的关系

    • 关系

      空格表示:AND 
      逗号表示:OR 
      !表示:NOT 
      换行表示:AND
      
      1
      2
      3
      4
  • 内置 tag

    • 指定操作系统:如 darwin、linux、windows 等,对应 runtime.GOOS 的值。

    • 指定CPU 架构:如 amd64、arm、386 等,对应 runtime.GOARCH 的值。

    • 指定编译器:例如:gccgo、gc,是否开启CGO,cgo。

    • 指定Go 版本:例如:go1.19、go1.20 等。

    • // +build ignore,编译时自动忽略该文件

    • demo

      // +build linux,arm !darwin
      
      表示该文件在 Linux 平台且 ARM 架构下编译,但不在 Darwin 平台下编译。
      
      1
      2
      3
  • 自定义tag, // +build mytag 编译的时候go build -tags mytag才会编译此文件

# 3. 注意事项

  • // +build 或者 //go:build 指令必须放在文件的开头。
  • // +build 或者 //go:build 指令只能出现一次,且只能针对整个文件进行编译,不能对单独的函数或变量进行编译。
  • 标记中的操作系统和 CPU 架构必须使用官方定义的名称,否则编译器无法识别。
  • 在编写代码时,应该尽量避免使用条件编译,以保持代码的简洁和易读性。
  • 在使用编译标记时,应该尽量使用官方定义的标记,避免与其他库或框架的标记冲突。

# 文件后缀

  • 这个方法通过改变文件名的后缀来提供条件编译,这种方案比编译标签要简单很多

  • go/build可以在不读取源文件的情况下就可以决定哪些文件不需要参与编译。

  • 简单来说,就是源文件包含后缀:$GOOS.go,那么这个源文件只会在这个平台下编译,$GOARCH.go也是如此。

  • demo

    mygo_freebsd_arm.go // only builds on freebsd/arm systems
    mygo_plan9.go       // only builds on plan9
    
    1
    2
#Go
上次更新: 2023/09/01, 22:31:42
go 泛型
分布式从ACID、CAP、BASE的理论推进

← go 泛型 分布式从ACID、CAP、BASE的理论推进→

最近更新
01
go与http代理
05-24
02
自制申威架构k8s-reloader
12-06
03
Docker Buildx 教程
12-01
更多文章>
Theme by Vdoing | Copyright © 2020-2024 小刘扎扎 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式