Skip to content
VLSI Mentor

Makefile · Part I · Module 2 · Rules and Dependencies

Targets, Rules and Recipes

Module 1 showed you the shape of a rule and how Make decides whether to run one. This chapter goes underneath that shape. A target is a name, and Make resolves it in one of three ways; a recipe is a list of commands that Make never inspects. The gap between those two facts is where a specific and very common bug lives — a rule whose recipe succeeds, reports nothing wrong, and never finishes its job.

Foundation18 min readMakefileGNU MakePart IRulesTargets

Part I · Module 2 · Chapter 2.1 · Targets, Rules and Recipes

1. A Target Is a Name, Not a Command

Start with a question that sounds trivial and is not: when you type make report.txt, what is report.txt?

It is a name you are asking Make to resolve. It is not a command, and Make does not assume it is a file either. Make takes the name and looks for two separate things: a rule whose target is that name, and a file on disk with that name. What it finds decides what happens, and there are three possible answers.

Set up a directory with two ordinary files and one rule to see all three. Create ports.txt and clocks.txt:

Azvya Education Pvt. Ltd.VLSI Mentor
ports.txt
clk
rst_n
wr_en
Azvya Education Pvt. Ltd.VLSI Mentor
clocks.txt
clk 100MHz
clk_div 50MHz
Azvya Education Pvt. Ltd.VLSI Mentor
Makefile
report.txt: ports.txt clocks.txt
	@echo "building report.txt"
	@echo "ports:" > report.txt
	@cat ports.txt >> report.txt
	@echo "clocks:" >> report.txt
	@cat clocks.txt >> report.txt

Build it once so report.txt exists, then ask Make for three different names:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
make report.txt
make nothing
make ports.txt
make report.txt
Azvya Education Pvt. Ltd.VLSI Mentor
Representative output — Make 3.x quotes names differently from 4.x
building report.txt
make: *** No rule to make target 'nothing'.  Stop.
make: Nothing to be done for 'ports.txt'.
make: 'report.txt' is up to date.

Four commands, and the last three are Make's three answers to "what is this name?"

What Make findsWhat it saysWhat it means
no rule and no fileNo rule to make targetthe name is meaningless here
a file, but no ruleNothing to be done forthe file exists and nothing can produce it, so there is nothing to do
a file and a ruleruns the recipe, or is up to datethe normal case: Make can decide

The middle row is the one most people have never seen. ports.txt exists, and no rule in the Makefile says how to produce it, so Make shrugs: the thing you asked for is already there and it has no way to make it anyway. That is not an error — it is the honest answer.

Understanding this resolution is what lets you read an unfamiliar error. No rule to make target is almost never a broken rule; it is a name Make could not account for — a typo, a file that was supposed to be generated by a rule somebody deleted, or a prerequisite that does not exist.

2. What the Three Parts Declare

Chapter 1.2 introduced the shape. Here is what each part declares, stated precisely, because the precision is what the rest of this chapter needs.

Azvya Education Pvt. Ltd.VLSI Mentor
The declaration
target: prerequisite1 prerequisite2
	command
	command

The target declares a name that this rule can produce. If that name corresponds to a file, the rule is promising to create or update that file. Make takes the promise at face value.

The prerequisites declare what must be up to date first. They are names too, resolved exactly the way §1 described — which is why a prerequisite can be a plain file, or another target with a rule of its own.

The recipe declares the commands to run. And here is the part worth stating bluntly: Make never reads the recipe. It does not parse it, does not look for filenames in it, and cannot tell whether the commands have anything at all to do with the target. The recipe is an opaque list of strings handed to a shell.

Those three sentences together produce the central fact of this chapter. The relationship between the target name and what the recipe actually does is asserted by you and never checked by Make.

3. A Rule With No Prerequisites

The simplest rule has a target and a recipe and nothing after the colon:

Azvya Education Pvt. Ltd.VLSI Mentor
Makefile
hello:
	@echo "Hello from a Make recipe."
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
make hello
Azvya Education Pvt. Ltd.VLSI Mentor
Actual output
Hello from a Make recipe.

Nothing named hello is ever created, so the name never resolves to a file, so there is never anything up to date. The recipe runs every time. That is the whole mechanism behind a target like clean or run.

