Open-Source Wikis

/

Go

/

Components

/

Go command

golang/go

Go command

cmd/go is the program a user actually invokes: go build, go test, go get, go run, go mod, go work, go install, go env, and so on. It's the orchestrator that resolves modules, walks import graphs, schedules per-package builds, manages the build cache, and shells out to compile, link, asm, cgo, and vet.

Purpose

The go command is the public face of the Go toolchain. Internally, it does three big things:

  1. Module resolution — given a go.mod, decide which versions of which modules to use.
  2. Package loading — turn a list of import paths into a graph of packages and their files.
  3. Build orchestration — drive the per-package compile/assemble/link calls, with a content-addressed build cache.

It also hosts a long list of subcommands (mod, work, vet, test, etc.), each of which lives in its own internal package.

Directory layout

src/cmd/go/
├── main.go                     # main + dispatch table of subcommands
├── alldocs.go                  # Generated; concatenated subcommand help
└── internal/
    ├── base/                   # Subcommand framework, common flags
    ├── work/                   # The build engine (build, install, test, run)
    ├── load/                   # Package loader (resolves imports → *Package)
    ├── modload/                # Module loader (resolves go.mod → resolved versions)
    ├── modfetch/               # Download + cache modules from proxies
    ├── modindex/               # On-disk index of stdlib + modcache
    ├── modcmd/                 # 'go mod' subcommands (init, tidy, edit, why, ...)
    ├── modget/                 # 'go get' (modify go.mod)
    ├── modinfo/                # JSON-export of module info
    ├── mvs/                    # Minimum version selection algorithm
    ├── workcmd/                # 'go work' (workspace mode)
    ├── toolchain/              # 'go.mod' toolchain= switching, re-exec
    ├── vcs/                    # VCS proxy (git/hg/svn) for module resolution
    ├── vcweb/                  # Test-only VCS server
    ├── auth/                   # 'go env GOAUTH' authenticated downloads
    ├── cache/                  # Content-addressed build/test cache
    ├── cacheprog/              # External cache helper protocol
    ├── cfg/                    # GO* environment variable handling
    ├── cmdflag/                # Subcommand flag helper
    ├── doc/                    # 'go doc'
    ├── envcmd/                 # 'go env'
    ├── fmtcmd/                 # 'go fmt'
    ├── fsys/                   # Overlay-aware filesystem (used by gopls)
    ├── generate/               # 'go generate'
    ├── gover/                  # Go version comparison ('go1.21' vs 'go1.22')
    ├── help/                   # Help registry
    ├── imports/                # Build-tag-aware import discovery
    ├── list/                   # 'go list' (dump package info)
    ├── lockedfile/             # File locking for concurrent invocations
    ├── mmap/                   # mmap helper
    ├── run/                    # 'go run'
    ├── search/                 # Path patterns ('./...' resolution)
    ├── str/                    # String helpers
    ├── telemetrycmd/           # 'go telemetry'
    ├── telemetrystats/         # Counter declarations
    ├── test/                   # 'go test'
    ├── tool/                   # 'go tool' (delegate to subtools)
    ├── trace/                  # 'go run -toolexec=trace'-style support
    ├── version/                # 'go version'
    ├── vet/                    # 'go vet'
    ├── web/                    # HTTP fetcher
    └── fips140/                # FIPS-140 compliance helpers

Subcommands

cmd/go/main.go builds a flat dispatch table of *base.Command. Each subcommand is registered from its package's init or via the table in main.go:

base.Go.Commands = []*base.Command{
    bug.CmdBug,           // go bug
    work.CmdBuild,        // go build
    clean.CmdClean,       // go clean
    doc.CmdDoc,           // go doc
    envcmd.CmdEnv,        // go env
    vet.CmdFix,           // go fix
    fmtcmd.CmdFmt,        // go fmt
    generate.CmdGenerate, // go generate
    modget.CmdGet,        // go get
    work.CmdInstall,      // go install
    list.CmdList,         // go list
    modcmd.CmdMod,        // go mod
    workcmd.CmdWork,      // go work
    run.CmdRun,           // go run
    telemetrycmd.CmdTelemetry, // go telemetry
    test.CmdTest,         // go test
    tool.CmdTool,         // go tool
    version.CmdVersion,   // go version
    vet.CmdVet,           // go vet
    ...
}

