Go Pkg 编译介绍

发布时间: 更新时间: 总字数:1270 阅读时间:3m 作者: IP上海 分享 网址

Golang 支持交叉编译,即在一个平台编译,在另一个平台运行,本文介绍Golang Pkg 编译相关。

使用

go build 在其他目录执行需要指定包名,在main下不需要

go build -a -x [pkgname|...]

其中:

  • -a 全部重新编译
  • -x 显示编译过程

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设置。

编译命令

  • 编译在Linux运行的包
CGO_ENABLED=0  GOOS=linux  GOARCH=amd64  go  build
  • 编译在Mac运行的包
CGO_ENABLED=0  GOOS=darwin  GOARCH=amd64  go  build
  • 编译在Windows运行的包
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 用来自定义构建配置不同的版本,参考

指定tags编译

  • dev_info.go
// +build dev

package main

var version = "DEV"
  • release_info.go
// +build release

package main

var version = "RELEASE"
  • main.go
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

传参编译

  • main.go
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

查看编译包的信息

  • 包括依赖和git信息等
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

go tool compile -S main.go

go 指令

go:build

  • 编译时约束
  • go e2e

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

  • runtime/timestub.go
//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
Home Archives Categories Tags Statistics
本文总阅读量 次 本站总访问量 次 本站总访客数