The absence of prerequisites says something specific: this rule depends on nothing. For an action that is honest. For a rule that produces a file it is usually a bug, and Chapter 1.3 §5 showed the stale output it causes.

4. One Prerequisite, and Many

A prerequisite list is just that — a list, separated by spaces:

Azvya Education Pvt. Ltd.VLSI Mentor
One prerequisite
summary.txt: report.txt
	@wc -l < report.txt | tr -d ' ' > summary.txt
Azvya Education Pvt. Ltd.VLSI Mentor
Two prerequisites
report.txt: ports.txt clocks.txt
	@echo "building report.txt"
	@echo "ports:" > report.txt
	@cat ports.txt >> report.txt
	@echo "clocks:" >> report.txt
	@cat clocks.txt >> report.txt

The §1 Makefile already had the two-prerequisite form. Build it, touch one input, and the rule runs:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
make report.txt      # up to date
touch clocks.txt
make report.txt
Azvya Education Pvt. Ltd.VLSI Mentor
Actual output
building report.txt

Any one prerequisite being newer is enough, and the recipe is all-or-nothing — Make runs the whole thing or none of it. There is no partial rebuild and no attempt to work out which input changed. Chapter 2.3 takes that decision apart properly.

What matters structurally is that the prerequisite list is a statement about requirements, not an ordering instruction and not documentation. Chapter 2.4 returns to that distinction, because people often write a prerequisite when what they wanted was "run this first".

5. The Target Name Is a Promise

Now the case that explains why §2 insisted Make never reads a recipe. Here is a rule that is wrong in a way no error message will tell you about:

Azvya Education Pvt. Ltd.VLSI Mentor
Makefile — the target and the recipe disagree
report.txt:
	@echo "pretending to build report.txt"
	@echo "data" > summary.txt

Read it carefully before running it. The target says report.txt. The recipe writes summary.txt. Nothing in the Makefile connects those two names, and Make has no opinion about it.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
make report.txt
Azvya Education Pvt. Ltd.VLSI Mentor
Actual output
pretending to build report.txt

Exit status zero. No warning. Now look at the directory and run it again:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
ls
make report.txt
make report.txt
Azvya Education Pvt. Ltd.VLSI Mentor
Actual output
Makefile	summary.txt
pretending to build report.txt
pretending to build report.txt

report.txt was never created, and the rule runs every single time. Make did exactly what its four steps require: step 3 looked for a file called report.txt, did not find one, and concluded the target needed building. Step 4 ran the recipe. The recipe succeeded. Step 3 will reach the same conclusion on the next run, and the next, forever.

Fix the recipe so it writes the name it promised:

Azvya Education Pvt. Ltd.VLSI Mentor
Makefile — corrected
report.txt:
	@echo "building report.txt"
	@echo "data" > report.txt
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
make report.txt
make report.txt
Azvya Education Pvt. Ltd.VLSI Mentor
Representative output
building report.txt
make: 'report.txt' is up to date.

One run builds, the second does nothing. The only change was making the file the recipe writes match the name the target declared.

Two rows compared. Top row: declared target report.txt, and beside it the file the recipe actually writes, summary.txt, marked as a mismatch that makes Make re-run the rule every time. Bottom row: declared target report.txt, and beside it the file the recipe writes, also report.txt, marked as matching so Make can skip the rule.report.txtdeclared targetsummary.txtrecipe writes thisreport.txtdeclared targetreport.txtrecipe writes this12
Figure 1 — the same rule shape with and without the promise kept. In the top row the recipe writes a different filename, so the declared target never appears on disk and Make re-runs the rule on every invocation. In the bottom row the names agree, the file appears, and Make can finally answer 'up to date'. Make compares only the declared name against the filesystem; it never inspects the recipe to notice the difference.

This failure has a recognisable signature in a real flow: a step that never stops re-running. If a compile repeats on every invocation even though nothing changed, the first thing to check is whether the file the compiler actually produces is the file the target names — a different directory, a different extension, or an output option pointing somewhere else.

6. Several Rules in One Makefile

A Makefile is a set of rules, and Make selects among them by target name. Nothing else about their arrangement matters — not adjacency, not grouping, not order (except for the default goal, which is Chapter 2.4).

