開篇
golang中沒有類似C語言中條件編譯的寫法,比如在C代碼中可以使用如下語法做一些條件編譯,結合宏定義來使用可以實現諸如按需編譯release和debug版本代碼的需求
#ifndef
#define
...
#end
但是golang支持兩種條件編譯方式
- 編譯標籤( build tag)
- 文件後綴
編譯標籤( build tag)
在源代碼裏添加標註,通常稱之爲編譯標籤( build tag),編譯標籤是在儘量靠近源代碼文件頂部的地方用註釋的方式添加
go build在構建一個包的時候會讀取這個包裏的每個源文件並且分析編譯便籤,這些標籤決定了這個源文件是否參與本次編譯
編譯標籤添加的規則(附上原文):
- a build tag is evaluated as the OR of space-separated options
- each option evaluates as the AND of its comma-separated terms
- each term is an alphanumeric word or, preceded by !, its negation
1). 編譯標籤由空格分隔的編譯選項(options)以"或"的邏輯關係組成
2). 每個編譯選項由逗號分隔的條件項以邏輯"與"的關係組成
3). 每個條件項的名字用字母+數字表示,在前面加!表示否定的意思
例子(編譯標籤要放在源文件頂部)
// +build darwin freebsd netbsd openbsd
這個將會讓這個源文件只能在支持kqueue的BSD系統裏編譯
一個源文件裏可以有多個編譯標籤,多個編譯標籤之間是邏輯"與"的關係
// +build linux darwin
// +build 386
這個將限制此源文件只能在 linux/386或者darwin/386平臺下編譯.
除了添加系統相關的tag,還可以自由添加自定義tag達到其它目的。
編譯方法:
只需要在go build指令後用-tags指定編譯條件即可
go build -tags mytag1 mytag2
注意:剛開始使用編譯標籤經常會犯下面這個錯誤
// +build !linux
package mypkg // wrong
這個例子裏的編譯標籤和包的聲明之間沒有用空行隔開,這樣編譯標籤會被當做包聲明的註釋而不是編譯標籤從而被忽略掉
下面這個是正確的標籤的書寫方式,標籤的結尾添加一個空行這樣標籤就不會當做其他聲明的註釋
// +build !linux
package mypkg // correct
用go vet命令也可以檢測到這個缺少空行的錯誤,初期可以用這個命令來避免缺少空行的錯誤
% go vet mypkg
mypkg.go:1: +build comment appears too late in file
exit status 1
作爲參考,下面的例子將licence聲明,編譯標籤和包聲明放在一起,請大家注意分辨
% head headspin.go
// Copyright 2013 Way out enterprises. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build someos someotheros thirdos,!amd64
// Package headspin implements calculates numbers so large
// they will make your head spin.
package headspin
文件後綴
這個方法通過改變文件名的後綴來提供條件編譯,這種方案比編譯標籤要簡單,go/build可以在不讀取源文件的情況下就可以決定哪些文件不需要參與編譯。文件命名約定可以在go/build 包裏找到詳細的說明,簡單來說如果你的源文件包含後綴:_GOOS.go,那麼這個源文件只會在這個平臺下編譯,_GOARCH.go也是如此。這兩個後綴可以結合在一起使用,但是要注意順序:_GOOS_GOARCH.go, 不能反過來用:_GOARCH_GOOS.go.
例子如下:
mypkg_freebsd_arm.go // only builds on freebsd/arm systems
mypkg_plan9.go // only builds on plan9
編譯標籤和文件後綴的選擇
編譯標籤和文件後綴的功能上有重疊,例如一個文件名:mypkg_linux.go包含了// +build linux將會出現冗餘
通常情況下,如果源文件與平臺或者cpu架構完全匹配,那麼用文件後綴,例如:
mypkg_linux.go // only builds on linux systems
mypkg_windows_amd64.go // only builds on windows 64bit platforms
相反,如果滿足以下任何條件,那麼使用編譯標籤:
- 這個源文件可以在超過一個平臺或者超過一個cpu架構下可以使用
- 需要去除指定平臺
- 有一些自定義的編譯條件