Each *base.Command has a Run function (func(ctx, *Command, []string)), help text, and flags. The base package handles flag parsing, help routing, and "did you mean" suggestions.

How go build works

graph TD
    Start[go build .] --> Args[parse flags + args]
    Args --> Modload[modload.LoadPackages]
    Modload --> Mvs[mvs: pick versions]
    Mvs --> Loader[load.PackagesAndErrors]
    Loader -->|per package: parse files,<br/>resolve imports| PkgGraph[Package graph]
    PkgGraph --> Builder[work.Builder]
    Builder --> Actions[Plan Action graph]
    Actions -->|leaf| Compile[Action: compile pkg]
    Actions -->|leaf| Asm[Action: assemble .s]
    Actions -->|root| Link[Action: link]
    Compile -.cache hit?.-> Cache[build cache]
    Compile -->|miss| Toolchain[exec compile]
    Link --> Binary[Output binary]

Concretely:

  1. cmd/go/internal/work.runBuild parses build flags (-o, -tags, -gcflags, -ldflags, -trimpath, etc.).
  2. modload.LoadPackages resolves modules using Minimum Version Selection (internal/mvs), reading go.mod and go.sum. Missing modules trigger a download via internal/modfetch.
  3. load.PackagesAndErrors walks each requested package, parses imports, applies build tags (internal/imports/build.go), and produces *load.Package nodes.
  4. work.Builder.Do plans an Action DAG: one action per package compile, plus dependencies, plus a final link action.
  5. The builder executes actions in topological order, in parallel up to -p N (default = NumCPU). Each action consults the build cache (internal/cache).
  6. Cache misses shell out to $GOROOT/pkg/tool/<host>/compile, link, asm, cgo, etc.

Module loading

The module loader is the most complex part of the go command. It handles:

  • Reading and editing go.mod and go.sum.
  • Resolving the build list — the set of module versions that satisfy all require directives.
  • Downloading modules through the proxy (proxy.golang.org by default) via internal/modfetch.
  • Verifying checksums against sum.golang.org (the public checksum database).
  • Workspace mode (go.work), which stitches together multiple modules.

The core algorithm is Minimum Version Selection (MVS) in internal/mvs/. Given a root module's requirements, MVS picks the minimum version of each module that all transitively-required versions agree on.

Module operations

  • go mod init — create a go.mod.
  • go mod tidy — add missing requirements, remove unused ones; fully consistent set.
  • go mod download — fetch and cache; do not change go.mod.
  • go mod graph — print the require graph as DAG edges.
  • go mod vendor — copy all dependencies into ./vendor/.
  • go mod why -m mod — explain why a module is in the graph.
  • go mod edit — programmatic edit of go.mod.

All implemented under internal/modcmd/.

Toolchain switching

Since Go 1.21, the go directive in go.mod may declare a Go language version higher than the current toolchain. The go.mod toolchain line and the GOTOOLCHAIN env var let the go command re-exec a different Go release that satisfies the requirement.

This logic lives in internal/toolchain/. The first go invocation downloads the requested toolchain into GOPATH/pkg/mod/golang.org/toolchain@<version> and execs into it. Users see this as a transparent "this project requires Go 1.22; I'll go fetch it."

The build cache

internal/cache/cache.go is a content-addressed, on-disk cache, by default at ~/.cache/go-build. Cache keys are derived from:

  • The action ID: hash of all inputs (source files, dependencies, compiler flags, target OS/arch, toolchain version, ...).
  • The output ID: hash of the action's output object file.

Cache lookups are cheap; cache hits skip the corresponding compile/link/vet invocation. go clean -cache wipes it.

go test results are also cached: a successful test run caches a "test passed" record keyed on the same input set. Subsequent identical go test invocations print (cached) and skip the run.