Azvya Education Pvt. Ltd.VLSI Mentor
Makefile
report.txt: ports.txt clocks.txt
	@echo "building report.txt"
	@echo "ports:" > report.txt
	@cat ports.txt >> report.txt
	@echo "clocks:" >> report.txt
	@cat clocks.txt >> report.txt

summary.txt: report.txt
	@echo "building summary.txt"
	@wc -l < report.txt | tr -d ' ' > summary.txt

hello:
	@echo "Hello from a Make recipe."

Three rules, three independent names. Ask for any one of them and Make resolves only that name and whatever it needs:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
make hello          # runs one recipe; report.txt and summary.txt untouched
make summary.txt    # builds report.txt first, because summary.txt needs it

summary.txt names report.txt as its prerequisite, so asking for the second builds the first. hello is connected to nothing, so nothing connects to it. A Makefile is a graph of names, and the rules are the edges you drew.

7. Files and Actions Are Structurally Different

By now the split should be visible in the examples themselves, so it is worth naming before Chapter 2.2 handles it properly.

a rule whose target names a filea rule whose target names an action
after a successful runthe file exists on disknothing on disk records it
on the next runMake can compare and skipMake must run it again
prerequisites area real requirementoften none, or a list of things to do first
examplesreport.txt, build/sim.imghello, run, clean, test

Both are ordinary rules — there is no separate syntax, and Make does not have two kinds of target internally. The difference is entirely whether a file by that name appears. That is also why an action target is fragile: if a file by that name does appear, the rule stops working, and that is exactly the problem Chapter 2.2 solves.

8. An RTL-Shaped Build

Now a structure closer to real work: three source files, one compiled artifact in a build directory, and one action that uses it.

The version below is portable and was executed — it stands in for a simulator by concatenating the sources into an artifact, so you can run every command yourself:

Azvya Education Pvt. Ltd.VLSI Mentor
Makefile — portable stand-in, executed as shown
build/sim.img: src/alu.v src/regfile.v src/tb_top.v
	@echo "compiling 3 sources into build/sim.img"
	@mkdir -p build
	@cat src/alu.v src/regfile.v src/tb_top.v > build/sim.img

run: build/sim.img
	@echo "running the simulation image (stand-in for a simulator)"
	@wc -l < build/sim.img | tr -d ' '

With three small .v files under src/:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
make run
Azvya Education Pvt. Ltd.VLSI Mentor
Actual output
compiling 3 sources into build/sim.img
running the simulation image (stand-in for a simulator)
8

Two rules ran because run needs build/sim.img and that file did not exist. Run it again:

Azvya Education Pvt. Ltd.VLSI Mentor
Actual output
running the simulation image (stand-in for a simulator)
8

The compile was skipped and the run repeated — the two behaviours from §7, side by side in one command. Now edit src/alu.v and ask again:

Azvya Education Pvt. Ltd.VLSI Mentor
Actual output
compiling 3 sources into build/sim.img
running the simulation image (stand-in for a simulator)
9

The edit made a prerequisite newer than the artifact, so the artifact was rebuilt, and the action that follows it ran against the new one.

It is worth walking that first run through Make's four steps once, because every later chapter assumes you can do this in your head:

StepWhat Make doesResult on the first run
1resolve the name runa rule exists; no file called run
2bring run's prerequisites up to dateone prerequisite, build/sim.img — recurse into it
2aresolve build/sim.imga rule exists; the file does not
2bits prerequisites are the three sourcesall three exist and nothing can produce them, so they are up to date
2cdecide for build/sim.imgthe target is missing, so build it — the compile message prints
3decide for runno file named run exists, so it is never up to date
4run run's recipethe simulation message prints

On the second run only steps 2c and 3 answer differently: build/sim.img now exists and nothing is newer, so its recipe is skipped, while run still names no file and so still executes.

Two details in that Makefile are worth pointing out, because both are deliberate:

The target is a path. build/sim.img is a perfectly ordinary target name that happens to contain a directory. Make compares the file at that path; it does not care that it is nested. The mkdir -p build in the recipe exists because Make does not create directories for you — it only checks and runs.

The sources are named twice. Once after the colon, where they make the rebuild work, and once in the command, where they do the work. Keeping those two lists in step by hand is a real maintenance cost; the mechanism that removes the duplication is an automatic variable, which is Chapter 3.3.

