Golang 支持交叉编译,即在一个平台编译,在另一个平台运行,本文介绍Golang Pkg 编译相关。
使用
go build
在其他目录执行需要指定包名,在main下不需要
go build -a -x [pkgname|...]
其中:
go build ./...
编译当前目录下所有的源文件,如果启用Go Modules,执行 go build
会把依赖写入 go.mod
中
参数说明
- GOOS: 目标平台
- mac : darwin
- linux : linux
- windows : windows
- GOARCH :目标平台的体系架构
- 386 也称 x86 : 32位操作系统
- amd64 也称 x64 : 64位操作系统,比如电脑一般都是amd64架构的
- arm 一般用于嵌入式开发,比如Android,IOS,Win mobile等
- 交叉编译不支持
CGO_ENABLED
,使用CGO_ENABLED=0
设置。
编译命令
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build
# 若是在windows编译,也可以采用如下命令设置变量:
SET CGO_ENABLED=0
SET GOOS=darwin
SET GOARCH=amd64
go build
go build tag
使用 go bulid -tag
用来自定义构建配置不同的版本,参考
// +build dev
package main
var version = "DEV"
// +build release
package main
var version = "RELEASE"
package main
import "fmt"
func main() {
fmt.Printf("running %s version", version)
}
go build -tags dev -o main-dev
go build -tags release -o main-release
传参编译
package main
import "fmt"
var version string
func main() {
fmt.Printf("running %s version", version)
}
go build -ldflags '-X main.version="dev"' -o main-dev
查看编译包的信息
go version [-m] [-v] [file ...]
go version -m -v gseo-darwin
gseo-darwin: go1.17.6
path github.com/xiexianbin/gseo
mod github.com/xiexianbin/gseo (devel)
dep cloud.google.com/go
...
build -buildmode=exe
build -compiler=gc
build DefaultGODEBUG=panicnil=1
build CGO_ENABLED=0
build GOARCH=amd64
build GOOS=darwin
build GOAMD64=v1
build vcs=git
build vcs.revision=86e93f43b6184ed07028c739a76c0d4b7a748b97
build vcs.time=2022-06-04T14:13:34Z
build vcs.modified=false
查看汇编代码
go tool compile -S main.go
插件
golang 在运行时实现动态的加载外部库
go build -buildmode=plugin
go tool compile -S main.go
go 指令
go:build
end2end test 可以通过如下控制,可以使用 go test -tags e2e
运行比较费时的测试,而不加时不允许该测试
//go:build e2e
// +build e2e
//go:build amd64 !wasm
//go:build linux && amd64
go:embed
go1.16 支持使用 //go:embed
支持将静态资源文件嵌入到golang中,支持的类型:
- 单文件读取:
go:embed hello1.txt
- 多文件读取:
go:embed hello1.txt hello2.txt
- 目录读取:
go:embed somedir
- 贪婪匹配:
go:embed somedir/*
package main
import (
"embed"
"fmt"
// _ "embed"
)
//go:embed hello1.txt
var str1 string
//go:embed hello1.txt
var b []byte
//go:embed hello1.txt
var f1 embed.FS
//go:embed hello1.txt hello2.txt
var f2 embed.FS
//go:embed hello1.txt
//go:embed hello2.txt
var f3 embed.FS
//go:embed somedir
var f4 embed.FS
// //go:embed somedir/*
// var f5 embed.FS
func main() {
print(str1)
print(string(b))
data, _ := f1.ReadFile("hello1.txt")
print(string(data))
data1, _ := f2.ReadFile("hello1.txt")
print(string(data1))
data2, _ := f2.ReadFile("hello2.txt")
fmt.Print(string(data2))
data3, _ := f3.ReadFile("hello1.txt")
print(string(data3))
data41, _ := f4.ReadFile("somedir/hello1.txt")
fmt.Print(string(data41))
data42, _ := f4.ReadFile("somedir/hello2.txt")
fmt.Print(string(data42))
}
go:generate
$ mkdir test && cd test
$ mkdir painkiller
$ cat painkiller/pill.go
package painkiller
//go:generate stringer -type=Pill
type Pill int
const (
Placebo Pill = iota
Aspirin
Ibuprofen
Paracetamol
Acetaminophen = Paracetamol
)
$ cat main.go
package main
import (
"fmt"
"test/painkiller"
)
func main() {
fmt.Println(painkiller.Aspirin)
}
$ go mod init test
$ go get golang.org/x/tools/cmd/stringer
$ go install golang.org/x/tools/cmd/stringer
# 生成 pill_string.go
$ go generate ./...
# 项目结构
$ test tree .
.
├── go.mod
├── go.sum
├── main.go
└── painkiller
├── pill.go
└── pill_string.go
2 directories, 5 files
# 运行 main.go
$ go run ./main.go
Aspirin
# 生成的文件
$ cat painkiller/pill_string.go
// Code generated by "stringer -type=Pill"; DO NOT EDIT.
package painkiller
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[Placebo-0]
_ = x[Aspirin-1]
_ = x[Ibuprofen-2]
_ = x[Paracetamol-3]
}
const _Pill_name = "PlaceboAspirinIbuprofenParacetamol"
var _Pill_index = [...]uint8{0, 7, 14, 23, 34}
func (i Pill) String() string {
if i < 0 || i >= Pill(len(_Pill_index)-1) {
return "Pill(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _Pill_name[_Pill_index[i]:_Pill_index[i+1]]
}
//go:generate stringer -type=Pill -linecomment -output pill_comment.go
type Pill int
const (
Placebo Pill = iota // 安慰剂
Aspirin // 阿司匹林
Ibuprofen // Ibuprofen
Paracetamol // Paracetamol
Acetaminophen = Paracetamol // Acetaminophen
)
go:linkname
//go:linkname time_now time.now
func time_now() (sec int64, nsec int32, mono int64) {
go:noescape
禁止变量逃逸
//go:noescape
func memmove(to, from unsafe.Pointer, n uintptr)
go:nosplit
声明函数不得包含堆栈溢出检查
//go:nosplit
func key32(p *uintptr) *uint32 {
go:noinline
声明函数禁止进行内联优化,配合 go tool compile -S main.go
可以查看编译指令
//go:noinline
func unexportedPanicForTesting(b []byte, i int) byte {
go:norace
声明函数禁止进行竞态检测
go:notinheap
声明函数不允许从 GC 堆上进行申请内存
line
用于指定源代码中的行号和文件名,通常用于生成代码或者调试时,帮助开发者快速定位问题
//line filename:line