For build systems that want to plug in their own remote cache, the GOCACHEPROG protocol (handled by internal/cacheprog/) lets an external program take over.

go test

internal/test/ orchestrates test runs. For each tested package, go test:

  1. Builds the package's tests by writing a synthesized _testmain.go that calls into the framework.
  2. Compiles + links a test binary.
  3. Runs the binary, parses go test -v output, optionally streams to cmd/test2json.
  4. Caches a "passed" record on success.

Special test modes:

  • -cover, -coverpkg — coverage instrumentation via internal/cov/.
  • -fuzz, -fuzztime — fuzzing via src/internal/fuzz/.
  • -race, -asan, -msan — sanitizer modes (require cgo).
  • -bench, -benchtime, -benchmem — benchmark mode.

go generate

internal/generate/ walks files matching //go:generate <command> and runs them in the file's directory. Used to regenerate code from rule files, schemas, etc.

go env

internal/envcmd/ reads/writes ~/.config/go/env. The defaults are seeded by $GOROOT/go.env. The hierarchy is:

  1. Environment variables override everything.
  2. Per-user go env settings.
  3. The $GOROOT/go.env defaults.

go vet

internal/vet/ is a thin wrapper that invokes cmd/vet/ (a separate binary) on each package built. The vet binary uses golang.org/x/tools/go/analysis (vendored under src/cmd/vendor/) and bundles the standard analyses.

Key abstractions

Abstraction Where Purpose
*base.Command cmd/go/internal/base/ One subcommand
*load.Package cmd/go/internal/load/ One Go package, fully resolved
*work.Action cmd/go/internal/work/ One step in the build DAG
modload.requirementsBuilder cmd/go/internal/modload/ The module loader's build list
mvs.Reqs cmd/go/internal/mvs/ The interface MVS consumes
cache.Cache cmd/go/internal/cache/ The build cache
imports.Tags cmd/go/internal/imports/ Build constraint evaluation

Key source files

File Purpose
src/cmd/go/main.go Entry point + subcommand dispatch
src/cmd/go/internal/work/build.go go build driver
src/cmd/go/internal/work/exec.go Action executor
src/cmd/go/internal/work/action.go Action DAG construction
src/cmd/go/internal/load/pkg.go Package loader
src/cmd/go/internal/modload/load.go Module loader
src/cmd/go/internal/modload/buildlist.go Build list (MVS result)
src/cmd/go/internal/modfetch/fetch.go Module download + verify
src/cmd/go/internal/cache/cache.go Build cache
src/cmd/go/internal/test/test.go go test driver
src/cmd/go/internal/toolchain/select.go Toolchain switching

Integration points

  • Compiler (compiler) is invoked via exec.Command from internal/work/.
  • Linker (linker) is invoked the same way as the final step.
  • Module proxy (proxy.golang.org, sum.golang.org) is contacted via internal/modfetch and internal/web.
  • gopls and other tools call into similar logic via golang.org/x/tools/go/packages, which is a separate but parallel implementation that talks to go list to extract package info.

Entry points for modification

  • New subcommand: add a *base.Command and register it in main.go. Don't forget alldocs.go (regenerated by go generate ./...).
  • Module loader bug: start in cmd/go/internal/modload/. The integration tests are in cmd/go/script_test.go plus the txtar files under cmd/go/testdata/script/.
  • Build cache: internal/cache/. cmd/go/script_test.go has many cache-related tests.
  • Test framework: cmd/go/internal/test/ plus the testing package itself in src/testing/.

Testing the go command

cmd/go/script_test.go is the workhorse: it runs scripts written in the txtar format (sibling to the cmd/go/testdata/script/ directory). Each script can cd, cp, go build, etc., and assert about output and file contents. New go command behaviors usually get a script test.

  • Compiler — what go build invokes for each package.
  • Linker — what go build invokes for the final binary.
  • src/cmd/go/alldocs.go — concatenated help for every subcommand (read in a browser via go help <topic>).
  • Toolingcmd/dist, cmd/vet, cmd/api.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Go command – Go wiki | Factory