Lesson 2 ended with a rule: a stage must rerun when any of its inputs is newer than its output. Applied by hand, this rule is easy to get wrong. A designer reruns placement after a floorplan change but forgets routing, or reruns everything from synthesis to be safe and loses half a day. The Unix tool make was written to apply exactly this rule to files, and it remains the most common way to order the stages of a flow.
This lesson introduces targets, prerequisites and recipes, explains how make uses file timestamps to decide what to rebuild, and builds a small Makefile for a synthesis, placement, routing and STA flow. The stage commands it calls are the wrappers from lesson 3.
Reading time: about 7 minutes.
4.1 Targets, prerequisites and recipes
A Makefile is a list of rules. Each rule names a target (usually a file to be built), its prerequisites (the files it is built from), and a recipe (the shell commands that build it).
target: prerequisite_1 prerequisite_2 ...
recipe_command_1
recipe_command_2
Each recipe line must begin with a tab character, not spaces. This is the most common first mistake with make, and the error it gives (missing separator) does not say so directly. Each recipe line runs in its own shell, and if any line returns a non-zero exit status, make stops – which is why lesson 3 insisted that every wrapper return a correct exit status.
Let us consider the smallest useful rule:
runs/aes/syn.v: rtl/aes.v flow/syn.tcl
yosys -c flow/syn.tcl -l runs/aes/syn.log
This says: the netlist runs/aes/syn.v is built from the RTL and the synthesis script, and the recipe to build it is the Yosys command. Typing make runs/aes/syn.v runs the recipe only if it is needed.
4.2 How make decides: timestamps
Every file on disk carries a modification time. When asked to build a target, make first builds any prerequisite that itself is a target, recursively. Then it compares times. The target is rebuilt if it does not exist, or if any prerequisite has a modification time newer than the target's. Otherwise the target is considered up to date and nothing runs.
Thus, make never inspects file contents. It does not know that an edit only changed a comment; a newer time is enough. The opposite is also true: if a file changes but its time does not (for example, it is copied with times preserved from an older version), make will not notice.
make reads timestamps. The placement script was edited at 14:10, after place.odb was written at 11:00, so placement reruns. Its new output is then newer than route.odb, so routing reruns, and so on. Notice that syn.v is untouched: none of its prerequisites changed.4.3 Phony targets
Designers prefer to type make place rather than a full file path. A target such as place is not a file; it is a name for a group of work. Such a target is called a phony target and is declared with the special target .PHONY:
.PHONY: all syn place route sta clean
place: runs/aes/place.odb
Why declare it? If a file or directory called place ever appears in the working directory, make would otherwise treat the target as that file, find it up to date, and do nothing. Declaring it phony tells make never to look for such a file. The usual pattern is that phony targets are short names that depend on real file targets, and the real file targets carry the recipes. Thus the timestamp logic still works, and the user still types a short name.
4.4 A small flow Makefile
The Makefile below runs four stages. It assumes the wrapper from lesson 3, extended to start the right tool for each stage and to accept the input and output file as arguments.
# Makefile -- syn -> place -> route -> sta for one design
DESIGN := aes_core
FLOW := flow
RUN := runs/$(DESIGN)
CFG := config/$(DESIGN).json
STAGE := python3 $(FLOW)/run_stage.py
.PHONY: all syn place route sta clean
.DELETE_ON_ERROR:
all: sta
syn: $(RUN)/syn.v
place: $(RUN)/place.odb
route: $(RUN)/route.odb
sta: $(RUN)/sta.rpt
$(RUN)/syn.v: rtl/$(DESIGN).v $(FLOW)/syn.tcl $(CFG)
mkdir -p $(RUN)
$(STAGE) syn $(CFG) --in $< --out $@
$(RUN)/place.odb: $(RUN)/syn.v $(FLOW)/place.tcl $(CFG)
$(STAGE) place $(CFG) --in $< --out $@
$(RUN)/route.odb: $(RUN)/place.odb $(FLOW)/route.tcl $(CFG)
$(STAGE) route $(CFG) --in $< --out $@
$(RUN)/sta.rpt: $(RUN)/route.odb $(FLOW)/sta.tcl $(CFG)
$(STAGE) sta $(CFG) --in $< --out $@
clean:
rm -rf $(RUN)
A few details are worth reading slowly.
:=defines a variable, and$(NAME)uses it. ChangingDESIGNon the command line (make DESIGN=uart) reuses the whole file for another block, in the spirit of lesson 3's separation of configuration from scripts.$@is an automatic variable meaning the target of the rule, and$<means its first prerequisite. Another useful one is$^, all prerequisites.- Each target lists its stage script as a prerequisite. This is what made the rebuild in the figure happen: editing
place.tclmakesplace.odbout of date. .DELETE_ON_ERROR:tells GNUmaketo delete a target whose recipe failed after modifying it. Without it, a tool that crashes halfway might leave a partial database with a fresh timestamp, and the nextmakewould treat it as up to date.
4.5 Incremental reruns in practice
Assumptions: the whole flow has run once. The designer then edits flow/route.tcl to change a routing setting.
make -nprints the recipes that would run, without running them. Here it shows the route and STA recipes only. A dry run like this is a cheap way to confirm the dependencies before spending hours of compute.make(the default targetall, which depends onsta) reruns routing, then STA. Synthesis and placement are skipped because their targets are newer than all their prerequisites.make -B placeforces placement and everything it depends on to rebuild regardless of times. This is occasionally needed, for example after a tool version change thatmakecannot see.
Two pitfalls appear in almost every real flow.
Missing prerequisites
If a file that affects a stage is not listed as a prerequisite, make will not rerun the stage when it changes. Libraries, SDC files, sourced helper scripts and tool versions are often forgotten. It is better to list too many inputs than too few, because a missed rerun produces results that look valid but are not.
Coarse prerequisites
The opposite problem appears in the Makefile above. Every stage depends on the single configuration file $(CFG), so changing a routing setting in it also reruns synthesis. A common remedy is to let the wrapper write a small per-stage settings file (for example runs/aes/place.cfg) and to rewrite it only when that stage's settings actually change. That file, not the full configuration, is then the prerequisite. Its timestamp moves only when relevant settings move.
Parallel targets
Targets that do not depend on each other can be built at the same time with make -j N. For example, signoff STA at four corners can be four independent targets that all depend on route.odb; make -j 4 runs them together. Lesson 6 shows how to send each one to a compute farm instead of the local machine.
4.6 Interview questions
How does make decide whether to rebuild a target? It rebuilds the target if the target file does not exist or if any prerequisite has a newer modification time, after first bringing the prerequisites themselves up to date.
What is a phony target and why declare it? A target name that is not a file, such as clean or route. Declaring it in .PHONY stops make from treating it as up to date if a file of that name exists.
Why list the stage script as a prerequisite of its output? So that a change to the script makes the output out of date and reruns that stage and every stage after it. Without it, script changes are silently ignored.
What do $@ and $< mean? The target of the current rule and the first prerequisite of that rule.
Why use .DELETE_ON_ERROR in a flow Makefile? A failed tool run can leave a partly written output with a new timestamp. Deleting it ensures the next run rebuilds the stage instead of trusting a broken file.
Key takeaways
- A rule has a target, prerequisites and a tab-indented recipe;
makestops when a recipe line returns a non-zero status. makerebuilds a target when it is missing or older than any prerequisite, and it looks only at timestamps, never at contents.- Phony targets give short names to stages, while real file targets carry the recipes and the timestamp logic.
- List every input that affects a stage, including scripts and constraints, and make prerequisites only as coarse as necessary.
make -n,make -B,make -jand.DELETE_ON_ERRORare the everyday tools for safe incremental and parallel reruns.