Update the make variable header to match the ?= and prefix rules
All checks were successful
check / check (push) Successful in 15s

This commit is contained in:
user
2026-09-04 11:19:45 +00:00
parent 18b0f039b5
commit 956870889f

View File

@@ -149,11 +149,15 @@ const MAKE_CONDITIONAL = /^\s*(?:ifeq|ifneq|ifdef|ifndef|else|endif)\b/;
// one. `$(MAKE)` was already special-cased below, which is this same rule
// half-applied to a single name; this is the general form of it.
//
// Deliberately only the simple case: a name assigned a literal on one line.
// `:=` and `=` differ in when make expands them and `?=` in whether it assigns
// at all, but none of that changes the single value a literal can take, so all
// three are read the same way. What is not read is anything needing evaluation
// — a value containing another `$(...)`, a make function, or a `define` body —
// Deliberately only the simple case: a name assigned a literal on one line,
// optionally through an `export`/`override` prefix. `:=` and `=` differ in
// when make expands them, which does not change the single value a literal can
// take, so those two are read the same way and the last one wins. `?=` differs
// in whether it assigns at all — it is skipped when the name already has a
// value — so among assignments to one name the first `?=` wins, and reading it
// as last-wins would resolve a reference to the string make discards. What is
// not read is anything needing evaluation — a value containing another
// `$(...)`, a make function, or a `define` body —
// because expanding those means implementing make, and a half-implementation
// that resolves a variable to the wrong string would count invocations that do
// not happen. An unresolved reference is left standing verbatim instead, which
@@ -182,8 +186,8 @@ const makeVariables = (text: string): Map<string, string> => {
const assignment = MAKE_ASSIGNMENT.exec(raw.replace(/#.*$/, "").trim());
if (assignment === null) continue;
const [, name, operator, value] = assignment;
if (name === undefined || operator === undefined) continue;
if (value === undefined) continue;
if (name === undefined || operator === undefined || value === undefined)
continue;
// `?=` assigns only when the name has no value yet, so the first one
// wins where `:=` and `=` let the last one win. Overwriting here would
// resolve the reference to a string make never uses.
@@ -853,9 +857,12 @@ describe("the resolver reads what the shell would run", () => {
// is not read as an assignment of the empty string.
expect(
parseMakefile(
["FMT := script/fmt-check", "export FMT", "check:", "\t@$(FMT)"].join(
"\n",
),
[
"FMT := script/fmt-check",
"export FMT",
"check:",
"\t@$(FMT)",
].join("\n"),
).get("check")?.recipe,
).toEqual(["script/fmt-check"]);
});