Go 自带了很多不同用途的子命令,这里关注和编译相关的子命令用法,其它子命令见 Golang 的子命令。
go build 串联了多个 go 内置工具完成编译链接过程,可以通过 go build 的参数控制编译链接过程:
# 查看 go build 支持的参数
go help build
其中 -asmflags 等参数的值被透传到 go build 使用的的对应工具:
-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.
go build 的 -compiler 参数用来指定编译器,go 支持两个编译器: gccgo 和 gc,默认使用 gc。
gccgo 是一个 gcc 的前端(将 go 文件翻译成 gcc 能处理的中间模式,然后由 gcc 后端编译成目标架构上二进制文件)。gccgo 作为 gcc 的一部分和 gcc 一起发布,需要通过安装 gcc 来安装,详细说明见 Go:Setting up and using gccgo。
对应的编译链接参数和 gcc 相同。
go tool compile 是 gc 的 go 代码编译器,通过 go build 的 -gcflogs 传入编译参数:
$ go tool compile
usage: compile [options] file.go...
-% int
debug non-static initializers
-+ compiling runtime
-B disable bounds checking
-C disable printing of columns in error messages
-D path
set relative path for local imports
-E debug symbol export
...省略...
go tool asm 是 gc 的汇编编译器,通过 go build 的 -asmflags 传入编译参数:
$ go tool asm
usage: asm [options] file.s ...
Flags:
-D value
predefined symbol with optional simple value -D=identifier=value; can be set multiple times
-I value
include directory; can be set multiple times
-S print assembly and machine code
-V print version and exit
-compiling-runtime
source to be compiled is part of the Go runtime
...省略...
go tool link 是 gc 的链接器,通过 go build 的 -ldflags 传入链接参数:
$ go tool link
usage: link [options] main.o
-B note
add an ELF NT_GNU_BUILD_ID note when using ELF
-E entry
set entry symbol name
-H type
set header type
-I linker
...省略...
go tool asm 将汇编代码编译成可以被链接器链接的 object(.o)文件,它是一个基于 plan9 的汇编编译器,相应地采用了 plan9 的汇编语法。
go tool asm 支持的汇编指令不完全等同于目标架构上的指令
,go tool asm 支持的是一个半抽象的指令集,和目标架构的指令集不完全相同。
A Manual for the Plan 9 assembler 介绍了 plan9 的汇编语法。
A Quick Guide to Go’s Assembler 介绍了 gc 汇编语法和 plan9 汇编语法的差异。
没找到将 .go 文件编译成 .s 汇编文件的方法
(隐约记得以前是可以的,现在貌似不支持了),可以到 go 的源码里查看不同架构的汇编文件写法:
cd $GOROOT/src/runtime/
➜ runtime ls *.s
asm.s memclr_plan9_386.s race_ppc64le.s rt0_openbsd_amd64.s sys_netbsd_arm64.s
asm_386.s memclr_plan9_amd64.s rt0_aix_ppc64.s rt0_openbsd_arm.s sys_openbsd_386.s
asm_amd64.s memclr_ppc64x.s rt0_android_386.s rt0_openbsd_arm64.s sys_openbsd_amd64.s
asm_arm.s memclr_riscv64.s rt0_android_amd64.s rt0_openbsd_mips64.s sys_openbsd_arm.s
asm_arm64.s memclr_s390x.s rt0_android_arm.s rt0_plan9_386.s sys_openbsd_arm64.s
...
go tool objdump 可以将编译后的 object 文件以及链接后的可执行文件反汇编,例如:
# 编译过程
main_empty.o main_fmt.o:
go tool compile main_empty.go
go tool compile main_fmt.go
# 链接过程
main_empty.out main_fmt.out: main_empty.o main_fmt.o
go tool link -o main_empty.out main_empty.o
go tool link -o main_fmt.out main_fmt.o
# 反汇编 object 文件
objdump_obj: main_fmt.o
go tool objdump -S main_fmt.o
# 反汇编链接后的可执行文件
objdump_exe: main_fmt.out
go tool objdump -S -s main.main main_fmt.out # -s 只显示 main 函数部分
#go tool objdump -S main_fmt.out # 整个可执行文件反汇编会看到链接器引入了大量文件
go tool nm 可以列出编译后的 object 文件以及链接后的可执行文件中定义或使用的 Symbols。
# 查看使用的 symbols
nm_obj: main_fmt.o
go tool nm -sort address -size -type main_fmt.o
# 查看使用的 symbols
nm_exe: main_fmt.out
go tool nm -sort address -size -type main_fmt.out
待学习..
升级 macOS 到 12.0 以后,原本可以编译的项目无法编译了:
# github.com/shirou/gopsutil/disk
iostat_darwin.c:28:2: warning: 'IOMasterPort' is deprecated: first deprecated in macOS 12.0 [-Wdeprecated-declarations]
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/IOKit.framework/Headers/IOKitLib.h:132:1: note: 'IOMasterPort' has been explicitly marked deprecated here
根据上述日志,iostat_darwin.c 使用了 macOS 的 IOMasterPort 接口,这个接口在 macOS 12.0 中不建议被使用:
//iostat_darwin.c:28:
IOMasterPort(bootstrap_port, &port);
match = IOServiceMatching("IOMedia");
CFDictionaryAddValue(match, CFSTR(kIOMediaWholeKey), kCFBooleanTrue);
status = IOServiceGetMatchingServices(port, match, &drives);
if(status != KERN_SUCCESS)
return -1;
macOS 12.0 将这个接口标记为不建议使用:
/*! @function IOMasterPort
@abstract Deprecated name for IOMainPort(). */
kern_return_t
IOMasterPort( mach_port_t bootstrapPort,
mach_port_t * mainPort )
__API_DEPRECATED_WITH_REPLACEMENT("IOMainPort", macos(10.0, 12.0), ios(1.0, 15.0), watchos(1.0, 8.0), tvos(1.0, 15.0));
用 go mod why
查看为什么会依赖引发这个问题的 github.com/shirou/gopsutil:
go mod why github.com/shirou/gopsutil
XXX.XXX.XXX/x/xx/dal/db imports
XXX.XXX.XXX/aweme-go/ktest/mock imports
XXX.XXX.XXX/edu/memongo imports
XXX.XXX.XXX/edu/memongo/mongobin imports
github.com/spf13/afero imports
io/fs: package io/fs is not in GOROOT (/Users/xx/Work/Bin/go-1.14.2/go/src/io/fs)
XXX.XXX.XXX/x/xx/dal/db imports
XXX.XXX.XXX/aweme-go/ktest/mock imports
XXX.XXX.XXX/edu/memongo imports
XXX.XXX.XXX/edu/memongo/mongobin imports
github.com/spf13/afero tested by
github.com/spf13/afero.test imports
testing/fstest: package testing/fstest is not in GOROOT (/Users/xx/Work/Bin/go-1.14.2/go/src/testing/fstest)
没法去掉这个依赖,目标服务要部署在 linux 上所以不想将 macOS 降级,考虑让 go 在编译的时候忽略这个 warning。
找来找去发现 go 的 gc 编译器没有忽略的错误的方法,而且导致问题的 github.com/shirou/gopsutil 引用 macOS 的 C 代码库时,使用的是 cgo:
// +build darwin
// +build cgo
package disk
/*
#cgo LDFLAGS: -framework CoreFoundation -framework IOKit
#include <stdint.h>
#include <CoreFoundation/CoreFoundation.h>
#include "iostat_darwin.h"
*/
import "C"
...
cgo 的编译参数要在目标代码的注释里添加,暂时没有什么好办法。。。