Streamline Go Project Builds with a Powerful Makefile
Learn how to use Makefile to automate compilation, testing, formatting, static analysis, dependency installation, and Docker image creation for Go projects, providing a concise, reproducible workflow that integrates smoothly with CI/CD pipelines.
1. Prerequisites
Familiarity with Makefile syntax.
Experience writing Go projects.
During development you often need to compile, run, test, format, or lint your code. While you can invoke go build, go run, go test, etc., directly, a Makefile lets you bundle these commands into short, repeatable targets.
2. Basic Makefile Syntax
PROJECT="example"
default:
@echo ${PROJECT}
install:
@govendor sync -v
test: install
@go test ./...
.PHONY: default install testThis minimal file demonstrates variable definition, a default target, a target that runs a command, a dependent target ( test depends on install), and the .PHONY declaration.
The general syntax is:
<target>: <prerequisites>
<commands> target: the name you invoke with make. prerequisites: other targets that run first. commands: shell commands executed for the target. .PHONY: marks non‑file targets. @: suppresses command echoing. #: comment. ${var}: variable expansion, similar to shell.
Wildcard patterns are supported.
3. Typical Go Project Commands go vet – static analysis. go test – run unit tests. go fmt – format source. go build – compile binaries. go run – compile and execute.
A Makefile for Go should expose these operations as separate targets: make default – compile. make fmt – format. make vet – static check. make test – run tests. make install – fetch dependencies. make clean – remove binaries.
4. Complete Example Makefile
BINARY="example"
VERSION=1.0.0
BUILD=`date +%FT%T%z`
PACKAGES=`go list ./... | grep -v /vendor/`
VETPACKAGES=`go list ./... | grep -v /vendor/ | grep -v /examples/`
GOFILES=`find . -name "*.go" -type f -not -path "./vendor/*"`
default:
@go build -o ${BINARY} -tags=jsoniter
list:
@echo ${PACKAGES}
@echo ${VETPACKAGES}
@echo ${GOFILES}
fmt:
@gofmt -s -w ${GOFILES}
fmt-check:
diff=$$(gofmt -s -d $(GOFILES)); \
if [ -n "$$diff" ]; then \
echo "Please run 'make fmt' and commit the result:"; \
echo "$$diff"; \
exit 1; \
fi
install:
@govendor sync -v
test:
@go test -cpu=1,2,4 -v -tags integration ./...
vet:
@go vet $(VETPACKAGES)
docker:
@docker build -t wuxiaoxiaoshen/example:latest .
clean:
@if [ -f ${BINARY} ]; then rm ${BINARY}; fi
.PHONY: default fmt fmt-check install test vet docker cleanThis file defines variables for the binary name, version, and build timestamp, lists packages, and provides targets for building, listing files, formatting, checking formatting, installing dependencies, testing, vetting, building a Docker image, and cleaning up.
5. CI/CD Integration (Travis CI Example)
language: go
go:
- "1.11"
- "1.11.x"
env:
- GO111MODULE=on
notifications:
email:
recipients:
- [email protected]
on_success: change
on_failure: always
before_install:
- go test -cpu=1,2,4 -v -tags integration ./...
- go vet $(go list ./... | grep -v /vendor/)
script:
- make fmt
- make fmt-check
- make vet
- make list
- go test -race ./... -coverprofile=coverage.txt -covermode=atomicIn production environments, the Makefile is typically invoked from CI pipelines to run tests, static checks, build Docker images, and push them to a registry, enabling continuous integration and deployment.
Go Development Architecture Practice
Daily sharing of Golang-related technical articles, practical resources, language news, tutorials, real-world projects, and more. Looking forward to growing together. Let's go!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
