go tool — Professional¶
1. How the suite is built and shipped¶
The Go distribution bootstraps itself through cmd/dist. In source, every helper tool lives under src/cmd/<name>/:
src/cmd/asm/ src/cmd/buildid/ src/cmd/cgo/ src/cmd/compile/
src/cmd/cover/ src/cmd/dist/ src/cmd/fix/ src/cmd/link/
src/cmd/nm/ src/cmd/objdump/ src/cmd/pack/ src/cmd/pprof/
src/cmd/test2json/ src/cmd/trace/ src/cmd/addr2line/ ...
cmd/dist is special: it is the bootstrap builder that compiles all other tools and lays them down in $GOROOT/pkg/tool/<GOOS_GOARCH>/. The go driver locates them by reading $GOTOOLDIR (default: $GOROOT/pkg/tool/<host>). That is the entire installation mechanism — there is no plugin registry, no path manipulation, no environment magic beyond two variables.
2. Why some tools are "internal-only" in spirit¶
compile, link, asm, pack, cgo are part of the build contract: they accept very specific inputs that the go driver constructs (-importcfg files listing every imported package's archive path, -buildid strings, search paths, etc.). They are public in the sense that you can run them, but their command line is a private interface between cmd/go and the toolchain. Two consequences for a professional:
- Treat their flags as unstable across Go releases. Each release can rearrange them. Even
go tool compile -hwarns you off direct use. - If you must intercept them (e.g., for caching, distributed builds, instrumentation), the supported entry is
go build -toolexec=PROGRAM—cmd/goinvokesPROGRAM <tool> <args...>, letting you wrap each call without owning the action graph.
3. Sources and architectural notes¶
A few worth reading in source when you operate at this level:
| Path | Why |
|---|---|
src/cmd/go/internal/work/exec.go | The action graph: who calls compile, who calls link, in what order |
src/cmd/dist/build.go | How the toolchain is bootstrapped and installed into pkg/tool/ |
src/cmd/cover/ | How -cover instrumentation rewrites packages at build time |
src/cmd/pprof/ | A thin wrapper around github.com/google/pprof (vendored) |
src/cmd/trace/ | The HTTP server + frontend for runtime traces |
Reading exec.go once is high leverage: it makes every later "what does go build actually do?" question concrete.
4. pprof and trace are thin façades¶
go tool pprof is a vendored copy of google/pprof with a Go-toolchain entrypoint. Behavior, flags, and the interactive prompt are upstream's. A standalone pprof you install from upstream is broadly compatible; the Go-bundled one is pinned to a version known to work with that toolchain release.
go tool trace is a small HTTP server that parses the runtime trace format (runtime/trace.Start) and serves the interactive viewer. The trace format is versioned; new Go releases evolve it (notably the rewrite around Go 1.21–1.22), and traces collected on a newer runtime may not open in an older go tool trace. Document the Go version next to any archived trace.
5. Deprecation lifecycle¶
Tools come and go across releases. Two examples to keep in mind:
go tool vet— gone. Vet is now an analyzer suite invoked bygo vet(orgo test, which runs a vet subset automatically). Older scripts that callgo tool vetwill fail.go tool yacc— removed long ago; replaced by externalgoyacc.covdata— added with the integration-coverage rework around Go 1.20; older toolchains do not have it.
The right policy is to assume go tool is toolchain-versioned: build a tool catalog test in CI that asserts the tools you rely on are present in the pinned toolchain.
go tool 2>/dev/null | grep -E '^(pprof|trace|cover|nm|objdump|buildid)$' \
| wc -l | xargs -I{} test {} -eq 6
6. Wrappers, intercepts, and caches¶
Three professional patterns for plugging into the suite:
-toolexec— wrap every per-tool invocation. Used by tools likexcaddy, custom code-signing, deterministic-builder sandboxes, and remote-build systems.GOTOOLCHAIN— pin the exact toolchain (e.g.,GOTOOLCHAIN=go1.22.3) so the entire suite (including pprof/trace) is reproducible across machines.GOFLAGS— global defaults for everygoinvocation (e.g.,GOFLAGS=-trimpath -buildvcs=false) that propagate togo tool ...where applicable.
7. Distribution sanity in CI¶
Some failures are not "your code is wrong" but "the toolchain on this runner is not what you think":
Print this at the top of CI jobs that use go tool ... extensively. It saves hours when a runner image silently upgrades Go and removes a tool you depended on.
8. Security posture¶
The tools execute as the invoking user with full filesystem access. Hardening points:
- Untrusted inputs:
pprofandtraceparse externally-provided files; treat profiles/traces from outside your org as untrusted input. The viewer also opens an HTTP server on localhost — make sure it is bound to loopback in shared environments. -toolexecprograms receive every compile/link invocation. They are an excellent supply-chain choke point and also an excellent attack surface; review them carefully.buildidlying —go tool buildid -wcan rewrite the build ID of an artifact, which downstream tools may use for identity. Treat build-id as advisory, not authenticating; for true authentication, sign artifacts.
9. Onboarding & docs policy¶
A short page in your internal docs that says:
- which toolchain version is pinned;
- which
go toolsubcommands are part of the standard workflow (and which are explicitly out-of-scope); - where profiles/traces are stored and how to open them locally;
- a copy-pasteable
-toolexecwrapper template if your build needs one.
This is cheaper than every engineer rediscovering go tool pprof -http=:8080 cpu.out.
10. Summary¶
go tool is a discoverable façade over per-tool binaries laid out by cmd/dist in $GOROOT/pkg/tool/<host>/. Build-internal tools (compile, link, asm, cgo, pack) have unstable command lines and should be intercepted only via -toolexec. User-facing tools (pprof, trace, cover, nm, objdump, addr2line, test2json, dist list, buildid) are stable enough to script against. Pin GOTOOLCHAIN, version-check your tool catalog in CI, and treat profiles/traces from outside your perimeter as untrusted input.
Further reading¶
cmd/goaction graph: https://github.com/golang/go/blob/master/src/cmd/go/internal/work/exec.gocmd/dist: https://github.com/golang/go/tree/master/src/cmd/dist-toolexecflag:go help build- google/pprof: https://github.com/google/pprof