go build's path argument

Suppose you have this directory structure for a Go project:

.
└── cmd
    └── web
        ├── main.go
        ├── handlers.go
        └── ...

├── go.mod
├── go.sum
└── pkg

You want to compile the content of cmd/web.

TL;DR: run go build ./cmd/web from ./.

From the package directory

From ./cmd/web, everything works as expected: go build, go build . and go build ./*.go all behave the same, producing an executable in ./cmd/web/web.

From the root directory

Running go build from the project’s root ./ behaves a bit differently.

  1. Running go build cmd/web/*.go produces an executable in ./handlers.
    This is because:

    When compiling a single main package, build writes the resulting executable to an output file named after the first source file (go build ed.go rx.go writes ‘ed’ or ‘ed.exe’) or the source code directory (go build unix/sam writes ‘sam’ or ‘sam.exe’). The ‘.exe’ suffix is added when writing a Windows executable.

  2. Running go build cmd/web returns the error package cmd/web is not in GOROOT; this is because Go is expecting a module path, but it’s not getting one.

  3. Running go build [module/path]/web produces an executable in ./web as expected.

  4. Running go build ./cmd/web also produces an executable in ./web as expected; this is because by specifying ./ at the beginning of the path, Go doesn’t expect a module anymore and compiles the package in the path.