◐ Off-By-One · answer catalog

go-cli-shellout-path-docs

1 answer(s)godocker

CMDS := $(patsubst cmd/%/main.go,%,$(wildcard cmd//main.go))

📦 Source in repository (JSON)

Answer

Root cause (reproduced). With more than one main package matched, go build ./cmd/... (no -o) builds but discards the executables — exit 0, nothing written. So the CLI's sibling lookup (./<name>, cmd/<name>/<name>) always failed and execution silently fell through to PATH (or a stale/absent install). The fix forces the binaries to be emitted into the repo root, plus adds an install path for production use.

1. Makefile — emit binaries + install target

PREFIX ?= /usr/local
BINDIR  = $(PREFIX)/bin

# one repo-root binary per package under cmd/ (name = dir name)
CMDS := $(patsubst cmd/%/main.go,%,$(wildcard cmd/*/main.go))

.PHONY: all build install clean

all: build

build:
    # -o . is REQUIRED: without it, go1.26 discards multi-package main binaries
    go build -o . ./cmd/...

install: build
    install -d $(DESTDIR)$(BINDIR)
    @for c in $(CMDS); do \
        install -m 0755 $$c $(DESTDIR)$(BINDIR)/$$c; \
    done

clean:
    rm -f $(CMDS)

Usage: make build (dev), make install → /usr/local/bin, make install PREFIX=~/.local, and make install DESTDIR=/tmp/pkg PREFIX=/usr for packaging (both PREFIX and BINDIR are DESTDIR-aware).

2. README — Install section

```markdown

Evidence & signatures

All verified against `/usr/bin/go` **go1.26.0 linux/amd64**, in a throwaway repo (`module example.com/helix` with `cmd/alpha`, `cmd/beta`, plus a `cmd/solo` added later):

| Check | Command | Result |
|---|---|---|
| Root cause reproduced | `go build ./cmd/...` | exit 0, **no binaries emitted** (only `go.mod`, `cmd/`) |
| Fix works | `go build -o . ./cmd/...` | `alpha` + `beta` (0755) appear in repo root |
| Single-package regression | add `cmd/solo`, `go build -o . ./cmd/...` | `solo` emitted too — no regression |
| Default install | `make install PREFIX=/tmp/.../prefix` | `/prefix/bin/alpha`, `/prefix/bin/beta` (mode 0755) |
| Prefix override | `make install PREFIX=/tmp/.../prefix` | installs to `$(PREFIX)/bin` |
| Packaging/staging | `make install DESTDIR=stage PREFIX=/usr` | installs to `stage/usr/bin/*` — DESTDIR-aware |
| Resolver order | `go test -v ./...` | `TestFindBin`: both `alpha`→`alpha`, `beta`→`beta` resolved via repo-root sibling (`./<name>`) |
| PATH fallback | binary hidden, isolated PATH | correctly reports not-found (would fall through to PATH when present) |

Edge cases: multi-package vs single-package `-o .` behavior; `PREFIX`/`DESTDIR` overrides (both honored, so distro packaging works); lookup order `./` → `cmd/x/x` → PATH; not-found message names all three locations and suggests `make install`. No stale binaries are left behind (Makefile `clean` removes repo-root artifacts; `-o .` only writes main-package binaries).
{"model": "deepseek-v4-flash", "problem_class": "go-cli-shellout-path-docs", "result": "passed", "tests": 6}
Generated from the verified corpus · MIT licensedBack to the catalog