
Go 1.13 之前 go build ./cmd/... 无法将多个二进制文件输出到当前目录;该限制源于工具链设计缺陷,需通过 -o 配合单目标构建或升级至 Go 1.13+ 才能原生支持多目标统一输出。
go 1.13 之前 `go build ./cmd/...` 无法将多个二进制文件输出到当前目录;该限制源于工具链设计缺陷,需通过 `-o` 配合单目标构建或升级至 go 1.13+ 才能原生支持多目标统一输出。
在 Go 项目中,尤其是包含多个 cmd/ 子目录(如 cmd/api, cmd/cli, cmd/admin)的仓库,开发者常期望一条命令即可构建所有可执行文件并统一落盘到当前工作目录。然而,在 Go 1.12 及更早版本中,以下命令行为并不符合直觉:
go build ./cmd/...
该命令不会在当前目录生成任何二进制文件——它会静默成功,但实际不写入任何输出(除非当前目录恰好是某个 cmd 包的根路径)。这是因为 go build 在处理通配符多包时,对 -o 标志的约束极为严格:-o 不允许与多个编译目标共存,而默认“输出到当前目录”的逻辑在多包场景下被完全绕过(见 issue #14295)。
✅ 正确的替代方案(兼容 Go 1.11+):
方案一:循环构建(推荐,稳定可靠)
使用 shell 循环逐个构建,并显式指定 -o 输出名:
# Linux/macOS
for cmd in cmd/*; do
[[ -d "$cmd" ]] && go build -o "./$(basename $cmd)" "$cmd"
done
# Windows PowerShell
Get-ChildItem .\cmd\ -Directory | ForEach-Object {
go build -o ".\$($_.Name).exe" "$($_.FullName)"
}方案二:利用 go list 动态获取命令包(更健壮)
避免硬编码路径,适配嵌套或非标准结构:
# 构建所有 main 包,并以包名命名二进制(不含扩展名)
for pkg in $(go list -f '{{if .Main}}{{.ImportPath}}{{end}}' ./cmd/...); do
name=$(basename "$pkg")
go build -o "./$name" "$pkg"
done⚠️ 注意事项:
- Windows 用户需添加 .exe 后缀(-o "./$name.exe"),Linux/macOS 默认无后缀;
- 若 cmd/ 下存在非 main 包(如工具库),go list -f '{{if .Main}}...' 可精准过滤;
- Go 1.13+ 已修复此问题:go build ./cmd/... 将自动在当前目录生成对应名称的二进制文件(如 cmd/api → api),无需额外脚本;
- 切勿使用 go build -o ./ ./cmd/... —— 这会报错 cannot use -o with multiple packages。
总结:在升级到 Go 1.13 前,脚本化构建是唯一可靠方式;升级后可回归简洁命令,享受官方对多二进制工作流的原生支持。


















