Go Build


原文链接: Go Build

Golang在Mac、Linux、Windows下如何交叉编译 - LauCyun's Blog

起先我是直接在go文件里指定LDFLAG:

//#cgo LDFLAGS: -static
编译的时候出现了如下错误:

cannot load imported symbols from ELF file $WORK/_/home/goplayground/_obj/cgo.o: no symbol section
我还真是第一次碰到没有符号表的ELF。

google groups给予了详细解答

静态标志需要在编译go文件时由命令行参数指定:

go build -ldflags -extldflags=-static

海思跨平台编译

CGO_ENABLED=1 GOOS=linux GOARCH=arm GOARM=7 CC=arm-himix200-linux-gcc CXX=arm-himix200-linux-g++ AR=arm-himix200-linux-ar go build

AR_ARM=/usr/bin/arm-himix200-linux-ar
CC_ARM=/usr/bin/arm-himix200-linux-gcc
CPP_ARM=/usr/bin/arm-himix200-linux-g++


.PHONY: all
all: 
    CGO_ENABLED=1 GOARCH=arm CC=$(CC_ARM) CXX=$(CPP_ARM) $(GO) test -c -o bn256.test.arm

### 直接在windows下编译arm会报错
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 go build
// +build !windows
方式1: env CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 go build
方式2: 需要采用如下方式编译就可以了

:: Linux arm
SET CGO_ENABLED=0
SET GOOS=linux
SET GOARCH=arm
go build

跨平台编译

set GOOS=windows
set GOARCH=386
set CGO_ENABLED=1

set CC=gcc.exe
set CXX=g++.exe
set PKG_CONFIG_LIBDIR=%INSTROOT%\lib\pkgconfig
set PATH=%CROSS_SAVE_PATH%;%INSTROOT%\bin

set CC_FOR_TARGET=gcc.exe
set CXX_FOR_TARGET=g++.exe
set PKG_CONFIG_LIBDIR_FOR_TARGET=%INSTROOT_FOR_TARGET%\lib\pkgconfig
set PATH_FOR_TARGET=%CROSS_SAVE_PATH%;%INSTROOT_FOR_TARGET%\bin

go 1.11.x

go build 默认将忽略 vendor 目录,如果想继续使用vendor 执行go build -mod vendor

go build ignore vendor directory by default, If you want to build dependencies from the vendor directory, you’ll need to ask for it. go build -mod vendor

golang “undefined” function declared in another file?

go run *.go 代替 go run main.go
或者
go run main.go employee.go

go run: cannot run *_test.go files

go build && ./<executable>
go run !(*_test).go

关闭编译器代

建议使用 -gcflags "-N -l" 参数关闭编译器代码优化和函数
内联,避免断点和单步执行无法准确对应源码行,避免小函数和局部变量被优化掉。
go build -gcflags "-N -l" -o test test.go

完全静态编译一个Go程序

在Docker化的今天, 我们经常需要静态编译一个Go程序,以便方便放在Docker容器中。 即使你没有引用其它的第三方包,只是在程序中使用了标准库net,你也会发现你编译后的程序依赖glic,这时候你需要glibc-static库,并且静态连接。

不同的Go版本下静态编译方式还有点不同,在go 1.10下, 下面的方式会尽可能做到静态编译:

CGO_ENABLED=0 go build -a -ldflags '-extldflags "-static"' .

go help build

构建编译由导入路径命名的包,以及它们的依赖关系,但它不会安装结果.
使用

go build [-o 输出名] [-i] [编译标记] [包名]

如果参数为***.go文件或文件列表,则编译为一个个单独的包。
当编译单个main包(文件),则生成可执行文件。
当编译单个或多个包非主包时,只构建编译包,但丢弃生成的对象(.a),仅用作检查包可以构建。
当编译包时,会自动忽略'_test.go'的测试文件。
参数
-o output 指定编译输出的名称,代替默认的包名。

-i install 安装作为目标的依赖关系的包(用于增量编译提速)。

以下 build 参数可用在 build, clean, get, install, list, run, test

-a 完全编译,不理会-i产生的.a文件(文件会比不带-a的编译出来要大?)
-n 仅打印输出build需要的命令,不执行build动作(少用)。
-p n 开多少核cpu来并行编译,默认为本机CPU核数(少用)。
-race 同时检测数据竞争状态,只支持 linux/amd64, freebsd/amd64, darwin/amd64 和 windows/amd64.
-msan 启用与内存消毒器的互操作。仅支持linux / amd64,并且只用Clang / LLVM作为主机C编译器(少用)。
-v 打印出被编译的包名(少用).
-work 打印临时工作目录的名称,并在退出时不删除它(少用)。
-x 同时打印输出执行的命令名(-n)(少用).
-asmflags 'flag list'

传递每个go工具asm调用的参数(少用)

-buildmode mode

编译模式(少用)
'go help buildmode'

-compiler name

使用的编译器 == runtime.Compiler
(gccgo or gc)(少用).

-gccgoflags 'arg list'

gccgo 编译/链接器参数(少用)

-gcflags 'arg list'

垃圾回收参数(少用).

-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 'flag list'

'-s -w': 压缩编译后的体积
-s: 去掉符号表
-w: 去掉调试信息,不能gdb调试了

-linkshared

