Our make(1) is behind NetBSD's and FreeBSD's make(1) on at least the rules of variable substitution.
Our DESCRIPION says There are seven different types of lines in a makefile: dependency lines, shell commands, variable assignments, include statements, conditional directives, for loops, and comments. Of these, include statements, conditional directives and for loops are extensions. but our VARIABLES merely explains Variable substitution occurs at two distinct times, depending on where the variable is being used. Variables in dependency lines are expanded as the line is read. Variables in shell commands are expanded when the shell command is executed. and therefore fails to explain behaviour for the other five line types. http://man.netbsd.org/make.1#VARIABLE%20ASSIGNMENTS (same as FreeBSD in this regard) does go into more detail here: Variable substitution occurs at three distinct times, depending on where the variable is being used. 1. Variables in dependency lines are expanded as the line is read. 2. Variables in shell commands are expanded when the shell command is executed. 3. ``.for'' loop index variables are expanded on each loop iteration. Note that other variables are not expanded inside loops so the fol- lowing example code: [...] Diff below sync this list in VARIABLES as is. After that I'd like to expand it and explain behaviour for other types; I've scratched my head on make's behaviour for too long and the manual failed to cover this completely. Feedback? OK? Index: make.1 =================================================================== RCS file: /cvs/src/usr.bin/make/make.1,v retrieving revision 1.131 diff -u -p -r1.131 make.1 --- make.1 26 Jan 2020 12:40:50 -0000 1.131 +++ make.1 26 Dec 2020 16:17:51 -0000 @@ -600,11 +600,48 @@ If the variable name contains only a sin braces or parentheses are not required. This shorter form is not recommended. .Pp -Variable substitution occurs at two distinct times, depending on where +Variable substitution occurs at three distinct times, depending on where the variable is being used. +.Bl -enum +.It Variables in dependency lines are expanded as the line is read. +.It Variables in shell commands are expanded when the shell command is executed. +.It +.Dq .for +loop index variables are expanded on each loop iteration. +Note that other variables are not expanded inside loops so +the following example code: +.Bd -literal -offset indent + +.Dv .for i in 1 2 3 +a+= ${i} +j= ${i} +b+= ${j} +.Dv .endfor + +all: + @echo ${a} + @echo ${b} + +.Ed +will print: +.Bd -literal -offset indent +1 2 3 +3 3 3 + +.Ed +Because while ${a} contains +.Dq 1 2 3 +after the loop is executed, ${b} +contains +.Dq ${j} ${j} ${j} +which expands to +.Dq 3 3 3 +since after the loop completes ${j} contains +.Dq 3 . +.El .Pp The four different classes of variables (in order of increasing precedence) are: