Go 中的工具链

1、编译

编译并不仅仅是执行“go build” 命令,还有一些须额外注意的内容。
如习惯使用 GDB 这类调试器,建议编译时添加 -gcflags “-N -l” 参数阻止优化和内联,否则调试时会有各种“找不到”的情况。

package main

func test(x *int)  {
	println(*x)
}

func main()  {
	x := 0x100
	test(&x)
}

go build -gcflags “-N -l -m”
输出:
./dataTest.go:3:11: test x does not escape
./dataTest.go:9:7: main &x does not escape
而当发布时,参数 -ldflags “-w -s” 会让链接器剔除符号表和调试信息,除能减少可执行文件大小外,还可稍微增加反汇编的难度。
go build -gcflags “-m” -ldflags “-w -s”
输出:
./dataTest.go:3:6: can inline test
./dataTest.go:7:6: can inline main
./dataTest.go:9:6: inlining call to test
./dataTest.go:3:11: test x does not escape
./dataTest.go:9:7: main &x does not escape

交叉编译
所谓交叉编译,是指在一个平台下编译出其他平台所需的可执行文件。这对于 UNIX-like 开发人员很重要,因为我们习惯使用 Mac 或 其他桌面环境。
自从 Go 实现自举后,交叉编译变得很重要。只续使用 GOOS、GOPATH 环境变量指定目标平台和架构就行。
go env GOOS
输出:
darwin

go build && file dataTest
输出: dataTest: Mach-O 64-bit executable x86_64
GOOS=linux go build && file dataTest
输出:ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped
GOOS=windows GOARCH=386 go build && file dataTest.exe
输出:PE32 executable (console) Intel 80386 (stripped to external PDB), for MS Windows

建议用 go install 命令为目标平台预编译后标准库,避免 go build 每次都须完整编译。
GOOS=linux go install std
GOOS=linux go install cmd
注意: 交叉编译不支持 CGO.

条件编译
除在代码中用 runtime.GOOS 进行判断外,编译器本身就支持文件级别的条件编译。
方法1:将平台和架构信息添加到主文件名尾部。

main.go

package main

func main()  {
	hello()
}

hello_darwin.go

package main

func hello()  {
	println("hello mac.")
}

hello_linux.go

package main

func hello()  {
	println("hello linux.")
}

GOOS=darwin go build -x
./main
输出: hello mac.

GOOS=linux go build -x
./main
输出: hello linux.

方法2:使用 build 编译指令。
与用文件名区分多版本类似,build 编译指令告知编译器:当前源码文件只能用于指定环境。它一样可用来区分多版本,切控制指令更加丰富和灵活。

a.go

// +build windows             <------- 其后面必须有空格

package main

func hello()  {
	println("hello windows.")
}

b.go

// +build linux darwin

package main

func hello()  {
	println("hello, unix.")
}

可添加多条build指令,表示多个 AND 条件。在单一指令里,空格表示OR条件,逗号表示AND,感叹号表示 NOT。

// +build linux darwin
// +build 386,!cgo

其相当于:
(linux OR darwin) AND (386 AND (NOT cgo))

除 GOOS、GOARCH 外,可用条件还有编译器、版本号等。

// +build ignore
// +build gccgo
// +build go1.5

方法3:使用自定义 tag 指令。
除预定义build 指令外,也可通过命令行 tags 参数传递自定义指令。
main.go

package main

func main()  {
	hello()
}

debug.go

// +build !release

package main

func hello()  {
	println("debug version.")
}

release.go

// +build release

package main

func hello()  {
	println("release version.")
}

log.go

// +build log

package main

func init()  {
	println("logging ...")
}

go build && ./main
输出: debug version.

go build -tags “release log” && ./main
输出:
logging …
release version.

预处理
简单点说,就是用 go generate 命令扫描源码文件,找出所有“go:generate”注释,提取其中的命令并执行。

  • 命令必须放在 .go 源文件中。
  • 命令必须以 “//go:generate” 开头(双斜线后不能有空格)。
  • 每个文件可有多条generate 命令。
  • 命令支持环境变量。
  • 必须显式执行 go generate 命令。
  • 按文件名顺序提取命令并执行。
  • 串行执行,出错后终止后续命令的执行。
    a.go
//go:generate echo $GOPATH
//go:generate ls -lh

package main

func hello()  {
	println("hello world")
}

b.go

//go:generate uname -a

package main

func init()  {
	
}

go generate -n
输出:
echo /Users/www/go
ls -lh
uname -a

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值