链接到以前使用创建的共享库
-buildmode=shared.

-pkgdir dir

从指定位置,而不是通常的位置安装和加载所有软件包。例如,当使用非标准配置构建时,使用-pkgdir将生成的包保留在单独的位置。

-tags 'tag list'

构建出带tag的版本.

-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>'.

以上命令,单引号/双引号均可。

对包的操作'go help packages'
对路径的描述'go help gopath'
对 C/C++ 的互操作'go help c'

注意

构建遵守某些约定('go help gopath'),但不是所有的项目都遵循这些约定,当使用自己的惯例或使用单独的软件构建系统时可以选择使用较低级别的调用go tool compile和go tool link来避免一些构建工具的开销和设计决策

你是刚开始使用Go工具么?或者你想扩展知识?这篇文章将会描述每个人都需要知道的Go工具参数。

$ go build -x

-x 会列出来go build调用到的所有命令。

如果你对Go的工具链好奇,或者使用了一个跨C编译器,并且想知道调用外部编译器用到的具体参数,或者怀疑链接器有bug;使用-x来查看所有调用。

$ go build -x
WORK=/var/folders/00/1b8h8000h01000cxqpysvccm005d21/T/go-build600909754
mkdir -p $WORK/hello/perf/_obj/
mkdir -p $WORK/hello/perf/_obj/exe/
cd /Users/jbd/src/hello/perf
/Users/jbd/go/pkg/tool/darwin_amd64/compile -o $WORK/hello/perf.a -trimpath $WORK -p main -complete -buildid bbf8e880e7dd4114f42a7f57717f9ea5cc1dd18d -D _/Users/jbd/src/hello/perf -I $WORK -pack ./perf.go
cd .
/Users/jbd/go/pkg/tool/darwin_amd64/link -o $WORK/hello/perf/_obj/exe/a.out -L $WORK -extld=clang -buildmode=exe -buildid=bbf8e880e7dd4114f42a7f57717f9ea5cc1dd18d $WORK/hello/perf.a
mv $WORK/hello/perf/_obj/exe/a.out perf

$ go build -gcflags

这个参数将会传递给编译器。go tool compile -help列出来了所有我们可以传递给编译器的参数。

禁用编译器优化和内联优化,你可以使用下面的参数:

$ go build -gcflags="-N -I"

$ go test -v

这个命令可以为测试提供完整的输出。它会打印测试名称、状态(成功或者失败)、测试所耗费的时间,还有测试的日志等等。

如果不使用-v参数来测试,输出很少很多,我经常使用-v参数来打开详细测试日志。例子:

$ go test -v context

$ go test -race

现在可以使用Go工具提供的-race参数进行竞争检测。它会检测并报告竞争。开发的过程中用这个命令来检测一下。

注:完整的命令是:

$ go test -race mypkg // to test the package
$ go run -race mysrc.go // to run the source file
$ go build -race mycmd // to build the command

$ go test -run

你可以在测试的时候通过-run参数来正则匹配过滤需要测试的代码。下面的命令只会运行test examples。

$ go test -run=Example

$ go test -coverprofile

当测试一个包的时候,可以输出一个测试覆盖率,然后使用命令go tool来在浏览器里面可视化。

$ go test -coverprofile=c.out && go tool cover -html=c.out

上面的命令将会创建一个测试覆盖率文件在浏览器打开结果。可视化的结果看起来是下面的结果:

IMG-THUMBNAIL

注:测试fmt包

go test -coverprofile=c.out fmt

$ go test -exec

一般很少有人知道Go的这个功能,你可以通过-exec插入另一个程序。这个参数允许通过Go工具完成一些外部工作。

一个常见的需求场景是你需要在一些宿主机上面执行一些测试。我们可以通过-exec命令调用adb命令来把二进制文件导入安卓设备并且可以收集到结果信息。参考这个来在安卓设备上面执行。
$ go get -u

如果你通过go get命令获取Go包,而这个包已经存在于本地的GOPATH,那么这个命令并不会帮你更新包。-u可以强制更新到最新版。

如果你是一个库作者,你最好在你的安装说明上加上-u参数,例如,golint是这么做的:

$ go get -u github.com/golang/lint/golint

$ go get -d

如果你想clone一个代码仓库到GOPATH里面,跳过编译和安装环节,使用-d参数。这样它只会下载包并且在编译和安装之前停止。

当需要clone虚拟网址代码仓库的时候,我经常使用这个命令来代替git clone,因为这样可以把Go代码自动放入合适的目录下面。例如:

$ go get -d golang.org/x/oauth2/...

这样可以克隆到$GOPATH/src/golang.org/x/ouath2目录下面。假设golang.org/x/oauth2是一个虚拟网址,通过go get获取这个代码仓库要比找出仓库的真实地址(go.googlesource.com/oauth2)更简单。
$ go get -t

如果你的测试包的有附加的依赖包,-t可以一并下载测试包的依赖包。如果没有加这个参数,go get只会下载非测试包的依赖包。
$ go list -f

这个命令可以列出来Go的所有包,并且可以指定格式。这个写脚本的时候很有用。

下面这个命令将会打印所有依赖的runtime包

go list -f ‘’ runtime [runtime/internal/atomic runtime/internal/sys unsafe]

`