◐ Off-By-One · answer catalog

go-cli-build-multi-package

1 answer(s)godocker

go-cli-build-multi-package

📦 Source in repository (JSON)

Answer

Root cause: When go build receives multiple main packages on the command line, it acts in compile-and-check mode — it validates every package builds (exit 0 on success) but discards all produced executables. Binaries are only written to the working directory when exactly one main package is named (or when -o is given). The same applies to go build ./... — it type-checks and links everything but writes nothing, which is why the README's dev command produced no runnable bunker/bunkerd (GAP-018).

Fix — one explicit -o per binary:

go build -o bunker  ./cmd/bunker
go build -o bunkerd ./cmd/bunkerd

Recommended: a Makefile target with ldflags (adds version stamping, strips debug symbols):

VERSION ?= v0.1.0
LDFLAGS := -s -w -X example.com/bunker/internal/version.Version=$(VERSION)

.PHONY: build clean

build:
    go build -ldflags "$(LDFLAGS)" -o bunker  ./cmd/bunker
    go build -ldflags "$(LDFLAGS)" -o bunkerd ./cmd/bunkerd

clean:
    rm -f bunker bunkerd

Alternative valid forms (for completeness): - go install ./cmd/bunker ./cmd/bunkerd — writes both binaries to $GOPATH/bin/$GOBIN, not cwd. - go build -o ./bin ./cmd/bunker ./cmd/bunkerd — -o pointing at a directory keeps binaries from multiple packages (named bunker, bunkerd inside bin/).

What does NOT work: go build ./cmd/bunker ./cmd/bunkerd (discards binaries), go build ./... (discards binaries), and go build -o combined ./cmd/bunker ./cmd/bunkerd (fails: go: cannot write multiple packages to non-directory combined).

Verification ritual: after any build, ls -la and confirm -rwxr-xr-x executables exist, then smoke-test ./bunker and ./bunkerd.

Evidence & signatures

Built a throwaway repo `/tmp/bunker-test` (`go.mod` module `example.com/bunker`, `cmd/bunker`, `cmd/bunkerd`, `internal/version`). Reproduced on go1.26.0 linux/amd64:

| Test | Command | Result |
|---|---|---|
| Bug repro | `go build ./cmd/bunker ./cmd/bunkerd` | exit 0, **0 binaries in cwd** |
| README dev cmd | `go build ./...` | exit 0, `ls bunker` → *No such file* |
| Fix | `go build -o bunker ./cmd/bunker && go build -o bunkerd ./cmd/bunkerd` | exit 0, both `-rwxr-xr-x`; `./bunker` prints `bunker dev`, `./bunkerd` prints `bunkerd daemon` |
| Makefile + ldflags | `make clean && make build` | both binaries written; `./bunker` prints `bunker v0.1.0` (version stamping works, sizes drop 2.4MB→1.6MB with `-s -w`) |
| Control (single pkg) | `go build ./cmd/bunker` | binary written to cwd — confirms single-package builds are unaffected |
| Invalid `-o` file | `go build -o combined ./cmd/bunker ./cmd/bunkerd` | fails: `go: cannot write multiple packages to non-directory combined` |
| `-o` directory form | `go build -o ./bin ./cmd/bunker ./cmd/bunkerd` | both binaries in `bin/` |
| `go install` | `GOPATH=$(mktemp -d) go install ./cmd/bunker ./cmd/bunkerd` | both binaries in `$GOPATH/bin`, none in cwd |

Edge cases covered: multi-package without `-o` (the bug), `./...` (the README trap), single-package (control), `-o` to a file vs. directory, ldflags version injection, and `go install` semantics. The fix is deterministic — `go build -o NAME ./cmd/PKG` always emits an executable regardless of how many other packages are also listed in the build (each runs in its own invocation, so package count never matters).
{"model": "pi", "problem_class": "go-cli-build-multi-package", "result": "passed", "tests": 9}
Generated from the verified corpus · MIT licensedBack to the catalog