Makefile: Simplifying Command Execution and Automation

Mohammad Roshandelpoor
4 min readFeb 11, 2024

Makefile is a powerful tool that allows us to streamline our command execution and automate repetitive tasks. It acts as both documentation and an executable script, making managing and sharing our project’s commands easier. In this article, we’ll explore the concept of Makefile and how it can simplify our development workflow.

What is Makefile, and How Does it Work?

Makefile is a file that resides in the project’s root directory and contains a set of rules, each consisting of a target and a recipe. The target represents a command or a set of commands, while the recipe specifies the actions to be performed when the target is executed. Makefile is executed using the make utility, which reads the Makefile and executes the specified targets.

The Makefile syntax is straightforward. Each rule follows the structure:

Makefile Format File

target: prerequisites
recipe

The target is the command's name, and the prerequisites are the commands that should be executed before the target. The recipe contains the actual commands to be executed.

Installation and Setup

Before we dive deeper into Makefile, let’s ensure that we have it installed on our system. Most Unix-based systems come with Makefile pre-installed. To check if Make is installed, open your terminal and run the following command:

make -v

If Make is not installed, you can install it using the package manager of your operating system. For example, on Ubuntu, you can run:

sudo apt-get install build-essential

Once Make is installed, we can start using Makefile in our projects.

Creating Your First Makefile

To demonstrate the power of Makefile, let’s consider a simple scenario where we have a PHP project running in a Docker container. We want to simplify the process of running the project’s commands using Makefile.

Create a Makefile: In the root directory of your project, create a file named Makefile.

Define Variables: Define variables at the beginning of the Makefile to make your commands more flexible and reusable. For example:

PHP = php
DOCKER_COMPOSE = docker-compose

Define Targets: Define targets in your Makefile, each representing a command or a set of commands. For example:

serve:
$(DOCKER_COMPOSE) exec php $(PHP) -S localhost:8000 -t public

The serve target runs the PHP built-in server inside the Docker container, serving the project on localhost:8000.

Execute Targets: Save the Makefile and open your terminal. Navigate to the project’s root directory and run the following command:

make serve

This will execute the serve target defined in the Makefile, starting the PHP server in the Docker container.

By using Makefile, we have simplified the process of running commands in our project. Instead of typing lengthy Docker commands, we can now execute them with just a single word, making our development workflow more efficient.

Advanced Usage and Best Practices

Let’s explore some advanced usage and best practices to make the most out of Makefile.

1. Organizing Commands with Targets

Makefile allows you to organize your commands into logical groups using targets. Each target can represent a specific task or a set of related commands. For example, you can have targets for building the project, running tests, deploying to a server, and more.

By breaking down your commands into targets, you can easily execute specific tasks without remembering complex command sequences. It also improves code readability and makes it easier for other team members to understand and contribute to the project.

2. Managing Dependencies with Prerequisites

In Makefile, you can define prerequisites for each target. Prerequisites are other targets that need to be executed before the current target. This ensures that the commands are executed in the correct order and that dependencies are properly managed.

For example, if you have a target to deploy your project to a server, you can define prerequisites such as building the project, running tests, and packaging the code. Makefile will automatically execute the prerequisites before executing the target, ensuring that all necessary steps are completed.

3. Using Variables for Flexibility

Variables in Makefile allow you to define values that can be reused throughout your commands. This provides flexibility and makes it easier to update values across multiple targets.

For example, you can define a variable for the PHP binary path and use it in multiple targets:

PHP = /usr/bin/php

lint:
$(PHP) -l src/

Using variables, you can easily update the PHP path if it changes or use different paths for different environments.

4. Creating Default Targets

Makefile allows you to define a default target that is executed when you run make without specifying a target. This is useful when you have a common task that should be executed by default.

To create a default target, simply add the target name at the beginning of your Makefile:

all: build

build:
# Build commands...

test:
# Test commands...

In this example, the all target is set as the default target. When you run make, it will execute the build target.

5. Generating Documentation with Makefile

Makefile can also be used to generate documentation for your project. By defining targets and recipes to generate documentation files, you can automate the process and ensure that your documentation is always up-to-date.

For example, you can have a target to generate API documentation using tools like Doxygen or Swagger:

docs:
doxygen Doxyfile
swagger generate spec -o docs/swagger.json

By running make docs, you can automatically generate the API documentation, making it easier for developers to understand and work with your project.

Conclusion

Makefile is a powerful tool that simplifies command execution and automates repetitive tasks in your development workflow. By organizing your commands into targets, managing dependencies, and using variables, you can streamline your project’s processes and make them more efficient.

Feel free to Subscribe for more content like this 🔔, clap 👏🏻 , comment 💬, and share the article with anyone you’d like

And as it always has been, I appreciate your support, and thanks for reading.

--

--

Mohammad Roshandelpoor

Software Engineer | Laravel | PHP | Nuxt | Vue | with over 10 years of experience, have a deep understanding of software architecture