Swipe left or right to navigate to next or previous post

Makefile is a special text based file that is used by make utility. It automates the process of compiling and linking programs. It contains list of a command that can be quickly executed by running the corresponding make command. It contains sets of rules to build a target command or set of command. Makefile is easy to execute a long list of commands and functions using a single command.
Makefile are commonly used in software development projects to manage complex build processes.
The simple and high level syntax for Makefile target is as follows:
ruleA: ruleB ruleC
command1
command2
A Makefile mainly consists of a set of rules, each of which has a list of zero or more prerequisites, and then zero or more commands. At a very high level, when a rule is invoked, Make first invokes any prerequisite rules (if needed), which may have their own stanzas defined elsewhere) and then runs the designated commands.
The high level syntax with specific key word for Make target is as follows:
target: prerequisites
command
command
command
A target can be the name of the executable or an object file. It can also be the name of a rule or action.
A prerequisite is an action or file used as an input for the target. These files/actions need to exist before the commands for the target are run. These are also called dependencies. We can declare multiple dependencies for a target by separating them with blank space. Some rules may not require any dependencies.
A command is a single unit of work that needs to be done in order to make the target(s). These need to start with a tab character.
The basic example of the Makefile is:
say_hello:
echo make says hello
To install the GNU Make command, please run the following commands
sudo apt update
sudo apt install make
For other Distros, please follow GNU Make
To create the configuration file for make command, Just create the file name called Makefile without any file extensions
touch Makefile
To add contents in Makefile. Open the file with your favorite text editor and put make command as shown in the following example
say_hello:
echo "Hello world"
say_welcome:
echo "Welcome guys"
To run the make command, just type make followed with the rule name like say_hello or say_welcome. If you just type make command, the default rule will run. We will explore about default rule later in this post. If default rule is missing, it will run the first rule in the Makefile.
make {replace_with_command_from_the_make_file}
make say_hello
make say_welcome
runserver:
python manage.py runserver
makemigrations:
python manage.py makemigrations
migrate:
python manage.py migrate
createsuperuser:
python manage.py createsuperuser
By default, when we run the make command, the first rule is executed. To execute some other rules of our choice, we need to set .DEFAULT_GOAL variable in the Makefile. For example, if you want to execute runserver by default, define .DEFAULT_GOAL :=runserver. Now, when we run the make command, it will run the runserver command.
Alternately use can use default keyword. For example, if you want to execute runserver by default, define .default:runserver. Now, when we run the make command, it will run the runserver command.
.DEFAULT_GOAL :=runserver
runserver:
python manage.py runserver
makemigrations:
python manage.py makemigrations
migrate:
python manage.py migrate
createsuperuser:
python manage.py createsuperuser
build:
docker compose build;
test-build-nocache:
docker compose -f docker-compose.yml build --no-cache;
deploy:
docker-compose build
docker-compose up -d
run-server:
docker compose up;
test-run-server-d:
docker compose -f docker-compose.yml up -d;
migrations:
docker compose exec django python manage.py makemigrations;
migrate:
docker compose exec django python manage.py migrate;
shell:
docker compose exec django python manage.py shell;
down:
docker compose down;
Instead of typing the following commands one by one.
virtualvenv -p python3 venv
source venv/bin/activate
pip install -r requirements.txt
python3 manage.py makemigrations
python3 manage.py migrate
python3 manage.py collectstatic
python3 manage.py runserver
It would be easier to run something like that run all the above commands.
make start
Before that, let's learn about the creating and accessing the variables in the Makefile
Variables can be defined inside a Makefile to hold the information about files, arguments or even parts of the command. Variables are written in UPPER_CASE followed by colons and is equals to sign (:=) and its value. Generally, variables are declared at the top of the Makefile.
PYTHON:=python3.12
MANAGE:=venv/bin/python manage.py
ACTIVATE:=venv/bin/activate
# Django Configuration
PORT:= 8000
Variables that are declared in Makefile can be access as a part of the command. The variables can ve access using $ sign followed by curly braces like ${VARIABLE_NAME} where VARIABLE_NAME is the name of the variable whose value you want to access.
PYTHON:=python3.12
MANAGE:=venv/bin/python manage.py
ACTIVATE:=venv/bin/activate
# Django Configuration
PORT:= 8000
install: virtualenv
@echo "-> Installing Dependencies"
@${ACTIVATE} pip3 install -r requirements.txt
migrate:
${MANAGE} makemigrations
@echo "-> Apply database migrations"
${MANAGE} migrate
run:
${MANAGE} runserver ${PORT}
superuser:
@${MANAGE} createsuperuser
In this example, the ACTIVATE variable as been accessed using ${ACTIVATE}
VENV := venv
BIN := $(VENV)/bin
PYTHON := $(BIN)/python3
SHELL := /bin/bash
include .env
help: ## Show this help
@egrep -h '\s##\s' ${MAKEFILE_LIST} | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
venv: ## Make a new virtual environment
virtualvenv -p python3 venv && source ${BIN}/activate
install: venv ## Make venv and install requirements
${BIN}/pip install --upgrade -r requirements.txt
freeze: ## Pin current dependencies
${BIN}/pip freeze > requirements.txt
migrate: ## Make and run migrations
${PYTHON} manage.py makemigrations
${PYTHON} manage.py migrate
db-up: ## Pull and start the Docker Postgres container in the background
docker pull postgres
docker-compose up -d
db-shell: ## Access the Postgres Docker database interactively with psql. Pass in DBNAME={name}.
docker exec -it container_name psql -d ${DBNAME}
test: ## Run tests
${PYTHON} manage.py test application --verbosity=0 --parallel --failfast
run: ## Run the Django server
${PYTHON} manage.py runserver
start: install migrate run ## Install requirements, apply migrations, then start development server
The above Makefile contains .env as include .env. It was included to ensure the access to environment variables stored in an .env file. This allows Make to use these variables in its commands. For example, the name of virtual environment or to pass in ${DBNAME} to psql
“##” comment syntax in a Makefile gives you a handy description of command-line aliases you can look in to your Django project. It’s very useful so long as you’re able to remember what all those aliases are. The help command above, which runs by default, prints a helpful list of available commands when you run make or make help:
The help command above, which runs by default, prints a helpful list of available commands when you run make or make help:
help Show this help
venv Make a new virtual environment
install Make venv and install requirements
migrate Make and run migrations
db-up Pull and start the Docker Postgres container in the background
db-shell Access the Postgres Docker database interactively with psql
test Run tests
run Run the Django server
start Install requirements, apply migrations, then start development server
.PHONY is actually itself a target for the make command. It denotes labels that do not represent actual files of the project.
Look at the basic example of Makefile
install:
echo "installing dependencies"
Everytime when you run the make install command, it will execute the specified command from the Makefile (in our case echo "installing dependencies"). However, if we have the file name called install, the make command would bound to run the install file instead of the command in the Makefile. To override this behaviour, .PHONY is used to make install command to execute no matter of the presence of a file named build.
.PHONY: install
install:
echo "installing dependencies"