Home | History | Annotate | Line # | Download | only in unit-tests
      1  1.11  rillig # $NetBSD: var-scope-local.mk,v 1.11 2024/03/05 23:07:58 rillig Exp $
      2   1.1  rillig #
      3   1.3  rillig # Tests for target-local variables, such as ${.TARGET} or $@.  These variables
      4   1.3  rillig # are relatively short-lived as they are created just before making the
      5   1.3  rillig # target.  In contrast, global variables are typically created when the
      6   1.3  rillig # makefiles are read in.
      7   1.3  rillig #
      8   1.3  rillig # The 7 built-in target-local variables are listed in the manual page.  They
      9   1.3  rillig # are defined just before the target is actually made.  Additional
     10   1.3  rillig # target-local variables can be defined in dependency lines like
     11   1.3  rillig # 'target: VAR=value', one at a time.
     12   1.3  rillig 
     13   1.3  rillig .MAIN: all
     14   1.3  rillig 
     15   1.6  rillig # Target-local variables in a target rule
     16   1.7  rillig #
     17   1.7  rillig # In target rules, '$*' only strips the extension off the pathname if the
     18   1.7  rillig # extension is listed in '.SUFFIXES'.
     19   1.7  rillig #
     20   1.7  rillig # expect: target-rule.ext: * = <target-rule.ext>
     21   1.6  rillig all: target-rule.ext dir/subdir/target-rule.ext
     22   1.6  rillig target-rule.ext dir/subdir/target-rule.ext: .PHONY
     23   1.6  rillig 	@echo '$@: @ = <${@:Uundefined}>'
     24   1.6  rillig 	@echo '$@: % = <${%:Uundefined}>'
     25   1.6  rillig 	@echo '$@: ? = <${?:Uundefined}>'
     26   1.6  rillig 	@echo '$@: < = <${<:Uundefined}>'
     27   1.6  rillig 	@echo '$@: * = <${*:Uundefined}>'
     28   1.6  rillig 
     29   1.6  rillig .SUFFIXES: .ir-gen-from .ir-from .ir-to
     30   1.7  rillig 
     31   1.7  rillig # In target rules, '$*' strips the extension off the pathname of the target
     32   1.7  rillig # if the extension is listed in '.SUFFIXES'.
     33   1.7  rillig #
     34   1.7  rillig # expect: target-rule.ir-gen-from: * = <target-rule>
     35   1.7  rillig all: target-rule.ir-gen-from dir/subdir/target-rule-dir.ir-gen-from
     36   1.7  rillig target-rule.ir-gen-from dir/subdir/target-rule-dir.ir-gen-from:
     37   1.7  rillig 	@echo '$@: @ = <${@:Uundefined}>'
     38   1.7  rillig 	@echo '$@: % = <${%:Uundefined}>'
     39   1.7  rillig 	@echo '$@: ? = <${?:Uundefined}>'
     40   1.7  rillig 	@echo '$@: < = <${<:Uundefined}>'
     41   1.7  rillig 	@echo '$@: * = <${*:Uundefined}>'
     42   1.7  rillig 
     43   1.6  rillig .ir-from.ir-to:
     44   1.6  rillig 	@echo '$@: @ = <${@:Uundefined}>'
     45   1.6  rillig 	@echo '$@: % = <${%:Uundefined}>'
     46   1.6  rillig 	@echo '$@: ? = <${?:Uundefined}>'
     47   1.6  rillig 	@echo '$@: < = <${<:Uundefined}>'
     48   1.6  rillig 	@echo '$@: * = <${*:Uundefined}>'
     49   1.6  rillig .ir-gen-from.ir-from:
     50   1.6  rillig 	@echo '$@: @ = <${@:Uundefined}>'
     51   1.6  rillig 	@echo '$@: % = <${%:Uundefined}>'
     52   1.6  rillig 	@echo '$@: ? = <${?:Uundefined}>'
     53   1.6  rillig 	@echo '$@: < = <${<:Uundefined}>'
     54   1.6  rillig 	@echo '$@: * = <${*:Uundefined}>'
     55   1.6  rillig 
     56   1.6  rillig # Target-local variables in an inference rule
     57   1.6  rillig all: inference-rule.ir-to dir/subdir/inference-rule.ir-to
     58   1.6  rillig inference-rule.ir-from: .PHONY
     59   1.6  rillig dir/subdir/inference-rule.ir-from: .PHONY
     60   1.6  rillig 
     61   1.6  rillig # Target-local variables in a chain of inference rules
     62   1.6  rillig all: inference-rule-chain.ir-to dir/subdir/inference-rule-chain.ir-to
     63   1.6  rillig inference-rule-chain.ir-gen-from: .PHONY
     64   1.6  rillig dir/subdir/inference-rule-chain.ir-gen-from: .PHONY
     65   1.6  rillig 
     66   1.7  rillig # The run-time 'check' directives from above happen after the parse-time
     67   1.7  rillig # 'check' directives from below.
     68   1.7  rillig #
     69   1.7  rillig # expect-reset
     70   1.6  rillig 
     71   1.6  rillig # Deferred evaluation during parsing
     72   1.6  rillig #
     73   1.3  rillig # The target-local variables can be used in expressions, just like other
     74   1.3  rillig # variables.  When these expressions are evaluated outside of a target, these
     75   1.3  rillig # expressions are not yet expanded, instead their text is preserved, to allow
     76   1.3  rillig # these expressions to expand right in time when the target-local variables
     77   1.3  rillig # are actually set.
     78   1.3  rillig #
     79   1.5  rillig # Conditions from .if directives are evaluated in the scope of the command
     80   1.3  rillig # line, which means that variables from the command line, from the global
     81   1.6  rillig # scope and from the environment are resolved, in this precedence order (but
     82   1.6  rillig # see the command line option '-e').  In that phase, expressions involving
     83   1.3  rillig # target-local variables need to be preserved, including the exact names of
     84   1.3  rillig # the variables.
     85   1.3  rillig #
     86   1.3  rillig # Each of the built-in target-local variables has two equivalent names, for
     87   1.3  rillig # example '@' is equivalent to '.TARGET'.  The implementation might
     88   1.1  rillig # canonicalize these aliases at some point, and that might be surprising.
     89   1.1  rillig # This aliasing happens for single-character variable names like $@ or $<
     90   1.1  rillig # (see VarFind, CanonicalVarname), but not for braced or parenthesized
     91   1.1  rillig # expressions like ${@}, ${.TARGET} ${VAR:Mpattern} (see Var_Parse,
     92   1.1  rillig # ParseVarname).
     93   1.3  rillig #
     94   1.5  rillig # In the following condition, make expands '$@' to the long-format alias
     95   1.5  rillig # '$(.TARGET)'; note that the alias is not written with braces, as would be
     96   1.5  rillig # common in BSD makefiles, but with parentheses.  This alternative spelling
     97   1.5  rillig # behaves the same though.
     98   1.3  rillig .if $@ != "\$\(.TARGET)"
     99   1.3  rillig .  error
    100   1.3  rillig .endif
    101   1.5  rillig # In the long form of writing a target-local variable, the text of the
    102   1.5  rillig # expression is preserved exactly as written, no matter whether it is written
    103   1.5  rillig # with '{' or '('.
    104   1.3  rillig .if ${@} != "\$\{@}"
    105   1.3  rillig .  error
    106   1.3  rillig .endif
    107   1.3  rillig .if $(@) != "\$\(@)"
    108   1.3  rillig .  error
    109   1.3  rillig .endif
    110   1.8  rillig # If the expression contains modifiers, the behavior depends on the
    111   1.3  rillig # actual modifiers.  The modifier ':M' keeps the expression in the state
    112   1.3  rillig # 'undefined'.  Since the expression is still undefined after evaluating all
    113   1.3  rillig # the modifiers, the value of the expression is discarded and the expression
    114   1.3  rillig # text is used instead.  This preserves the expressions based on target-local
    115   1.3  rillig # variables as long as possible.
    116   1.3  rillig .if ${@:M*} != "\$\{@:M*}"
    117   1.3  rillig .  error
    118   1.3  rillig .endif
    119   1.3  rillig # In the following examples, the expressions are based on target-local
    120   1.3  rillig # variables but use the modifier ':L', which turns an undefined expression
    121   1.3  rillig # into a defined one.  At the end of evaluating the expression, the state of
    122   1.5  rillig # the expression is not 'undefined' anymore.  The value of the expression
    123   1.3  rillig # is the name of the variable, since that's what the modifier ':L' does.
    124   1.1  rillig .if ${@:L} != "@"
    125   1.1  rillig .  error
    126   1.1  rillig .endif
    127   1.1  rillig .if ${.TARGET:L} != ".TARGET"
    128   1.1  rillig .  error
    129   1.1  rillig .endif
    130   1.1  rillig .if ${@F:L} != "@F"
    131   1.1  rillig .  error
    132   1.1  rillig .endif
    133   1.1  rillig .if ${@D:L} != "@D"
    134   1.1  rillig .  error
    135   1.1  rillig .endif
    136   1.1  rillig 
    137   1.3  rillig 
    138   1.6  rillig # Custom local variables
    139   1.6  rillig #
    140   1.3  rillig # Additional target-local variables may be defined in dependency lines.
    141   1.3  rillig .MAKEFLAGS: -dv
    142   1.3  rillig # In the following line, the ':=' may either be interpreted as an assignment
    143   1.3  rillig # operator or as the dependency operator ':', followed by an empty variable
    144   1.3  rillig # name and the assignment operator '='.  It is the latter since in an
    145   1.6  rillig # assignment, the left-hand side must be a single word or empty.
    146   1.6  rillig #
    147   1.6  rillig # The empty variable name is expanded twice, once for 'one' and once for
    148   1.6  rillig # 'two'.
    149   1.9  rillig # expect: one: ignoring ' = three' as the variable name '' expands to empty
    150   1.9  rillig # expect: two: ignoring ' = three' as the variable name '' expands to empty
    151   1.3  rillig one two:=three
    152   1.8  rillig # If the two targets to the left are generated by an expression, the
    153   1.3  rillig # line is parsed as a variable assignment since its left-hand side is a single
    154   1.3  rillig # word.
    155   1.3  rillig # expect: Global: one two = three
    156   1.3  rillig ${:Uone two}:=three
    157   1.3  rillig .MAKEFLAGS: -d0
    158   1.3  rillig 
    159   1.1  rillig 
    160   1.1  rillig .SUFFIXES: .c .o
    161   1.1  rillig 
    162   1.3  rillig # One of the dynamic target-local variables is '.TARGET'.  Since this is not
    163   1.3  rillig # a suffix transformation rule, the variable '.IMPSRC' is not defined.
    164   1.3  rillig # expect: : Making var-scope-local.c out of nothing.
    165   1.3  rillig var-scope-local.c:
    166   1.3  rillig 	: Making ${.TARGET} ${.IMPSRC:Dfrom ${.IMPSRC}:Uout of nothing}.
    167   1.3  rillig 
    168   1.3  rillig # This is a suffix transformation rule, so both '.TARGET' and '.IMPSRC' are
    169   1.3  rillig # defined.
    170   1.3  rillig # expect: : Making var-scope-local.o from var-scope-local.c.
    171   1.3  rillig # expect: : Making basename "var-scope-local.o" in "." from "var-scope-local.c" in ".".
    172   1.1  rillig .c.o:
    173   1.1  rillig 	: Making ${.TARGET} from ${.IMPSRC}.
    174   1.1  rillig 
    175   1.1  rillig 	# The local variables @F, @D, <F, <D are legacy forms.
    176   1.1  rillig 	# See the manual page for details.
    177   1.3  rillig 	: Making basename "${@F}" in "${@D}" from "${<F}" in "${<D}".
    178   1.1  rillig 
    179   1.3  rillig # expect: : all overwritten
    180   1.3  rillig all: var-scope-local.o
    181   1.1  rillig 	# The ::= modifier overwrites the .TARGET variable in the node
    182   1.1  rillig 	# 'all', not in the global scope.  This can be seen with the -dv
    183   1.3  rillig 	# option, looking for "all: @ = overwritten".
    184   1.3  rillig 	: ${.TARGET} ${.TARGET::=overwritten}${.TARGET}
    185   1.3  rillig 
    186   1.3  rillig 
    187   1.3  rillig # Begin tests for custom target-local variables, for all 5 variable assignment
    188   1.3  rillig # operators.
    189   1.3  rillig all: var-scope-local-assign.o
    190   1.3  rillig all: var-scope-local-append.o
    191   1.3  rillig all: var-scope-local-append-global.o
    192   1.3  rillig all: var-scope-local-default.o
    193   1.3  rillig all: var-scope-local-subst.o
    194   1.3  rillig all: var-scope-local-shell.o
    195   1.3  rillig 
    196   1.3  rillig var-scope-local-assign.o \
    197   1.3  rillig var-scope-local-append.o \
    198   1.3  rillig var-scope-local-append-global.o \
    199   1.3  rillig var-scope-local-default.o \
    200   1.3  rillig var-scope-local-subst.o \
    201   1.3  rillig var-scope-local-shell.o:
    202  1.11  rillig 	@echo "Making ${.TARGET} with make '"${VAR:Q}"' and env '$$VAR'."
    203   1.2     sjg 
    204   1.3  rillig # Target-local variables are enabled by default.  Force them to be enabled
    205   1.3  rillig # just in case a test above has disabled them.
    206   1.2     sjg .MAKE.TARGET_LOCAL_VARIABLES= yes
    207   1.2     sjg 
    208   1.3  rillig VAR=	global
    209  1.10     sjg .export VAR
    210   1.3  rillig 
    211   1.3  rillig # If the sources of a dependency line look like a variable assignment, make
    212   1.3  rillig # treats them as such.  There is only a single variable assignment per
    213   1.3  rillig # dependency line, which makes whitespace around the assignment operator
    214   1.3  rillig # irrelevant.
    215   1.3  rillig #
    216   1.3  rillig # expect-reset
    217  1.11  rillig # expect: Making var-scope-local-assign.o with make 'local' and env 'local'.
    218   1.3  rillig var-scope-local-assign.o: VAR= local
    219   1.3  rillig 
    220   1.3  rillig # Assignments using '+=' do *not* look up the global value, instead they only
    221   1.3  rillig # look up the variable in the target's own scope.
    222   1.3  rillig var-scope-local-append.o: VAR+= local
    223   1.3  rillig # Once a variable is defined in the target-local scope, appending using '+='
    224   1.3  rillig # behaves as expected.  Note that the expression '${.TARGET}' is not resolved
    225   1.3  rillig # when parsing the dependency line, its evaluation is deferred until the
    226   1.3  rillig # target is actually made.
    227  1.11  rillig # expect: Making var-scope-local-append.o with make 'local to var-scope-local-append.o' and env 'local to var-scope-local-append.o'.
    228   1.3  rillig var-scope-local-append.o: VAR += to ${.TARGET}
    229   1.8  rillig # To access the value of a global variable, use an expression.  This
    230   1.3  rillig # expression is expanded before parsing the whole dependency line.  Since the
    231   1.5  rillig # expansion happens to the right of the dependency operator ':', the expanded
    232   1.5  rillig # text does not influence parsing of the dependency line.  Since the expansion
    233   1.5  rillig # happens to the right of the assignment operator '=', the expanded text does
    234   1.5  rillig # not influence the parsing of the variable assignment.  The effective
    235   1.5  rillig # variable assignment, after expanding the whole line first, is thus
    236   1.3  rillig # 'VAR= global+local'.
    237  1.11  rillig # expect: Making var-scope-local-append-global.o with make 'global+local' and env 'global+local'.
    238   1.3  rillig var-scope-local-append-global.o: VAR= ${VAR}+local
    239   1.3  rillig 
    240   1.3  rillig var-scope-local-default.o: VAR ?= first
    241   1.3  rillig var-scope-local-default.o: VAR ?= second
    242   1.3  rillig # XXX: '?=' does look at the global variable.  That's a long-standing
    243   1.3  rillig # inconsistency between the assignment operators '+=' and '?='.  See
    244   1.3  rillig # Var_AppendExpand and VarAssign_Eval.
    245  1.11  rillig # expect: Making var-scope-local-default.o with make 'global' and env 'global'.
    246   1.3  rillig 
    247   1.3  rillig # Using the variable assignment operator ':=' provides another way of
    248   1.3  rillig # accessing a global variable and extending it with local modifications.  The
    249   1.3  rillig # '$' has to be written as '$$' though to survive the expansion of the
    250   1.5  rillig # dependency line as a whole.  After that, the parser sees the variable
    251   1.5  rillig # assignment as 'VAR := ${VAR}+local' and searches for the variable 'VAR' in
    252   1.5  rillig # the usual scopes, picking up the variable from the global scope.
    253  1.11  rillig # expect: Making var-scope-local-subst.o with make 'global+local' and env 'global+local'.
    254   1.3  rillig var-scope-local-subst.o: VAR := $${VAR}+local
    255   1.3  rillig 
    256   1.3  rillig # The variable assignment operator '!=' assigns the output of the shell
    257   1.5  rillig # command, as everywhere else.  The shell command is run when the dependency
    258   1.5  rillig # line is parsed.
    259   1.3  rillig var-scope-local-shell.o: VAR != echo output
    260   1.3  rillig 
    261   1.3  rillig 
    262   1.3  rillig # While VAR=use will be set for a .USE node, it will never be seen since only
    263   1.3  rillig # the ultimate target's context is searched; the variable assignments from the
    264   1.3  rillig # .USE target are not copied to the ultimate target's.
    265  1.11  rillig # expect: Making .USE var-scope-local-use.o with make 'global' and env 'global'.
    266   1.2     sjg a_use: .USE VAR=use
    267  1.11  rillig 	@echo "Making .USE ${.TARGET} with make '"${VAR:Q}"' and env '$$VAR'."
    268   1.2     sjg 
    269   1.3  rillig all: var-scope-local-use.o
    270   1.3  rillig var-scope-local-use.o: a_use
    271