Skip to main content
โšก Calmops

Go Toolchain: build, run, test, fmt

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

  1. Always format code - Use go fmt or goimports
  2. Run tests before committing - Use go test -race
  3. Use go vet - Catch common mistakes
  4. Cross-compile for target platforms - Test on actual OS
  5. Use build tags - Conditionally compile code
  6. Embed version info - Use -ldflags for versioning
  7. Run tests with race detector - Catch concurrency bugs
  8. 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

Tools and Resources

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