Use of 'Empty Target' in makefile
Categories:
Understanding and Using 'Empty Targets' in Makefiles

Explore the concept of empty targets in GNU Make, their purpose, and how to effectively use them to manage dependencies and force command execution.
In the world of C/C++ development, Makefiles are indispensable for automating build processes. GNU Make, in particular, offers a rich set of features to manage complex projects. Among these features, 'empty targets' might seem counter-intuitive at first glance, but they serve crucial roles in specific scenarios. This article will demystify empty targets, explain their utility, and provide practical examples of when and how to use them effectively.
What is an Empty Target?
An empty target in a Makefile is a target that has no commands associated with it and typically no prerequisites that would cause it to be rebuilt. Its primary characteristic is that it doesn't create a file with its name. When Make encounters an empty target, it considers it 'up-to-date' if no prerequisites are newer, or if it's explicitly marked as phony. However, the true power of empty targets often lies in their use as prerequisites for other targets, especially when combined with the .PHONY
directive or when used to force command execution.
empty_target:
.PHONY: empty_target
A basic empty target, often declared as PHONY.
.PHONY
, declaring it as .PHONY
is a good practice to prevent Make from looking for a file named empty_target
and to ensure it's always considered 'out-of-date' when invoked directly, or when its prerequisites are newer.Use Cases for Empty Targets
Empty targets are particularly useful in two main scenarios: forcing command execution and managing dependencies for targets that don't produce files. Let's explore these in detail.
flowchart TD A[Start Build] --> B{Target Invoked?} B -->|Yes| C{Is Target a File?} C -->|Yes| D{File Exists?} D -->|Yes| E{Prerequisites Newer?} E -->|Yes| F[Execute Commands] E -->|No| G[Target Up-to-date] D -->|No| F C -->|No, PHONY or Empty| F F --> H[End Build] G --> H
Decision flow for Make target execution, highlighting how empty/PHONY targets bypass file existence checks.
1. Forcing Command Execution (The 'Always Rebuild' Pattern)
One of the most common uses for empty targets is to force a set of commands to run every time a particular target is invoked, even if no files have changed. This is often achieved by making a 'real' target depend on an empty, phony target. The empty target acts as a trigger, ensuring its commands (or the commands of the target depending on it) are always executed.
clean:
rm -f *.o *.exe
.PHONY: clean
# Example of an empty target used to force a rebuild
force_rebuild:
.PHONY: force_rebuild
all: force_rebuild main.exe
main.exe: main.o
gcc -o main.exe main.o
main.o: main.c
gcc -c main.c
Using a PHONY empty target force_rebuild
to ensure all
always triggers a check of its dependencies.
In this example, force_rebuild
is an empty, phony target. When all
is invoked, force_rebuild
is always considered out-of-date (because it's PHONY), which in turn forces all
's commands (or its other prerequisites) to be considered. While force_rebuild
itself has no commands, its presence as a prerequisite ensures that main.exe
's dependencies are always checked, and main.exe
is rebuilt if main.o
is newer, or if main.o
itself needs rebuilding. This pattern is less common for simple builds but can be useful in more complex scenarios where a target needs to always run some setup or check before its actual work.
2. Managing Dependencies for Non-File-Producing Targets
Many Makefile targets, like clean
, install
, or test
, do not produce a file with their name. If these targets were not declared as .PHONY
, Make would check for the existence of a file named clean
, install
, or test
. If such a file existed, Make would consider the target up-to-date and would not execute its commands. Declaring these as .PHONY
(which is essentially making them empty targets in the sense that they don't represent files) ensures their commands always run when invoked directly.
all: program
program: main.o helper.o
gcc -o program main.o helper.o
main.o: main.c
gcc -c main.c
helper.o: helper.c
gcc -c helper.c
clean:
rm -f *.o program
.PHONY: all clean
Common use of .PHONY
for clean
and all
targets, making them behave like empty targets that don't correspond to files.
Here, clean
is an empty target in the sense that it doesn't create a file named clean
. By declaring it .PHONY
, we tell Make not to look for a file named clean
and to always execute its commands when make clean
is run. This is the most prevalent and important use case for the concept of 'empty targets' in practice.
.PHONY
special target is crucial for empty targets that represent actions rather than files. It prevents conflicts with actual files that might share the same name as a target and ensures the target's commands are always executed when invoked.