Automating workflows with Makefiles
Tags: go, web3, etherium, ganache
Published: 2022-07-30 15:54:27

**Make** is a Unix utility that can be used to build and maintain groups of programs (and other types of files) from source code. It is accessible as `make` command in unix shells. When running the command for automation, you need to provide a **Makefile**. The utility is traditionally used for compiling code (C/C++), but they can also be used to automate common commands.

A Makefile will contain a set of rules that can get you up and running within no time. It saves time and effort therefore improving the overall productivity of a team. We will look at the important pieces that accelerates automation with Makefiles.

To begin with, there are two pieces in this equation: The `make` commandline tool and the Makefile. So far, we need to be aware that a **Makefile** contains automation rules while make tool executes them.

### Example Golang Automation: Simple Smart Contract App
The  [Golang](https://go.dev/) project we will work on has a couple of iterative tasks. For instance, in-order to execute a task, a programmer has to type very long commands on the terminal. One annoying thing is that executing these might be iterative, therefore, exhausting. In this episode, we will automate the following tasks.
- Format code
- Running tests
- Compiling smart contracts
- Building binaries
- Setting up dependencies 

Our center of interest will be automating the processes above using Makefiles. However, we will first take a moment to learn G 

## Makefiles
A Makefile structure  resembles that of a `YAML` file and uses a declarative paradigm.

###  Syntax of a makefile
A Makefile has a pretty simple syntax. Once you have some basic programming knowledge, you can become the Zeus of Makefiles. The anatomy is basically a declarative format as follows:

```YAML
target: dependencies
    command
    command
    command
``` 

- **target** - Name of an action we would like to carry out. 
- **dependencies** - These are optional set of rules/targets that need to be executed first. They are only included when the target will need them.
- **Commands** - These are usually written after a tab. They are the commands that the user wants to automate. 

### Executing a makefile
As mentioned, we use the `make`command. It takes in a parameter of the target that we would like to run. 
Eg. 

```BASH
$ make # run the default/main target
$ make clean
$ make test
``` 

### Basic Syntax
#### Comments
Comments are written using `#`. The statements after the comment symbol will be ignored by the parser

```YAML
# This is a comment
``` 
#### Standard output
The `@` symbol is used to disable displaying the output to stdout. This is only used when the user does not want the output to be visible on the terminal. For instance, check the target **mute** below.

```YAML
hello: # Target that prints 
  echo "Hello World" # Prints Hello World to the Screen

mute: # Target that does not print
  @echo "Hello World" # No output
``` 

#### Variables
Setting a variable in a Makefile is done using `=` symbol. It takes the format `VARIABLE = value`. The example below shows declaring a variable `GOVERSION`.

```YAML
GOVERSION = 1.19 
``` 
*Variable setting example 1.0*
```YAML
HELLO = 'hello'
HELLO_WORLD = $(HELLO) world  # hello world
``` 
*Variable setting example 1.1*

To expand the value of `HELLO_WORLD` during assignment, we use the symbols `:=`

```YAML
HELLO = 'hello'
HELLO_WORLD = $(HELLO) world  # hello world

HELLO = 'hi' # change the value of the greeting
HELLO_WORLD := $(HELLO) world  # hello world
``` 
Variables can be accessed using either `$()` or `${}` syntax as shown in the example above.

### Targets
Basically, we can consider targets to be named routines in a makefile. In Makefiles, the target `all` is run by default.

#### The all target
Making multiple targets and you want all of them to run? Make an `all` target.
```YAML
all: setup compile # Installs dependencies and compiles

setup:
	go mod download # Downloads dependencies

compile:
	go build -o ./bin/app # Compile the source

clean:
	rm -f ./bin/app # Deletes the binary
``` 

#### Executing the targets
Now that we have automated a simple workflow. Let's see how to run it. The following terminal snapshot explains.

```BASH
$ make # The target all will be executed
$ make setup # This will only run setup target
$ make compile # This will only run compile target
``` 
#### Defining a custom default target
At times, we might not want want to use the `all` target. This is a proof that makefiles are very customisable to meet one's tastes. To define a custom default target, we reassign the `.DEFAULT_GOAL` variable by giving it a value of the new target that should run by default.

```YAML
.DEFAULT_GOAL := hello

hello:
 echo "Hello World"
``` 


## PART II
In the next chapter, I will summarise by automating a real-life Golang project, talk about the usecases and best practises when using Makefiles. 

## Appreciation
Thank you for reaching here. Please share your comments and reach out to me on [Twitter](https://twitter.com/oyamokt)