Go 支持按照條件編譯,具體來說它是通過 go/build包 里定義的tags和命名約定來讓Go的包可以管理不同平台的代碼 。
我們這里以下面這個開源項目為例,來看Go的按條件編譯, 這個開源項目是把Go的os包進行了擴展。
https://bitbucket.org/kardianos/osext/src
osext 是獲得當前執行程序的執行目錄和文件信息。
執行情況如下:
查看編譯文件
我們用go list來查看在當前平台下 os/exec包里有哪些文件將會被編譯
看當前項目下,有哪些文件會被編譯,命令如下:
這里的 {{.GoFiles}} 是text/template里的模板代碼
go list 命令的信息如下:
查看包名、路徑、依賴項等等信息。
參數:
-json: 使用 json 格式輸出包的相關信息,包括下面的依賴和導⼊。
-f{{.Deps}}: 查看依賴包,包括直接或間接依賴。
-f{{.Imports}}: 查看導入的包。
D:\mycodes\golang\src\bitbucket.org\kardianos\osext>go list -f
flag needs an argument: -f
usage: list [-e] [-f format] [-json] [build flags] [packages]
List lists the packages named by the import paths, one per line.
The default output shows the package import path:
code.google.com/p/google-api-go-client/books/v1
code.google.com/p/goauth2/oauth
code.google.com/p/sqlite
The -f flag specifies an alternate format for the list, using the
syntax of package template. The default output is equivalent to -f
'{{.ImportPath}}'. The struct being passed to the template is:
type Package struct {
Dir string // directory containing package sources
ImportPath string // import path of package in dir
ImportComment string // path in import comment on package statement
Name string // package name
Doc string // package documentation string
Target string // install path
Goroot bool // is this package in the Go root?
Standard bool // is this package part of the standard Go library?
Stale bool // would 'go install' do anything for this package?
Root string // Go root or Go path dir containing this package
// Source files
GoFiles []string // .go source files (excluding CgoFiles, TestGoF
iles, XTestGoFiles)
CgoFiles []string // .go sources files that import "C"
IgnoredGoFiles []string // .go sources ignored due to build constraints
CFiles []string // .c source files
CXXFiles []string // .cc, .cxx and .cpp source files
MFiles []string // .m source files
HFiles []string // .h, .hh, .hpp and .hxx source files
SFiles []string // .s source files
SwigFiles []string // .swig files
SwigCXXFiles []string // .swigcxx files
SysoFiles []string // .syso object files to add to archive
// Cgo directives
CgoCFLAGS []string // cgo: flags for C compiler
CgoCPPFLAGS []string // cgo: flags for C preprocessor
CgoCXXFLAGS []string // cgo: flags for C++ compiler
CgoLDFLAGS []string // cgo: flags for linker
CgoPkgConfig []string // cgo: pkg-config names
// Dependency information
Imports []string // import paths used by this package
Deps []string // all (recursively) imported dependencies
// Error information
Incomplete bool // this package or a dependency has an error
Error *PackageError // error loading package
DepsErrors []*PackageError // errors loading dependencies
TestGoFiles []string // _test.go files in package
TestImports []string // imports from TestGoFiles
XTestGoFiles []string // _test.go files outside package
XTestImports []string // imports from XTestGoFiles
}
The template function "join" calls strings.Join.
The template function "context" returns the build context, defined as:
type Context struct {
GOARCH string // target architecture
GOOS string // target operating system
GOROOT string // Go root
GOPATH string // Go path
CgoEnabled bool // whether cgo can be used
UseAllFiles bool // use files regardless of +build lines,
file names
Compiler string // compiler to assume when computing targ
et paths
BuildTags []string // build constraints to match in +build l
ines
ReleaseTags []string // releases the current release is compat
ible with
InstallSuffix string // suffix to use in the name of the insta
ll dir
}
For more information about the meaning of these fields see the documentation
for the go/build package's Context type.
The -json flag causes the package data to be printed in JSON format
instead of using the template format.
The -e flag changes the handling of erroneous packages, those that
cannot be found or are malformed. By default, the list command
prints an error to standard error for each erroneous package and
omits the packages from consideration during the usual printing.
With the -e flag, the list command never prints errors to standard
error and instead processes the erroneous packages with the usual
printing. Erroneous packages will have a non-empty ImportPath and
a non-nil Error field; other information may or may not be missing
(zeroed).
For more about build flags, see 'go help build'.
For more about specifying packages, see 'go help packages'.
編譯標簽
在源代碼里添加標注,通常稱之為編譯標簽( 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
- 編譯標簽由空格分隔的編譯選項(options)以"或"的邏輯關系組成
- 每個編譯選項由逗號分隔的條件項以邏輯"與"的關系組成
- 每個條件項的名字用字母+數字表示,在前面加!表示否定的意思
比如 https://bitbucket.org/kardianos/osext/src 這里的 osext_procfs.go 文件頭上的 +build 部分就是。
這里標示 linux netbsd openbsd solaris 這些操作系統下會編譯這個文件。
更復雜的編譯標簽 可以參考: http://blog.csdn.net/varding/article/details/12675971
文件后綴
這個方法通過改變文件名的后綴來提供條件編譯,這種方案比編譯標簽要簡單,go/build可以在不讀取源文件的情況下就可以決定哪些文件不需要參與編譯
文件命名約定可以在go/build 包里找到詳細的說明,簡單來說如果你的源文件包含后綴:_$GOOS.go,那么這個源文件只會在這個平台下編譯,_$GOARCH.go也是如此。這兩個后綴可以結合在一起使用,但是要注意順序:_$GOOS_$GOARCH.go, 不能反過來用:_$GOARCH_$GOOS.go
比如 https://bitbucket.org/kardianos/osext/src 這里的文件就是這個規則
osext_plan9.go 只會在 plan9 中編譯。
osext_windows.go 只會在windows下編譯。
更多請參考: http://blog.csdn.net/varding/article/details/12675971
參考資料:
使用go build 進行條件編譯
http://blog.csdn.net/varding/article/details/12675971