Makefiles use so-called rules with the following format:
target: prerequisite(s)command(s)
A target is normally the file we want to create.
A prerequisite is another target (normally another file) which is required to exist before we can create the file.
The command(s) are the shell commands which create the target (once again, the file we want to create).
The "target-prerequisites" line starts at the beginning of the line, while the "commands" line always has to start with a TAB.
Note: If the target (the file) already exists and is considered up to date (Makefile term explained later), the commands will NOT be executed, but instead the following message will be shown:
Even if make mainly is a software compilation tool, in this example we will focus on how file depends on each other (targets and their prerequisites) without invoking a compiler.
Let say we want to create 3 files (independently from each other) called hello.txt, doyoulikemake.txt, and bye.txt, and then display their contents.
To do this using a makefile, we should type:
make hello.txt
make doyoulikemake.txt
make bye.txt
In this case, the targets are hello.txt, doyoulikemake.txt, and bye.txt, respectively.
They will be created independently (no other files need to exist to create them), so there are no prerequistes needed for these targets.
Let's start with the following Makefile (create it in an empty directory):
hello.txt:
@echo "Hello, world!" > hello.txt@cat hello.txtdoyoulikemake.txt:
@echo "Do you like make?" > doyoulikemake.txt@cat doyoulikemake.txtbye.txt:
@echo "Bye, see you later." > bye.txt@cat bye.txt
Type
$ make hello.txt
and you will see
Hello, world!
Type
$ make hello.txt
again (and again) and you will see
make: `hello.txt' is up to date.
Generally speaking, make considers a target up to date if the following two conditions are fulfilled: a. the target exists. b. the target is newer than its prerequisites.
When a target has no prerequisites, as in the example above, condition b. is always fulfilled.
In such cases, it is sufficient for a target to exist to be considered up to date.
So if we want to see the file contents again (by executing the rule commands), we have to remove hello.txt, or the commands will not be executed.
Let's add a rule with a target called clean for removing the text files:
clean:
rm -rf hello.txt doyoulikemake.txt bye.txt
The name of the target is clean, but there is no existing file called clean, nor will it be created by the rule command.
Imagine that a file called clean was created by mistake (with touch clean, for example).
That would imply that both the conditions a. and b. always are fulfilled (the target clean exists, so condition a. is fulfilled, and it has no dependencies, so condition b. is always fulfilled), which in turn would imply that the rm command would never be executed. This is not what we wanted.
To avoid this to happen, we will create a so-called phony target.
A phony target forces the command(s) in a rule to always be executed.
This is how the modified phony target clean looks like:
There is a problem with the targets hello.txt, doyoulikemake.txt, and bye.txt - when these targets are up to date (when they exist), the file contents isn't displayed.
With our new target clean we could always type
make clean hello.txt
to force the files to be deleted before we create them again, but it is not an elegant solution.
A better solution is to let the command of each rule only create the target, and create a new rule to display the target file contents.
We always want to display the contents, so the commands for the new rule should always be executed.
This means the new rule should be a phony rule.
To display the contents of the target files, they must obviously exist.
This means that the new rule will depend on the target files, they will be prerequisites for the new rule.
Let's call the new rule display:
Read the rule above as:
"Always execute this rule (it is phony), but before doing so, create the prerequisites hello.txt, doyoulikemake.txt, and bye.txt if they did not exist already. Then display the contents of the files with cat."
A modified target rule will look like this (the second command is just used to show when the target is created):
Now play around with make, make clean, make display, make hello.txt, and make doyoulikemake.txt clean bye.txt display, and be sure you understand how they interact.
Exercise:
If the target name appears in a rule, it can be replaced by the automatic variable$@.
Replace target names wherever it is possible with $@.