Go build不自动编译自定义库?需加-a才生效是否符合预期?
go build的预期行为 正常来说,当你修改了项目中被主包依赖的文件(比如你的apis/rtb.go和jsondef/structures.go),直接执行go build应该会自动检测到这些文件的变化,重新编译对应的子包,再链接生成最终的二进制文件。你需要用go build -a才能生效的情况,大概率是遇到了构建缓存或者项目结构/依赖配置的问题,下面是具体的排查方向和解决办法:
1. 检查子包的导入与包声明是否正确
首先确认两个关键点:
- 子目录中的文件是否正确声明了包名:比如
apis/rtb.go的第一行应该是package apis,jsondef/structures.go的第一行是package jsondef - 主包文件(
thingsToComposer.go)是否正确导入了这两个子包:- 如果你的项目使用Go Modules(推荐方式),导入路径应该是你的模块名加上子包路径,比如
import "tb-to-composer/apis"(前提是你已经通过go mod init tb-to-composer初始化了模块) - 如果是GOPATH模式,导入路径可以用相对路径
import "./apis"
- 如果你的项目使用Go Modules(推荐方式),导入路径应该是你的模块名加上子包路径,比如
如果主包没有正确导入这些子包,go build默认只会编译主目录下的.go文件,不会处理子目录里的内容——但这种情况下go build -a也不会把这些子包编进去,所以如果你的二进制确实用到了子包的代码,那这个问题可能不成立。
2. 检查文件系统的时间同步问题
Go的构建缓存是基于文件的修改时间和内容哈希来判断是否需要重新编译的。如果你的项目运行在虚拟机、容器或者网络文件系统(NFS)中,可能会出现主机和容器/虚拟机的时间不同步的情况,导致Go认为文件没有被修改。
你可以在项目目录下执行以下命令,查看文件的修改时间是否正确:
ls -l apis/rtb.go jsondef/structures.go
如果时间显示异常(比如比当前时间早很多或者晚很多),需要同步你的系统时间,比如在Linux下执行:
sudo timedatectl set-ntp true
3. 手动清理Go构建缓存
有时候构建缓存可能出现异常,导致Go无法正确识别文件变化。你可以手动清理缓存,然后再尝试go build:
go clean -cache
清理后再执行go build,看是否能正常重新编译修改后的文件。
4. 确认项目的构建范围
如果你执行go build时没有指定包路径,默认只会编译当前目录下的主包。但如果你的子包是主包的依赖,Go会自动处理依赖的编译。不过你也可以尝试明确指定编译整个模块,看是否能解决问题:
go build ./...
这个命令会编译模块下的所有包,包括子包。
总结
正常情况下go build应该自动处理依赖文件的修改,你遇到的情况属于异常。优先排查包导入、时间同步问题,再尝试清理缓存,一般就能解决。
内容的提问来源于stack exchange,提问作者Vieira Neto Manoel

