Stop Copy-Pasting Old Scripts, Use Makefile Instead!

Mario Gunawan
3 min readSep 13, 2022

Imagine this, you have a project with a lot of scripts and the way you do it is by putting it in a markdown file then copy pasting it all over again to your terminal. Wouldn’t it be better if there’s a way to simplify this process?

Introduction

Makefile is a way to group your terminal commands into one group which we usually calls “target”. A target consists of several commands to be executed in order from top to bottom and stops whenever there is an error output from a command. In windows, you actually need to install makefile in windows.

Why it’s good

Now imagine this, you have some commands that you must start everytime a person comes into your project. Let’s say, there are some bundles of commands in your projects like this:

## Initial Setup
pip install virtualenv
python3 -m venv /path/to/new/virtual/environment
cp .env.example .env
## Start
py app.py
## To create this to the service
cp something.service /etc/systemd/service
systemctl start something.service

This setup might not be a problem at first, but as your project grows and you add more scripts to be run, you might start to notice that it’s better to bundle this service so that you could run it all at once, and that’s what Makefile is all about!

In make, you only need to run make setup in the terminal for the initial setup, make start for the starting and make add_service to create the service. It’s so much easier that it’s mindblowing that some experienced developers still doesn’t use it for scripting.

When to Use It

As stated before, the best way to determine you need to start building your makefile is when your project grows. When there are a lot of scripts which depends on each other and needs to be run in order, makefile will be your best friend.

Let’s Start Building it

The syntax for makefile is pretty easy. Let’s assume we are building a python project like above. A makefile that do the scripts might look like this: (The filename is just Makefile without any file extensions)

all: startsetup:
pip install virtualenv
python3 -m venv /path/to/new/virtual/environment
cp .env.example .env
start:
py app.py
add_service:
cp something.service /etc/systemd/service
systemctl start something.service

Now, all you need to run is make <target> in which the target is the grouping name like “start”, or “add_service”. You might notice that the first target is all and it doesn’t have any body but have start beside it. The first target of a makefile will be the default target. (regardless of naming, but all is the convention)

What about the start beside it? This, we calls prerequisites. It means that before running a certain target, you must run this set of target(s) first. Let’s say for example we want to split the setups:

install_venv:
pip install virtualenv
setup_venv:
python3 -m venv /path/to/new/virtual/environment
copy_dotenv:
cp .env.example .env

Now this could be bundled into one target that looks like this:

setup: install_venv setup_venv copy_dotenv

Which could make it even more verbose if you wanted that. Another useful thing is you can also declare variables using := syntax:

...
main_file := main.py
start:
py $(main_file) # or py ${main_file}
py $(main_file) # or py ${main_file}

--

--

Mario Gunawan

I'm a passionate mobile / web developer. Writing articles about software development, mainly about flutter and react.