When you’re often working on large projects involving Golang, it’s often time consuming to keep typing the build and test commands go build xx
, go test xx
, repeatedly. And often these commands itself may become non-trivial.
Makefiles provide a very effective way to automate writing tasks for our application.
Let’s understand how we can easily set up our workflow using makefiles!
NOTE: While the make toolchain is widely popular, it is limited to only UNIX platforms. So if you’re using Windows, you may need to install a Linux environment inside Windows (such as msys
/ WSL
) to use make commands.
Using Makefiles in Go
The main functionality use-case for makefiles is to easily run different tasks using “tags”. Using tags, make TAGNAME
will simply run the task corresponding to TAGNAME
.
So let’s assume a sample program main.go
. If you want to build this file, you’d normally run this command:
go build main.go
And if you want to execute the program directly, you’d do this:
go build -o main.out main.go
./main.out
However, with a single makefile
, you can create 2 tasks build
and run
instead.
BINARY_NAME=main.out
build:
go build -o ${BINARY_NAME} main.go
run:
go build -o ${BINARY_NAME} main.go
./${BINARY_NAME}
clean:
go clean
rm ${BINARY_NAME}
Now, you can run the build
and run
tasks like this:
make build
make run
If you want to add a default tag which would call the necessary tasks, we can use the all
tag:
BINARY_NAME=main.out
all: build test
build:
go build -o ${BINARY_NAME} main.go
test:
go test -v main.go
run:
go build -o ${BINARY_NAME} main.go
./${BINARY_NAME}
clean:
go clean
rm ${BINARY_NAME}
This will now build and test our main.go
program, when we run:
make
See how much easy our work has now become? That’s why these build toolchains are extremely useful!
Notice that you can use shell variables in makefiles. The variable BINARY_NAME
is actually main.out
, so the dollar sign will perform the variable substitution.
And the best part is that you don’t need to stop here. You can run as many complex tasks as you need.
For example, if your project has multiple dependencies that you need to install using go get package-name
, you could automate that too!
We could create a separate task called deps
, which will install all the relevant packages directly.
For instance, if my project needs the Gorilla websocket library, I could have a task like this:
deps:
go get github.com/gorilla/websocket
And when I run:
make deps
All dependencies get installed.
Hopefully this post gives you an idea of how you could automate build tasks and setup your Golang project workflow quickly. Until next time!