Home | History | Annotate | Line # | Download | only in unit-tests
var-scope-local.mk revision 1.4
      1  1.4  rillig # $NetBSD: var-scope-local.mk,v 1.4 2022/02/05 10:41:15 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.3  rillig # The target-local variables can be used in expressions, just like other
     16  1.3  rillig # variables.  When these expressions are evaluated outside of a target, these
     17  1.3  rillig # expressions are not yet expanded, instead their text is preserved, to allow
     18  1.3  rillig # these expressions to expand right in time when the target-local variables
     19  1.3  rillig # are actually set.
     20  1.3  rillig #
     21  1.3  rillig # Conditions like the ones below are evaluated in the scope of the command
     22  1.3  rillig # line, which means that variables from the command line, from the global
     23  1.3  rillig # scope and from the environment are resolved, in this order (but see the
     24  1.3  rillig # command line option '-e').  In that phase, expressions involving
     25  1.3  rillig # target-local variables need to be preserved, including the exact names of
     26  1.3  rillig # the variables.
     27  1.3  rillig #
     28  1.3  rillig # Each of the built-in target-local variables has two equivalent names, for
     29  1.3  rillig # example '@' is equivalent to '.TARGET'.  The implementation might
     30  1.1  rillig # canonicalize these aliases at some point, and that might be surprising.
     31  1.1  rillig # This aliasing happens for single-character variable names like $@ or $<
     32  1.1  rillig # (see VarFind, CanonicalVarname), but not for braced or parenthesized
     33  1.1  rillig # expressions like ${@}, ${.TARGET} ${VAR:Mpattern} (see Var_Parse,
     34  1.1  rillig # ParseVarname).
     35  1.3  rillig #
     36  1.3  rillig # In the following condition, make does not expand '$@' but instead changes it
     37  1.3  rillig # to the long-format alias '$(.TARGET)'; note that the alias is not written
     38  1.3  rillig # with braces, as would be common in BSD makefiles, but with parentheses.
     39  1.3  rillig # This alternative form behaves equivalently though.
     40  1.3  rillig .if $@ != "\$\(.TARGET)"
     41  1.3  rillig .  error
     42  1.3  rillig .endif
     43  1.3  rillig # In the long form of writing a target-local variable, the expression is
     44  1.3  rillig # preserved exactly as written, no matter whether with '{' or '('.
     45  1.3  rillig .if ${@} != "\$\{@}"
     46  1.3  rillig .  error
     47  1.3  rillig .endif
     48  1.3  rillig .if $(@) != "\$\(@)"
     49  1.3  rillig .  error
     50  1.3  rillig .endif
     51  1.3  rillig # If the variable expression contains modifiers, the behavior depends on the
     52  1.3  rillig # actual modifiers.  The modifier ':M' keeps the expression in the state
     53  1.3  rillig # 'undefined'.  Since the expression is still undefined after evaluating all
     54  1.3  rillig # the modifiers, the value of the expression is discarded and the expression
     55  1.3  rillig # text is used instead.  This preserves the expressions based on target-local
     56  1.3  rillig # variables as long as possible.
     57  1.3  rillig .if ${@:M*} != "\$\{@:M*}"
     58  1.3  rillig .  error
     59  1.3  rillig .endif
     60  1.3  rillig # In the following examples, the expressions are based on target-local
     61  1.3  rillig # variables but use the modifier ':L', which turns an undefined expression
     62  1.3  rillig # into a defined one.  At the end of evaluating the expression, the state of
     63  1.3  rillig # the expression is not 'undefined' anymore, and the value of the expression
     64  1.3  rillig # is the name of the variable, since that's what the modifier ':L' does.
     65  1.1  rillig .if ${@:L} != "@"
     66  1.1  rillig .  error
     67  1.1  rillig .endif
     68  1.1  rillig .if ${.TARGET:L} != ".TARGET"
     69  1.1  rillig .  error
     70  1.1  rillig .endif
     71  1.1  rillig .if ${@F:L} != "@F"
     72  1.1  rillig .  error
     73  1.1  rillig .endif
     74  1.1  rillig .if ${@D:L} != "@D"
     75  1.1  rillig .  error
     76  1.1  rillig .endif
     77  1.1  rillig 
     78  1.3  rillig 
     79  1.3  rillig # Additional target-local variables may be defined in dependency lines.
     80  1.3  rillig .MAKEFLAGS: -dv
     81  1.3  rillig # In the following line, the ':=' may either be interpreted as an assignment
     82  1.3  rillig # operator or as the dependency operator ':', followed by an empty variable
     83  1.3  rillig # name and the assignment operator '='.  It is the latter since in an
     84  1.3  rillig # assignment, the left-hand side must be at most a single word.  The empty
     85  1.3  rillig # variable name is expanded twice, once for 'one' and once for 'two'.
     86  1.3  rillig # expect: Var_SetExpand: variable name "" expands to empty string, with value "three" - ignored
     87  1.3  rillig # expect: Var_SetExpand: variable name "" expands to empty string, with value "three" - ignored
     88  1.3  rillig one two:=three
     89  1.3  rillig # If the two targets to the left are generated by a variable expression, the
     90  1.3  rillig # line is parsed as a variable assignment since its left-hand side is a single
     91  1.3  rillig # word.
     92  1.3  rillig # expect: Global: one two = three
     93  1.3  rillig ${:Uone two}:=three
     94  1.3  rillig .MAKEFLAGS: -d0
     95  1.3  rillig 
     96  1.1  rillig 
     97  1.1  rillig .SUFFIXES: .c .o
     98  1.1  rillig 
     99  1.3  rillig # One of the dynamic target-local variables is '.TARGET'.  Since this is not
    100  1.3  rillig # a suffix transformation rule, the variable '.IMPSRC' is not defined.
    101  1.3  rillig # expect: : Making var-scope-local.c out of nothing.
    102  1.3  rillig var-scope-local.c:
    103  1.3  rillig 	: Making ${.TARGET} ${.IMPSRC:Dfrom ${.IMPSRC}:Uout of nothing}.
    104  1.3  rillig 
    105  1.3  rillig # This is a suffix transformation rule, so both '.TARGET' and '.IMPSRC' are
    106  1.3  rillig # defined.
    107  1.3  rillig # expect: : Making var-scope-local.o from var-scope-local.c.
    108  1.3  rillig # expect: : Making basename "var-scope-local.o" in "." from "var-scope-local.c" in ".".
    109  1.1  rillig .c.o:
    110  1.1  rillig 	: Making ${.TARGET} from ${.IMPSRC}.
    111  1.1  rillig 
    112  1.1  rillig 	# The local variables @F, @D, <F, <D are legacy forms.
    113  1.1  rillig 	# See the manual page for details.
    114  1.3  rillig 	: Making basename "${@F}" in "${@D}" from "${<F}" in "${<D}".
    115  1.1  rillig 
    116  1.3  rillig # expect: : all overwritten
    117  1.3  rillig all: var-scope-local.o
    118  1.1  rillig 	# The ::= modifier overwrites the .TARGET variable in the node
    119  1.1  rillig 	# 'all', not in the global scope.  This can be seen with the -dv
    120  1.3  rillig 	# option, looking for "all: @ = overwritten".
    121  1.3  rillig 	: ${.TARGET} ${.TARGET::=overwritten}${.TARGET}
    122  1.3  rillig 
    123  1.3  rillig 
    124  1.3  rillig # Begin tests for custom target-local variables, for all 5 variable assignment
    125  1.3  rillig # operators.
    126  1.3  rillig all: var-scope-local-assign.o
    127  1.3  rillig all: var-scope-local-append.o
    128  1.3  rillig all: var-scope-local-append-global.o
    129  1.3  rillig all: var-scope-local-default.o
    130  1.3  rillig all: var-scope-local-subst.o
    131  1.3  rillig all: var-scope-local-shell.o
    132  1.3  rillig 
    133  1.3  rillig var-scope-local-assign.o \
    134  1.3  rillig var-scope-local-append.o \
    135  1.3  rillig var-scope-local-append-global.o \
    136  1.3  rillig var-scope-local-default.o \
    137  1.3  rillig var-scope-local-subst.o \
    138  1.3  rillig var-scope-local-shell.o:
    139  1.3  rillig 	: Making ${.TARGET} with VAR="${VAR}".
    140  1.2     sjg 
    141  1.3  rillig # Target-local variables are enabled by default.  Force them to be enabled
    142  1.3  rillig # just in case a test above has disabled them.
    143  1.2     sjg .MAKE.TARGET_LOCAL_VARIABLES= yes
    144  1.2     sjg 
    145  1.3  rillig VAR=	global
    146  1.3  rillig 
    147  1.3  rillig # If the sources of a dependency line look like a variable assignment, make
    148  1.3  rillig # treats them as such.  There is only a single variable assignment per
    149  1.3  rillig # dependency line, which makes whitespace around the assignment operator
    150  1.3  rillig # irrelevant.
    151  1.3  rillig #
    152  1.3  rillig # expect-reset
    153  1.3  rillig # expect: : Making var-scope-local-assign.o with VAR="local".
    154  1.3  rillig var-scope-local-assign.o: VAR= local
    155  1.3  rillig 
    156  1.3  rillig # Assignments using '+=' do *not* look up the global value, instead they only
    157  1.3  rillig # look up the variable in the target's own scope.
    158  1.3  rillig var-scope-local-append.o: VAR+= local
    159  1.3  rillig # Once a variable is defined in the target-local scope, appending using '+='
    160  1.3  rillig # behaves as expected.  Note that the expression '${.TARGET}' is not resolved
    161  1.3  rillig # when parsing the dependency line, its evaluation is deferred until the
    162  1.3  rillig # target is actually made.
    163  1.3  rillig # expect: : Making var-scope-local-append.o with VAR="local to var-scope-local-append.o".
    164  1.3  rillig var-scope-local-append.o: VAR += to ${.TARGET}
    165  1.3  rillig # To access the value of a global variable, use a variable expression.  This
    166  1.3  rillig # expression is expanded before parsing the whole dependency line.  Since the
    167  1.3  rillig # expansion happens to the right of both the dependency operator ':' and also
    168  1.3  rillig # to the right of the assignment operator '=', the expanded text does not
    169  1.3  rillig # affect the dependency or the variable assignment structurally.  The
    170  1.3  rillig # effective variable assignment, after expanding the whole line first, is thus
    171  1.3  rillig # 'VAR= global+local'.
    172  1.3  rillig # expect: : Making var-scope-local-append-global.o with VAR="global+local".
    173  1.3  rillig var-scope-local-append-global.o: VAR= ${VAR}+local
    174  1.3  rillig 
    175  1.3  rillig var-scope-local-default.o: VAR ?= first
    176  1.3  rillig var-scope-local-default.o: VAR ?= second
    177  1.3  rillig # XXX: '?=' does look at the global variable.  That's a long-standing
    178  1.3  rillig # inconsistency between the assignment operators '+=' and '?='.  See
    179  1.3  rillig # Var_AppendExpand and VarAssign_Eval.
    180  1.3  rillig # expect: : Making var-scope-local-default.o with VAR="global".
    181  1.3  rillig 
    182  1.3  rillig # Using the variable assignment operator ':=' provides another way of
    183  1.3  rillig # accessing a global variable and extending it with local modifications.  The
    184  1.3  rillig # '$' has to be written as '$$' though to survive the expansion of the
    185  1.3  rillig # dependency line as a whole.
    186  1.3  rillig var-scope-local-subst.o: VAR := $${VAR}+local
    187  1.3  rillig 
    188  1.3  rillig # The variable assignment operator '!=' assigns the output of the shell
    189  1.3  rillig # command, as everywhere else.
    190  1.3  rillig var-scope-local-shell.o: VAR != echo output
    191  1.3  rillig 
    192  1.3  rillig 
    193  1.3  rillig # While VAR=use will be set for a .USE node, it will never be seen since only
    194  1.3  rillig # the ultimate target's context is searched; the variable assignments from the
    195  1.3  rillig # .USE target are not copied to the ultimate target's.
    196  1.2     sjg a_use: .USE VAR=use
    197  1.2     sjg 	: ${.TARGET} uses .USE VAR="${VAR}"
    198  1.2     sjg 
    199  1.3  rillig all: var-scope-local-use.o
    200  1.3  rillig var-scope-local-use.o: a_use
    201  1.4  rillig 
    202  1.4  rillig 
    203  1.4  rillig # Since parse.c 1.656 from 2022-01-27 and before parse.c 1.662 from
    204  1.4  rillig # 2022-02-05, there was an out-of-bounds read in Parse_IsVar when looking for
    205  1.4  rillig # a variable assignment in a dependency line with trailing whitespace.  Lines
    206  1.4  rillig # without trailing whitespace were not affected.  Global variable assignments
    207  1.4  rillig # were guaranteed to have no trailing whitespace and were thus not affected.
    208  1.4  rillig #
    209  1.4  rillig # Try to reproduce some variants that may lead to a crash, depending on the
    210  1.4  rillig # memory allocator.  To get a crash, the terminating '\0' of the line must be
    211  1.4  rillig # the last byte of a memory page.  The expression '${:U}' forces this trailing
    212  1.4  rillig # whitespace.
    213  1.4  rillig 
    214  1.4  rillig # On FreeBSD x86_64, a crash could in some cases be forced using the following
    215  1.4  rillig # line, which has length 47, so the terminating '\0' may end up at an address
    216  1.4  rillig # of the form 0xXXXX_XXXX_XXXX_Xfff:
    217  1.4  rillig Try_to_crash_FreeBSD.xxxxxxxxxxxxxxxxxx: 12345 ${:U}
    218  1.4  rillig 
    219  1.4  rillig # The following line has length 4095, so line[4095] == '\0'.  If the line is
    220  1.4  rillig # allocated on a page boundary and the following page is not mapped, this line
    221  1.4  rillig # leads to a segmentation fault.
    222  1.4  rillig ${:U:range=511:@_@1234567@:ts.}: 12345 ${:U}
    223  1.4  rillig 
    224  1.4  rillig # The following line has length 8191, so line[8191] == '\0'.  If the line is
    225  1.4  rillig # allocated on a page boundary and the following page is not mapped, this line
    226  1.4  rillig # leads to a segmentation fault.
    227  1.4  rillig ${:U:range=1023:@_@1234567@:ts.}: 12345 ${:U}
    228  1.4  rillig 
    229  1.4  rillig 12345:
    230