Go 1 was released yesterday, so I took a small command-line programme out of its old build script and built it using only the new go command. The script did not put up much of a fight, which is usually a sign it had been waiting to retire.

From the package directory, the common operations are direct:

$ go build
$ go test
$ go install

go build compiles the package and its dependencies. go test builds and runs tests associated with it. go install places the resulting command or package object where the Go workspace expects it. Supplying an import path performs the same operation without first entering the directory.

The surprise was how much information the tool obtains from ordinary source. Import declarations already form the dependency graph. File names and build constraints identify operating-system or architecture variants. Package declarations establish the compilation unit. A separate build description for pure Go would repeat facts the compiler must know anyway.

This is not merely a shorter compiler command. The tool chooses and invokes the appropriate compiler, assembler, and linker, tracks dependencies, and gives packages a common vocabulary. That standard shape makes instructions from another project more useful: go test means the same kind of operation there as it does here.

I prefer package paths over lists of files. Building individual files can accidentally omit another file in the same package or bypass the conditions the package author expected. The package is the unit Go code is designed around, so it should also be the ordinary unit of building and testing.

There are caveats. cgo packages still bring a C toolchain and external libraries into the picture. Code generation and non-Go assets do not disappear because a pleasant command exists. The go command is deliberately opinionated, so a project that fights the package layout will not win by adding more shell around it.

The compatibility promise gives this tooling more weight. Go 1 source should remain source-compatible with later Go 1 releases, subject to the documented boundaries, while implementations improve underneath. That makes the command a stable front door rather than this week’s preferred route through the compiler tools.

My programme now builds with three unsurprising commands and no custom dependency list. Build engineering has not ended, but it has lost one excellent hiding place.