Exercise Answers¶
Page Maps¶
graph LR
family["Reproducible Research"]
program["Deep Dive Make"]
section["Rule Semantics Precedence Edge Cases"]
page["Exercise Answers"]
capstone["Capstone evidence"]
family --> program --> section --> page
page -.applies in.-> capstone
flowchart LR
orient["Orient on the page map"] --> read["Read the main claim and examples"]
read --> inspect["Inspect the related code, proof, or capstone surface"]
inspect --> verify["Run or review the verification path"]
verify --> apply["Apply the idea back to the module and capstone"]
Use this after you have written your own answers. The point is comparison, not copying.
Strong answers in Module 04 do not merely name a feature. They explain:
- what semantic rule is in play
- what evidence would expose it
- why the repair is more honest than the broken version
Exercise 1: Choose the right CLI probe¶
The strongest answer starts with make --trace app because the immediate question is "why
did this run?" --trace is the cleanest first route to the causal edge or rule location.
A strong second command is make -p or make -q app, depending on what you are
trying to settle next:
-pif the dispute is about the evaluated rule or variable world-qif the dispute is whether the build has actually converged
The important reasoning is that clean, -B, and -j1 all change conditions more
aggressively. They may still be useful later, but they are weaker as first evidence.
Exercise 2: Prove where a variable value came from¶
A good answer introduces a small probe such as:
.PHONY: show-cflags
show-cflags:
@printf 'origin=%s flavor=%s raw=%s expanded=%s\n' \
'$(origin CFLAGS)' '$(flavor CFLAGS)' '$(value CFLAGS)' '$(CFLAGS)'
That answer is strong because it separates:
- origin: who won
- flavor: how the value is stored
- raw text: what expression was assigned
- expanded text: what the recipe eventually sees
A good repair usually simplifies one of two things:
- precedence, by removing accidental environment wins such as
-e - expansion timing, by replacing recursive assignment with
:=when laziness is not needed
Exercise 3: Repair a generated-include loop¶
The essential explanation is:
Make includes the generated file as part of evaluation. If the rule rewrites that file on every run, Make keeps seeing a changed build definition and never settles on a stable evaluated state.
A strong repair writes deterministic content from a real input and publishes atomically.
Example:
Atomic publication matters because included files participate in evaluation. A partially written file is not just a broken artifact. It is a broken build definition.
Exercise 4: Replace a platform branch with a capability gate¶
A strong answer says the build should branch on the feature it needs, not on an operating system label that only loosely predicts that feature.
For example:
HAVE_GNU_TAR := $(if $(shell tar --version 2>/dev/null | grep -q 'GNU tar' && printf yes),yes,)
ifeq ($(HAVE_GNU_TAR),yes)
ARCHIVE := tar
else
$(error need GNU tar-compatible archive behavior)
endif
The exact capability can vary. The important move is architectural:
- compute the capability once
- give it a stable name
- make later branches depend on that name
That is easier to audit because the reason for the branch is explicit and inspectable.
Exercise 5: Repair a multi-output generator honestly¶
The two valid repairs are:
Grouped targets¶
Choose this when the supported Make version includes grouped-target semantics. It is the closest match to the real event: one generator invocation publishes multiple outputs.
Stamp-governed generation¶
API_STAMP := build/api.stamp
$(API_STAMP): gen_api.py schema.yml | build/
python3 gen_api.py
touch $@
api.h api.json: $(API_STAMP)
Choose this when you need a fallback that is easier to support across broader Make versions or when the stamp makes the publication event clearer to the team.
The tradeoff is simple:
- grouped targets are semantically cleaner when available
- stamps are a durable fallback when grouped targets are not part of the contract
What mastery-level answers sound like¶
A mastery-level answer set in this module does three things well:
- it names semantic rules precisely instead of speaking in vague "Make is weird" language
- it picks evidence before it picks a repair
- it explains the repair as a better truth contract, not just a different syntax choice
That is the standard this module is trying to build.