小結:
go build -ldflags "-H windowsgui -X main.TaskType=PING -X main.BuildVersion=v1" -o App.exe;
例:編譯的時候,帶上編譯的人的姓名
go build -ldflags "-X main.Developer=zhangsan"
1
main.go
package main
import "fmt"
var Developer string
func main() {
fmt.Println("Developer:", Developer)
}
C:\>go help build
usage: go build [-o output] [build flags] [packages]
Build compiles the packages named by the import paths,
along with their dependencies, but it does not install the results.
If the arguments to build are a list of .go files from a single directory,
build treats them as a list of source files specifying a single package.
When compiling packages, build ignores files that end in '_test.go'.
When compiling a single main package, build writes
the resulting executable to an output file named after
the first source file ('go build ed.go rx.go' writes 'ed' or 'ed.exe')
or the source code directory ('go build unix/sam' writes 'sam' or 'sam.exe').
The '.exe' suffix is added when writing a Windows executable.
When compiling multiple packages or a single non-main package,
build compiles the packages but discards the resulting object,
serving only as a check that the packages can be built.
The -o flag forces build to write the resulting executable or object
to the named output file or directory, instead of the default behavior described
in the last two paragraphs. If the named output is an existing directory or
ends with a slash or backslash, then any resulting executables
will be written to that directory.
The -i flag installs the packages that are dependencies of the target.
The -i flag is deprecated. Compiled packages are cached automatically.
The build flags are shared by the build, clean, get, install, list, run,
and test commands:
-a
force rebuilding of packages that are already up-to-date.
-n
print the commands but do not run them.
-p n
the number of programs, such as build commands or
test binaries, that can be run in parallel.
The default is the number of CPUs available.
-race
enable data race detection.
Supported only on linux/amd64, freebsd/amd64, darwin/amd64, windows/amd64,
linux/ppc64le and linux/arm64 (only for 48-bit VMA).
-msan
enable interoperation with memory sanitizer.
Supported only on linux/amd64, linux/arm64
and only with Clang/LLVM as the host C compiler.
On linux/arm64, pie build mode will be used.
-v
print the names of packages as they are compiled.
-work
print the name of the temporary work directory and
do not delete it when exiting.
-x
print the commands.
-asmflags '[pattern=]arg list'
arguments to pass on each go tool asm invocation.
-buildmode mode
build mode to use. See 'go help buildmode' for more.
-compiler name
name of compiler to use, as in runtime.Compiler (gccgo or gc).
-gccgoflags '[pattern=]arg list'
arguments to pass on each gccgo compiler/linker invocation.
-gcflags '[pattern=]arg list'
arguments to pass on each go tool compile invocation.
-installsuffix suffix
a suffix to use in the name of the package installation directory,
in order to keep output separate from default builds.
If using the -race flag, the install suffix is automatically set to race
or, if set explicitly, has _race appended to it. Likewise for the -msan
flag. Using a -buildmode option that requires non-default compile flags
has a similar effect.
-ldflags '[pattern=]arg list'
arguments to pass on each go tool link invocation.
-linkshared
build code that will be linked against shared libraries previously
created with -buildmode=shared.
-mod mode
module download mode to use: readonly, vendor, or mod.
By default, if a vendor directory is present and the go version in go.mod
is 1.14 or higher, the go command acts as if -mod=vendor were set.
Otherwise, the go command acts as if -mod=readonly were set.
See https://golang.org/ref/mod#build-commands for details.
-modcacherw
leave newly-created directories in the module cache read-write
instead of making them read-only.
-modfile file
in module aware mode, read (and possibly write) an alternate go.mod
file instead of the one in the module root directory. A file named
"go.mod" must still be present in order to determine the module root
directory, but it is not accessed. When -modfile is specified, an
alternate go.sum file is also used: its path is derived from the
-modfile flag by trimming the ".mod" extension and appending ".sum".
-overlay file
read a JSON config file that provides an overlay for build operations.
The file is a JSON struct with a single field, named 'Replace', that
maps each disk file path (a string) to its backing file path, so that
a build will run as if the disk file path exists with the contents
given by the backing file paths, or as if the disk file path does not
exist if its backing file path is empty. Support for the -overlay flag
has some limitations:importantly, cgo files included from outside the
include path must be in the same directory as the Go package they are
included from, and overlays will not appear when binaries and tests are
run through go run and go test respectively.
-pkgdir dir
install and load all packages from dir instead of the usual locations.
For example, when building with a non-standard configuration,
use -pkgdir to keep generated packages in a separate location.
-tags tag,list
a comma-separated list of build tags to consider satisfied during the
build. For more information about build tags, see the description of
build constraints in the documentation for the go/build package.
(Earlier versions of Go used a space-separated list, and that form
is deprecated but still recognized.)
-trimpath
remove all file system paths from the resulting executable.
Instead of absolute file system paths, the recorded file names
will begin with either "go" (for the standard library),
or a module path@version (when using modules),
or a plain import path (when using GOPATH).
-toolexec 'cmd args'
a program to use to invoke toolchain programs like vet and asm.
For example, instead of running asm, the go command will run
'cmd args /path/to/asm <arguments for asm>'.
The -asmflags, -gccgoflags, -gcflags, and -ldflags flags accept a
space-separated list of arguments to pass to an underlying tool
during the build. To embed spaces in an element in the list, surround
it with either single or double quotes. The argument list may be
preceded by a package pattern and an equal sign, which restricts
the use of that argument list to the building of packages matching
that pattern (see 'go help packages' for a description of package
patterns). Without a pattern, the argument list applies only to the
packages named on the command line. The flags may be repeated
with different patterns in order to specify different arguments for
different sets of packages. If a package matches patterns given in
multiple flags, the latest match on the command line wins.
For example, 'go build -gcflags=-S fmt' prints the disassembly
only for package fmt, while 'go build -gcflags=all=-S fmt'
prints the disassembly for fmt and all its dependencies.
For more about specifying packages, see 'go help packages'.
For more about where packages and binaries are installed,
run 'go help gopath'.
For more about calling between Go and C/C++, run 'go help c'.
Note: Build adheres to certain conventions such as those described
by 'go help gopath'. Not all projects can follow these conventions,
however. Installations that have their own conventions or that use
a separate software build system may choose to use lower-level
invocations such as 'go tool compile' and 'go tool link' to avoid
some of the overheads and design decisions of the build tool.
See also: go install, go get, go clean.
C:\>go version
go version go1.16.7 windows/amd64
go build 可以用-gcflags給go編譯器傳入參數,也就是傳給go tool compile的參數,因此可以用go tool compile --help查看所有可用的參數。
其中-m可以檢查代碼的編譯優化情況,包括逃逸情況和函數是否內聯。
如果只在編譯特定包時需要傳遞參數,格式應遵守“包名=參數列表”,如go build -gcflags -gcflags='log=-N -l' main.go
go build用-ldflags給go鏈接器傳入參數,實際是給go tool link的參數,可以用go tool link --help查看可用的參數。
常用-X來指定版本號等編譯時才決定的參數值。例如代碼中定義var buildVer string,然后在編譯時用go build -ldflags "-X main.buildVer=1.0" ... 來賦值。注意-X只能給string類型變量賦值。
go build 參數匯總_DisMisPres的博客-CSDN博客 https://blog.csdn.net/DisMisPres/article/details/115110442
go 的編譯是以 package main 的 main() 函數作為主入口,生成可執行文件。若 build 的是非 main 包,則不會生成可執行文件,只檢查是否可執行編譯。
可以輸入 go help build 查看官方解釋。
go build 編譯包時,會忽略“_test.go”結尾的文件(即測試文件)。
參數 含義
-o output 指定編譯輸出的名稱,代替包名
-i install 安裝作為目標的依賴關系的包(用於增量編譯提速)
-a 強行對項目所有的代碼包(包含標准庫中的代碼包)進行重新構建,即使它們已經是最新的了
-n 打印編譯期間所用到的命令,僅僅是打印並不真正執行它們
-p n 指定編譯過程中執行各任務的並行數量(確切地說應該是並發數量)。在默認情況下,該數量等於CPU的邏輯核數。但是在darwin/arm平台(即iPhone和iPad所用的平台)下,該數量默認是1
-race 開啟競態條件的檢測。不過此標記目前僅在linux/amd64、freebsd/amd64、darwin/amd64和windows/amd64平台下受到支持
-msan 使用內存清除器啟用互操作。只支持Linux/AMD 64、Linux/ARM 64,並且只有clang/llvm作為主機c+編譯器
-v 打印出那些被編譯時的代碼包的名字
-x 打印編譯期間所用到的其它命令(且執行),注意它與-n標記的區別
-work 打印出編譯時生成的臨時工作目錄的路徑,並在編譯結束時保留它。在默認情況下,編譯結束時會刪除該目錄
以下為不常用命令
-asmflags 此標記可以后跟另外一些標記,如-D、-I、-S等。這些后跟的標記用於控制Go語言編譯器編譯匯編語言文件時的行為
-buildmode 此標記用於指定編譯模式,使用方式如-buildmode=default(這等同於默認情況下的設置)。此標記支持的編譯模式目前有6種。借此,我們可以控制編譯器在編譯完成后生成靜態鏈接庫(即.a文件,也就是我們之前說的歸檔文件)、動態鏈接庫(即.so文件)或/和可執行文件(在Windows下是.exe文件) go help buildmode
-compiler 此標記用於指定當前使用的編譯器的名稱。其值可以為gc或gccgo。其中,gc編譯器即為Go語言自帶的編輯器,而gccgo編譯器則為GCC提供的Go語言編譯器
-gccgoflags 此標記用於指定需要傳遞給gccgo編譯器或鏈接器的標記的列表
-gcflags 此標記用於指定需要傳遞給go tool compile命令的標記的列表
-installsuffix 為了使當前的輸出目錄與默認的編譯輸出目錄分離,可以使用這個標記。此標記的值會作為結果文件的父目錄名稱的后綴。其實,如果使用了-race標記,這個標記會被自動追加且其值會為race。如果我們同時使用了-race標記和-installsuffix,那么在-installsuffix標記的值的后面會再被追加_race,並以此來作為實際使用的后綴
-ldflags 此標記用於指定需要傳遞給go tool link命令的標記的列表
-linkshared 此標記用於與-buildmode=shared一同使用。后者會使作為編譯目標的非main代碼包都被合並到一個動態鏈接庫文件中,而前者則會在此之上進行鏈接操作
-pkgdir 指定一個目錄,並從改目錄下加載編譯好的.a 文件,並把編譯可能產生新的 .a 文件放入到該目錄中
-tags 此標記用於指定在實際編譯期間需要受理的編譯標簽(也可被稱為編譯約束)的列表
-toolexec 此標記可以讓我們去自定義在編譯期間使用一些Go語言自帶工具(如vet、asm等)的方式
-tags
例:編譯debug版本
go build -tags "debug"
1
注意:build.go 和 build_debug.go 的文件開頭的 // +build debug 注釋,這個就是你編譯時的 tags
main.go
package main
func main() {
tBuildTag()
}
build.go
// +build !debug
package main
import "fmt"
func tBuildTag() {
fmt.Println("no debug")
}
build_debug.go
// +build debug
package main
import "fmt"
func tBuildTag() {
fmt.Println("debug")
}
-ldflags ‘flag list’
'-s -w': 壓縮編譯后的體積
-s: 去掉符號表
-w: 去掉調試信息,不能gdb調試了
-X: 設置包中的變量值
例:編譯的時候,帶上編譯的人的姓名
go build -ldflags "-X main.Developer=zhangsan"
1
main.go
package main
import "fmt"
var Developer string
func main() {
fmt.Println("Developer:", Developer)
}
執行編譯好的程序,可以看到 Developer: zhangsan 輸出。
-race
go run -race 是不會進行競態檢測的。需要先 go build -race,然后再執行編譯好的文件。如下是一個競態示例輸出:
==================
WARNING: DATA RACE
Read at 0x00c0000c9ce0 by goroutine 8:
container/list.(*List).remove()
D:/Go/src/container/list/list.go:109 +0x119
container/list.(*List).Remove()
D:/Go/src/container/list/list.go:141 +0x27a
commonTest/list.tList1.func2()
F:/GoTest/GoTest/list/list.go:55 +0x10c
Previous write at 0x00c0000c9ce0 by goroutine 7:
container/list.(*List).insertValue()
D:/Go/src/container/list/list.go:104 +0x10c
container/list.(*List).PushBack()
D:/Go/src/container/list/list.go:155 +0xc6
commonTest/list.tList1.func1()
F:/GoTest/GoTest/list/list.go:27 +0x92
Goroutine 8 (running) created at:
commonTest/list.tList1()
F:/GoTest/GoTest/list/list.go:37 +0x1cb
commonTest/list.Test()
F:/GoTest/GoTest/list/entrance.go:4 +0x37
main.main()
F:/GoTest/GoTest/main.go:19 +0x32
Goroutine 7 (finished) created at:
commonTest/list.tList1()
F:/GoTest/GoTest/list/list.go:25 +0x17e
commonTest/list.Test()
F:/GoTest/GoTest/list/entrance.go:4 +0x37
main.main()
F:/GoTest/GoTest/main.go:19 +0x32
==================
google官方解釋
go build 命令介紹
go build命令詳解
“go build -X” 的妙用
golang項目中使用條件編譯 - yuchen16 - 博客園 https://www.cnblogs.com/ksir16/p/9050721.html
How to use conditional compilation with the go build tool – The acme of foolishness https://dave.cheney.net/2013/10/12/how-to-use-conditional-compilation-with-the-go-build-tool
golang項目中使用條件編譯
C語言中的條件編譯
golang中沒有類似C語言中條件編譯的寫法,比如在C代碼中可以使用如下語法做一些條件編譯,結合宏定義來使用可以實現諸如按需編譯release和debug版本代碼的需求
#ifndef #define ... #end
golang中的條件編譯
golang支持兩種條件編譯的實現方式
- build tags
- 文件后綴
1. 通過Build tags實現
build tags 是通過代碼注釋的形式實現的,要寫在文件的最頂端;
go build指令在編譯項目的時候會檢查每一個文件的build tags,用來決定是編譯還是跳過該文件
build tags遵循以下規則
- 不同tag域之間用空格區分,他們是OR關系
- 同一tag域之內不同的tag用都好區分,他們是AND關系
- 每一個tag都由字母和數字構成,!開頭表示條件“非”
示例:
// +build darwin freebsd netbsd openbsd
約束此文件只能在支持kqueue的BSD系統上編譯
一個文件可能包含多行條件編譯注釋,比如:
// +build linux darwin // +build 386
約束該文件在linux/386 或 darwin/386平台編譯
需要注意的點
tag注釋和包聲明必須用空行隔開,比如下面的寫法是錯誤的,編譯器會把第一行作為包說明來處理,而不是build tags
1 // +build !linux 2 package mypkg // wrong
正確的寫法如下:
1 // +build !linux 2 3 package mypkg // correct
編譯方法:
只需要在go build指令后用-tags指定編譯條件即可
go build -tags linux
2. 通過文件名后綴實現
具有_$GOOS.go
后綴的go文件在編譯的時候會根據當前平台來判斷是否將該文件導入並編譯;同樣適用於處理器架構判斷 _$GOARCH.go
。
兩者可以結合起來使用,形式為: _$GOOS_$GOARCH.go
示例:
mypkg_freebsd_arm.go // 只在 freebsd/arm 編譯 mypkg_plan9.go // 只在 plan9 編譯
文件名必須提供,如果只由后綴的文件名會被編譯器忽略,比如:
_linux.go _freebsd_386.go
這兩個文件會被編譯器忽略,因為以下划線開頭的文件都會被忽略
How to use conditional compilation with the go build tool
When developing Go packages that rely on specific features of the underlying platform or processor it is often necessary to provide a specialised implementation.
Go does not have a preprocessor, a macro system, or a #define
declaration to control the inclusion of platform specific code. Instead a system of tags and naming convention defined in the go/build
package and supported by the go
tool allows Go packages to customise themselves for the specific platform they are being compiled for.
This post explains how conditional compilation is implemented and show you how you can use it in your projects.
But first, go list
Before we can talk about conditional compilation, we need to learn a little bit about the go list
command. go list
gives you access to the internal data structures which power the build process.
go list
takes the most of the same arguments as go build
, test
, and install
but does not perform any compilation. Using the -f
, format flag we can supply a snippet of text/template
code which is executed in a context containing a go/build.Package
structure.
Using the format flag, we can ask go list
to tell us the names of the files that would be compiled.
% go list -f '{{.GoFiles}}' os/exec [exec.go lp_unix.go]
In the example above I asked for the list of files in os/exec
package that would be compiled on this linux/arm
system. The result is two files, exec.go
which contains the common code shared across all platforms, and lp_unix.go
while contains an implementation of exec.LookPath
for unix-like systems.
If I were to run the same command on a Windows system, the result would be
C:\go> go list -f '{{.GoFiles}}' os/exec [exec.go lp_windows.go]
This short example demonstrates the two parts of the Go conditional compilation system, known as Build Constraints, which we will now explore in more detail.
Build tags
The first method of conditional compilation is via an annotation in the source code, commonly known as a build tag.
Build tags are implemented as comments and should appear as close to the top of the file as possible.
When go build
is asked to build a package it will analyse each source file in the package looking for build tags. These tags control whether go build
will pass the file to the compiler.
A build tags follow these three rules
- 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
As an example, the build tag found at the top of a source file
// +build darwin freebsd netbsd openbsd
would constrain this file to only building on BSD systems that supported kqueue.
A file may have multiple build tags. The overall constraint is the logical AND of the individual constraints. For example
// +build linux darwin // +build 386
constrains the build to linux/386
or darwin/386
platforms only.
A note about comments
One thing that generally catches people out when they are first trying to make build tags work is this
// +build !linux package mypkg // wrong
In this example there is no newline separating the build tag and the package declaration. Because of this the build tag is associated with the package declaration as a comment describing the package and thus ignored.
// +build !linux package mypkg // correct
This is the correct form, a comment with a trailing newline stands alone and is not associated with any declaration and go vet
will detect the missing newline.
% go vet mypkg mypkg.go:1: +build comment appears too late in file exit status 1
When this feature was added to go vet
it detected several mistakes in the standard library and sub repos, so don’t feel bad if you get it wrong the first time.
For reference, here is a sample showing a licence preamble, a build tag, and a package declaration
% 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
File suffixes
The second option for providing conditional compilation is the name of the source file itself. This scheme is simpler than build tags, and allows the go/build
package to exclude files without having to process the file.
The naming convention is described in the documentation for the go/build
package. Simply put, if your source file includes the suffix, _$GOOS.go
then it will only be built on that platform. All other platforms will behave as if the file is not present. The same applies for _$GOARCH.go
. The two can be combined as _$GOOS_$GOARCH.go
, but not _$GOARCH_$GOOS.go
.
Some examples of file suffixes are,
mypkg_freebsd_arm.go // only builds on freebsd/arm systems mypkg_plan9.go // only builds on plan9
Your source files still require a name, a suffix is not sufficient, for example
_linux.go _freebsd_386.go
will be ignored, even on linux or freebsd systems, because the go/build
package ignores any file beginning with a period or an underscore.
Choosing between build tags and file suffixes
Build tags and file suffixes overlap in fuctionality. For example, a file called mypkg_linux.go
that contained the build tag // +build linux
is redundant.
In general, when choosing between a build tag or a file suffix, you should choose a file suffix when there is an exact match between the platform or architecture and the file you want to include. eg,
mypkg_linux.go // only builds on linux systems mypkg_windows_amd64.go // only builds on windows 64bit platforms
Conversely if your file is applicable to more than one platform or architecture, or you need to exclude a specific platform, a build tag should be used. eg,
% grep '+build' $HOME/go/src/pkg/os/exec/lp_unix.go // +build darwin dragonfly freebsd linux netbsd openbsd
builds on all unix like platforms.
% grep '+build' $HOME/go/src/pkg/os/types_notwin.go // +build !windows
builds on all platforms except Windows.
Wrapping up
While this post has focused only on Go source files, build tags and file suffixes can be used with any source file that the go
tool can build. This includes .c
and .s
files. The Go standard library, specifically the runtime
, syscall
, os
and net
packages contain great examples, I recommend studying them.
Test files also support build tags and file suffixes and behave in the same manner as Go source files, conditionally including test cases on a per platform basis. Again the standard library contains many great examples.
Finally, while the title of this article talks about the go
tool, the conditional compilation features are not limited to just that tool. You can build your own tools to consume and analyse Go code with the same file suffix and build tag semantics using the go/build
package.
Posted in Go, Photography by Dave Cheney · Tags: build constraints, build tags, go build