The simulator version of the same two rules looks like this. It is illustrative — vcs is a commercial tool that is not installed here, so unlike every other transcript in this chapter it was not run:

Azvya Education Pvt. Ltd.VLSI Mentor
Makefile — illustrative; vcs was not executed
build/simv: src/alu.v src/regfile.v src/tb_top.v
	mkdir -p build
	vcs -full64 -sverilog src/alu.v src/regfile.v src/tb_top.v -o build/simv

run: build/simv
	./build/simv -l run.log

Compare it line for line with the portable version and the structure is identical. And note what the target name promises: -o build/simv must write exactly the path the target declared. Point the simulator's output option somewhere else — a different directory, or the default simv in the current directory — and you get §5's bug with a twenty-minute compile attached to it.

9. Common Mistakes

Writing a command as the target. The target is a name, so a rule like compile report.txt: declares two targets called compile and report.txt, not a command with an argument. Make will accept it and behave in a way you did not intend.

Assuming Make checks the recipe. It does not, ever. A mismatch between the target name and the file the recipe writes produces §5's silent re-run. A recipe that writes nothing at all behaves the same way.

Expecting a directory to be created. build/sim.img as a target does not make build/ exist. If the recipe does not create the directory, the redirect fails and the rule errors out.

Thinking a name must be a file. No rule to make target and Nothing to be done for are different answers to different situations (§1). The first means Make cannot account for the name at all; the second means the name is a file it cannot and need not produce.

Letting a generated file sit in the source tree without a rule. If report.txt was once generated by a rule that has since been deleted, make report.txt reports Nothing to be done and the stale file stays forever, looking authoritative.

10. Check Your Understanding

Question 1. A Makefile has a rule for coverage.rpt. You run make coverage.rpt twice; the first run prints a build message and the second prints the same build message again. The recipe exits zero both times. What is the most likely cause, and which single command confirms it?

Question 2. make src/alu.v prints Nothing to be done for 'src/alu.v'. Is that an error? What are the two facts about src/alu.v that produce exactly this message?

Question 3. A rule reads build/sim.img: src/alu.v and its recipe is a single cat src/alu.v > build/sim.img. The build directory does not exist. What happens, and whose fault is it — Make's or the recipe's?

Question 4. In §6's Makefile, make hello leaves report.txt and summary.txt untouched even though all three rules are in the same file. Why?

11. Exercise

Here is a Makefile that is meant to write a compile filelist into a build/ directory and then count its entries. It contains two separate mistakes from this chapter.

Azvya Education Pvt. Ltd.VLSI Mentor
Makefile — two bugs
build/filelist.f: src/alu.v src/tb_top.v
	@echo "writing the filelist"
	@echo "src/alu.v" > filelist.f
	@echo "src/tb_top.v" >> filelist.f

check: build/filelist.f
	@echo "filelist has this many entries:"
	@wc -l < build/filelist.f | tr -d ' '

Before running it, write down: what does make check print, what does it leave on disk, and what exit status does make return?

12. Remember

  • A target is a name Make resolves, and it has three possible answers: no rule and no file (No rule to make target), a file with no rule (Nothing to be done for), or a file with a rule (build it or report it up to date).
  • Make never reads a recipe. It cannot see which files the commands touch, so the link between a target's name and what the recipe does is asserted by the author and never verified.
  • The target name is a promise. A recipe that succeeds without creating the declared file makes the rule re-run on every invocation, with no error — the signature is a step that never stops rebuilding.
  • No prerequisites means "depends on nothing." Correct for an action, a bug for a generated file.
  • Any one newer prerequisite triggers the whole recipe. A rule is all-or-nothing.
  • Rules are selected by name, not by position or adjacency. A Makefile is a graph of names; the prerequisites are the edges.
  • A target may be a path, and Make will not create the directory for you.
  • File targets can be skipped; action targets cannot — the difference is only whether a file by that name appears on disk.

The next chapter takes that last point and makes it safe. An action target works only while no file shares its name, and sooner or later one does — a directory called test, a script called run, an artifact called clean. Chapter 2.2 shows the collision happening and the one-line declaration that prevents it.

Where this fits

Part of the Makefile curriculum.