Go Toolchain: build, run, test, fmt
The Go toolchain provides powerful commands for building, running, testing, and formatting Go programs. Understanding these tools is essential for productive Go development. This guide covers the most important toolchain commands and their practical usage.
Overview of Go Commands
go build # Compile packages and dependencies
go run # Compile and run Go program
go test # Test packages
go fmt # Format Go source code
go install # Compile and install packages
go get # Download and install packages
go clean # Remove object files and cached files
go doc # Show documentation
go vet # Report likely mistakes in packages
go mod # Module maintenance
go build - Compiling Programs
Basic Usage
# Build current package
go build
# Build specific package
go build ./cmd/myapp
# Build with output name
go build -o myapp
# Build for different OS
GOOS=linux GOARCH=amd64 go build -o myapp-linux
# Build with version info
go build -ldflags "-X main.Version=1.0.0"
Build Flags
# Verbose output
go build -v
# Print commands being executed
go build -x
# Disable optimizations (faster compilation)
go build -gcflags="-N -l"
# Enable race detector
go build -race
# Build tags
go build -tags "prod"
# Output directory
go build -o ./bin/myapp
Cross-Compilation
# Build for Linux
GOOS=linux GOARCH=amd64 go build -o myapp-linux
# Build for macOS
GOOS=darwin GOARCH=amd64 go build -o myapp-macos
# Build for Windows
GOOS=windows GOARCH=amd64 go build -o myapp.exe
# Build for ARM (Raspberry Pi)
GOOS=linux GOARCH=arm GOARM=7 go build -o myapp-arm
# List supported platforms
go tool dist list
Embedding Version Information
# In main.go
package main
import "fmt"
var Version = "dev"
func main() {
fmt.Println("Version:", Version)
}
# Build with version
go build -ldflags "-X main.Version=1.0.0"
# Run
./myapp
# Output: Version: 1.0.0
Build Constraints
Use build tags to conditionally compile code:
// +build linux
package main
// This code only compiles on Linux
Or use build constraints:
//go:build linux && amd64
package main
// This code only compiles on Linux with amd64 architecture
go run - Running Programs
Basic Usage
# Run current package
go run main.go
# Run with arguments
go run main.go arg1 arg2
# Run specific file
go run ./cmd/myapp/main.go
# Run multiple files
go run main.go utils.go
Common Patterns
# Run with environment variables
ENV_VAR=value go run main.go
# Run with flags
go run main.go -config config.yaml
# Run and capture output
go run main.go > output.txt 2>&1
# Run in background
go run main.go &
# Run with timeout
timeout 10s go run main.go
Development Workflow
# Watch for changes and rerun (using entr)
find . -name "*.go" | entr go run main.go
# Or use air for hot reload
air
# Or use CompileDaemon
CompileDaemon -build="go build -o myapp" -command=./myapp
go test - Testing
Basic Testing
# Run all tests in current package
go test
# Run tests in specific package
go test ./...
# Run specific test
go test -run TestMain
# Run tests matching pattern
go test -run "Test.*User"
# Run benchmarks
go test -bench=.
# Run benchmarks with specific pattern
go test -bench="BenchmarkSort"
Test Flags
# Verbose output
go test -v
# Show coverage
go test -cover
# Generate coverage file
go test -coverprofile=coverage.out
# Display coverage in HTML
go test -coverprofile=coverage.out
go tool cover -html=coverage.out
# Run with race detector
go test -race
# Timeout for tests
go test -timeout 30s
# Run tests in parallel
go test -parallel 4
# Run tests sequentially
go test -parallel 1
# Show test output even on success
go test -v
Coverage Analysis
# Generate coverage report
go test -coverprofile=coverage.out ./...
# View coverage in browser
go tool cover -html=coverage.out
# View coverage in terminal
go tool cover -func=coverage.out
# Check coverage percentage
go test -cover ./...
Example Test File
package main
import "testing"
func TestAdd(t *testing.T) {
result := Add(2, 3)
expected := 5
if result != expected {
t.Errorf("Add(2, 3) = %d, want %d", result, expected)
}
}
func BenchmarkAdd(b *testing.B) {
for i := 0; i < b.N; i++ {
Add(2, 3)
}
}
Running Tests
# Run tests
go test
# Run with verbose output
go test -v
# Run specific test
go test -run TestAdd
# Run benchmarks
go test -bench=. -benchmem
# Run with coverage
go test -cover
# Run with race detector
go test -race
go fmt - Formatting
Basic Usage
# Format current file
go fmt
# Format specific file
go fmt main.go
# Format all files in package
go fmt ./...
# Format and write to file
go fmt -w main.go
# Check if formatting is needed
go fmt -l ./...
Formatting Rules
Go enforces strict formatting rules:
// โ
Good: Proper indentation and spacing
func main() {
fmt.Println("Hello, World!")
}
// โ Bad: Inconsistent indentation
func main() {
fmt.Println("Hello, World!")
}
// โ
Good: Proper brace placement
if x > 0 {
fmt.Println("positive")
}
// โ Bad: Brace on new line (not Go style)
if x > 0
{
fmt.Println("positive")
}
Using goimports
goimports is like go fmt but also organizes imports:
# Install goimports
go install golang.org/x/tools/cmd/goimports@latest
# Format and organize imports
goimports -w main.go
# Format all files
goimports -w ./...
go install - Installing Packages
Basic Usage
# Install current package
go install
# Install specific package
go install github.com/user/package
# Install with version
go install github.com/user/[email protected]
# Install from main branch
go install github.com/user/package@main
# Install binary to specific location
GOBIN=/usr/local/bin go install github.com/user/package
Installing Tools
# Install golangci-lint
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
# Install gopls (language server)
go install github.com/golang/tools/gopls@latest
# Install dlv (debugger)
go install github.com/go-delve/delve/cmd/dlv@latest
# Verify installation
which golangci-lint
go clean - Cleaning
Basic Usage
# Remove object files
go clean
# Remove all build artifacts
go clean -a
# Remove cache
go clean -cache
# Remove test cache
go clean -testcache
# Remove modcache
go clean -modcache
# Verbose output
go clean -v
go vet - Code Analysis
Basic Usage
# Check current package
go vet
# Check specific package
go vet ./...
# Check with specific rules
go vet -composites=false ./...
# Verbose output
go vet -v ./...
Common Issues Detected
// โ Unreachable code
func example() {
return
fmt.Println("unreachable") // vet warns about this
}
// โ Unused variables
func example() {
x := 5 // vet warns if x is never used
}
// โ Printf format errors
fmt.Printf("%d", "string") // vet warns about type mismatch
go doc - Documentation
Basic Usage
# Show package documentation
go doc
# Show function documentation
go doc fmt.Println
# Show type documentation
go doc http.Server
# Show method documentation
go doc http.Server.ListenAndServe
# Show all documentation
go doc -all fmt
# Open in browser
go doc -http=:6060
go mod - Module Management
Basic Usage
# Initialize module
go mod init github.com/user/project
# Tidy dependencies
go mod tidy
# Download dependencies
go mod download
# Verify dependencies
go mod verify
# Show dependency graph
go mod graph
# Show all dependencies
go list -m all
Practical Workflows
Development Workflow
# 1. Format code
go fmt ./...
# 2. Run linter
golangci-lint run ./...
# 3. Run tests
go test -v -race ./...
# 4. Build
go build -o myapp
# 5. Run
./myapp
CI/CD Pipeline
#!/bin/bash
# Format check
go fmt ./...
if [ $? -ne 0 ]; then
echo "Format check failed"
exit 1
fi
# Vet
go vet ./...
if [ $? -ne 0 ]; then
echo "Vet check failed"
exit 1
fi
# Tests
go test -v -race -coverprofile=coverage.out ./...
if [ $? -ne 0 ]; then
echo "Tests failed"
exit 1
fi
# Build
go build -o myapp
if [ $? -ne 0 ]; then
echo "Build failed"
exit 1
fi
echo "All checks passed!"
Release Build
#!/bin/bash
VERSION=$(git describe --tags --always)
BUILD_TIME=$(date -u '+%Y-%m-%d_%H:%M:%S')
# Build for multiple platforms
for OS in linux darwin windows; do
for ARCH in amd64 arm64; do
OUTPUT="myapp-${VERSION}-${OS}-${ARCH}"
if [ "$OS" = "windows" ]; then
OUTPUT="${OUTPUT}.exe"
fi
GOOS=$OS GOARCH=$ARCH go build \
-ldflags "-X main.Version=${VERSION} -X main.BuildTime=${BUILD_TIME}" \
-o $OUTPUT
echo "Built $OUTPUT"
done
done
Best Practices
โ Good Practices
- Always format code - Use
go fmtorgoimports - Run tests before committing - Use
go test -race - Use
go vet- Catch common mistakes - Cross-compile for target platforms - Test on actual OS
- Use build tags - Conditionally compile code
- Embed version info - Use
-ldflagsfor versioning - Run tests with race detector - Catch concurrency bugs
- Check coverage - Aim for high test coverage
โ Anti-Patterns
# โ Bad: Not formatting code
# Manual formatting is error-prone
# โ Bad: Ignoring test failures
# Always fix failing tests
# โ Bad: Not using race detector
go test # Missing -race flag
# โ Bad: Hardcoding version
# Use -ldflags instead
# โ Bad: Not running vet
# Always run go vet before committing
Resources and References
Official Documentation
- Go Command Documentation - Complete command reference
- Go Build Constraints - Build tags guide
- Go Testing Package - Testing documentation
Recommended Reading
- Effective Go - Best practices guide
- Go Code Review Comments - Code review guide
- Cross Compilation Guide - Platform-specific builds
Tools and Resources
- Go Playground - Online Go editor
- golangci-lint - Comprehensive linter
- Go Module Proxy - Official module proxy
Summary
The Go toolchain provides essential commands for development:
- go build - Compile programs
- go run - Run programs directly
- go test - Test packages
- go fmt - Format code
- go install - Install packages
- go vet - Analyze code
- go clean - Clean build artifacts
Master these commands for efficient Go development.
Comments