Home | History | Annotate | Line # | Download | only in unit-tests
var-op-expand.mk revision 1.14
      1  1.14  rillig # $NetBSD: var-op-expand.mk,v 1.14 2021/11/20 17:47:33 rillig Exp $
      2   1.1  rillig #
      3   1.2  rillig # Tests for the := variable assignment operator, which expands its
      4   1.2  rillig # right-hand side.
      5   1.1  rillig 
      6  1.11     sjg .MAKE.SAVE_DOLLARS:=      yes
      7   1.5  rillig 
      8   1.5  rillig # If the right-hand side does not contain a dollar sign, the ':=' assignment
      9   1.5  rillig # operator has the same effect as the '=' assignment operator.
     10   1.5  rillig VAR:=			value
     11   1.5  rillig .if ${VAR} != "value"
     12   1.5  rillig .  error
     13   1.5  rillig .endif
     14   1.5  rillig 
     15   1.5  rillig # When a ':=' assignment is performed, its right-hand side is evaluated and
     16   1.5  rillig # expanded as far as possible.  Contrary to other situations, '$$' and
     17   1.5  rillig # variable expressions based on undefined variables are preserved though.
     18   1.5  rillig #
     19   1.5  rillig # Whether a variable expression is undefined or not is determined at the end
     20   1.5  rillig # of evaluating the expression.  The consequence is that ${:Ufallback} expands
     21   1.5  rillig # to "fallback"; initially this expression is undefined since it is based on
     22   1.5  rillig # the variable named "", which is guaranteed to be never defined, but at the
     23   1.5  rillig # end of evaluating the expression ${:Ufallback}, the modifier ':U' has turned
     24   1.5  rillig # the expression into a defined expression.
     25   1.5  rillig 
     26   1.5  rillig 
     27   1.5  rillig # literal dollar signs
     28   1.5  rillig VAR:=		$$ $$$$ $$$$$$$$
     29   1.5  rillig .if ${VAR} != "\$ \$\$ \$\$\$\$"
     30   1.5  rillig .  error
     31   1.5  rillig .endif
     32   1.5  rillig 
     33   1.5  rillig 
     34   1.5  rillig # reference to a variable containing a literal dollar sign
     35   1.5  rillig REF=		$$ $$$$ $$$$$$$$
     36   1.5  rillig VAR:=		${REF}
     37   1.5  rillig REF=		too late
     38   1.5  rillig .if ${VAR} != "\$ \$\$ \$\$\$\$"
     39   1.5  rillig .  error
     40   1.5  rillig .endif
     41   1.5  rillig 
     42   1.5  rillig 
     43   1.5  rillig # reference to an undefined variable
     44   1.5  rillig .undef UNDEF
     45   1.5  rillig VAR:=		<${UNDEF}>
     46   1.5  rillig UNDEF=		after
     47   1.5  rillig .if ${VAR} != "<after>"
     48   1.5  rillig .  error
     49   1.5  rillig .endif
     50   1.5  rillig 
     51   1.5  rillig 
     52   1.5  rillig # reference to a variable whose name is computed from another variable
     53   1.5  rillig REF2=		referred to
     54   1.5  rillig REF=		REF2
     55   1.5  rillig VAR:=		${${REF}}
     56   1.5  rillig REF=		too late
     57   1.5  rillig .if ${VAR} != "referred to"
     58   1.5  rillig .  error
     59   1.5  rillig .endif
     60   1.5  rillig 
     61   1.5  rillig 
     62   1.5  rillig # expression with an indirect modifier referring to an undefined variable
     63   1.5  rillig .undef UNDEF
     64   1.5  rillig VAR:=		${:${UNDEF}}
     65   1.5  rillig UNDEF=		Uwas undefined
     66   1.5  rillig .if ${VAR} != "was undefined"
     67   1.5  rillig .  error
     68   1.5  rillig .endif
     69   1.5  rillig 
     70   1.5  rillig 
     71   1.5  rillig # expression with an indirect modifier referring to another variable that
     72   1.5  rillig # in turn refers to an undefined variable
     73   1.5  rillig #
     74   1.5  rillig # XXX: Even though this is a ':=' assignment, the '${UNDEF}' in the part of
     75   1.5  rillig # the variable modifier is not preserved.  To preserve it, ParseModifierPart
     76   1.5  rillig # would have to call VarSubstExpr somehow since this is the only piece of
     77   1.5  rillig # code that takes care of this global variable.
     78   1.5  rillig .undef UNDEF
     79   1.5  rillig REF=		U${UNDEF}
     80   1.5  rillig #.MAKEFLAGS: -dv
     81   1.5  rillig VAR:=		${:${REF}}
     82   1.5  rillig #.MAKEFLAGS: -d0
     83   1.5  rillig REF=		too late
     84   1.5  rillig UNDEF=		Uwas undefined
     85   1.5  rillig .if ${VAR} != ""
     86   1.5  rillig .  error
     87   1.5  rillig .endif
     88   1.5  rillig 
     89   1.1  rillig 
     90   1.6  rillig # In variable assignments using the ':=' operator, undefined variables are
     91   1.6  rillig # preserved, no matter how indirectly they are referenced.
     92   1.6  rillig .undef REF3
     93   1.6  rillig REF2=		<${REF3}>
     94   1.6  rillig REF=		${REF2}
     95   1.6  rillig VAR:=		${REF}
     96   1.6  rillig REF3=		too late
     97   1.6  rillig .if ${VAR} != "<too late>"
     98   1.6  rillig .  error
     99   1.6  rillig .endif
    100   1.6  rillig 
    101   1.6  rillig 
    102   1.6  rillig # In variable assignments using the ':=' operator, '$$' are preserved, no
    103   1.6  rillig # matter how indirectly they are referenced.
    104   1.6  rillig REF2=		REF2:$$ $$$$
    105   1.6  rillig REF=		REF:$$ $$$$ ${REF2}
    106   1.6  rillig VAR:=		VAR:$$ $$$$ ${REF}
    107   1.6  rillig .if ${VAR} != "VAR:\$ \$\$ REF:\$ \$\$ REF2:\$ \$\$"
    108   1.6  rillig .  error
    109   1.6  rillig .endif
    110   1.6  rillig 
    111   1.6  rillig 
    112   1.6  rillig # In variable assignments using the ':=' operator, '$$' are preserved in the
    113   1.6  rillig # expressions of the top level, but not in expressions that are nested.
    114   1.6  rillig VAR:=		top:$$ ${:Unest1\:\$\$} ${:Unest2${:U\:\$\$}}
    115   1.6  rillig .if ${VAR} != "top:\$ nest1:\$ nest2:\$"
    116   1.6  rillig .  error
    117   1.6  rillig .endif
    118   1.6  rillig 
    119   1.6  rillig 
    120   1.9  rillig # In variable assignments using the ':=' operator, there may be expressions
    121   1.9  rillig # containing variable modifiers, and these modifiers may refer to other
    122  1.10  rillig # variables.  These referred-to variables are expanded at the time of
    123  1.10  rillig # assignment.  The undefined variables are kept as-is and are later expanded
    124  1.10  rillig # when evaluating the condition.
    125   1.9  rillig #
    126   1.9  rillig # Contrary to the assignment operator '=', the assignment operator ':='
    127   1.9  rillig # consumes the '$' from modifier parts.
    128   1.9  rillig REF.word=	1:$$ 2:$$$$ 4:$$$$$$$$
    129  1.10  rillig .undef REF.undef
    130  1.10  rillig VAR:=		${:Uword undef:@word@${REF.${word}}@}, direct: ${REF.word} ${REF.undef}
    131  1.10  rillig REF.word=	word.after
    132  1.10  rillig REF.undef=	undef.after
    133  1.10  rillig .if ${VAR} != "1:2:\$ 4:\$\$ undef.after, direct: 1:\$ 2:\$\$ 4:\$\$\$\$ undef.after"
    134   1.9  rillig .  error
    135   1.9  rillig .endif
    136   1.9  rillig 
    137   1.9  rillig # Just for comparison, the previous example using the assignment operator '='
    138  1.10  rillig # instead of ':='.  The right-hand side of the assignment is not evaluated at
    139  1.10  rillig # the time of assignment but only later, when ${VAR} appears in the condition.
    140  1.10  rillig #
    141  1.10  rillig # At that point, both REF.word and REF.undef are defined.
    142   1.9  rillig REF.word=	1:$$ 2:$$$$ 4:$$$$$$$$
    143  1.10  rillig .undef REF.undef
    144  1.10  rillig VAR=		${:Uword undef:@word@${REF.${word}}@}, direct: ${REF.word} ${REF.undef}
    145  1.10  rillig REF.word=	word.after
    146  1.10  rillig REF.undef=	undef.after
    147  1.10  rillig .if ${VAR} != "word.after undef.after, direct: word.after undef.after"
    148   1.9  rillig .  error
    149   1.9  rillig .endif
    150   1.9  rillig 
    151   1.9  rillig 
    152   1.8  rillig # Between var.c 1.42 from 2000-05-11 and before parse.c 1.520 from 2020-12-27,
    153   1.8  rillig # if the variable name in a ':=' assignment referred to an undefined variable,
    154   1.8  rillig # there were actually 2 assignments to different variables:
    155   1.8  rillig #
    156   1.8  rillig #	Global["VAR_SUBST_${UNDEF}"] = ""
    157   1.8  rillig #	Global["VAR_SUBST_"] = ""
    158   1.8  rillig #
    159   1.8  rillig # The variable name with the empty value actually included a dollar sign.
    160   1.8  rillig # Variable names with dollars are not used in practice.
    161   1.8  rillig #
    162   1.8  rillig # It might be a good idea to forbid undefined variables on the left-hand side
    163   1.8  rillig # of a variable assignment.
    164   1.5  rillig .undef UNDEF
    165   1.7  rillig VAR_ASSIGN_${UNDEF}=	assigned by '='
    166   1.7  rillig VAR_SUBST_${UNDEF}:=	assigned by ':='
    167   1.7  rillig .if ${VAR_ASSIGN_} != "assigned by '='"
    168   1.7  rillig .  error
    169   1.7  rillig .endif
    170   1.8  rillig .if defined(${:UVAR_SUBST_\${UNDEF\}})
    171   1.7  rillig .  error
    172   1.7  rillig .endif
    173   1.7  rillig .if ${VAR_SUBST_} != "assigned by ':='"
    174   1.7  rillig .  error
    175   1.7  rillig .endif
    176   1.3  rillig 
    177  1.12  rillig 
    178  1.12  rillig # The following test case demonstrates that the variable 'LATER' is preserved
    179  1.12  rillig # in the ':=' assignment since the variable 'LATER' is not yet defined.
    180  1.12  rillig # After the assignment to 'LATER', evaluating the variable 'INDIRECT'
    181  1.12  rillig # evaluates 'LATER' as well.
    182  1.12  rillig #
    183  1.12  rillig .undef LATER
    184  1.12  rillig INDIRECT:=	${LATER:S,value,replaced,}
    185  1.12  rillig .if ${INDIRECT} != ""
    186  1.12  rillig .  error
    187  1.12  rillig .endif
    188  1.12  rillig LATER=	late-value
    189  1.12  rillig .if ${INDIRECT} != "late-replaced"
    190  1.12  rillig .  error
    191  1.12  rillig .endif
    192  1.12  rillig 
    193  1.12  rillig 
    194  1.12  rillig # Same as the test case above, except for the additional modifier ':tl' when
    195  1.12  rillig # evaluating the variable 'INDIRECT'.  Nothing surprising here.
    196  1.12  rillig .undef LATER
    197  1.12  rillig .undef later
    198  1.12  rillig INDIRECT:=	${LATER:S,value,replaced,}
    199  1.12  rillig .if ${INDIRECT:tl} != ""
    200  1.12  rillig .  error
    201  1.12  rillig .endif
    202  1.12  rillig LATER=	uppercase-value
    203  1.12  rillig later=	lowercase-value
    204  1.12  rillig .if ${INDIRECT:tl} != "uppercase-replaced"
    205  1.12  rillig .  error
    206  1.12  rillig .endif
    207  1.12  rillig 
    208  1.12  rillig 
    209  1.12  rillig # Similar to the two test cases above, the situation gets a bit more involved
    210  1.12  rillig # here, due to the double indirection.  The variable 'indirect' is supposed to
    211  1.12  rillig # be the lowercase version of the variable 'INDIRECT'.
    212  1.12  rillig #
    213  1.12  rillig # The assignment operator ':=' for the variable 'INDIRECT' could be a '=' as
    214  1.12  rillig # well, it wouldn't make a difference in this case.  The crucial detail is the
    215  1.14  rillig # assignment operator ':=' for the variable 'indirect'.  During this
    216  1.12  rillig # assignment, the variable modifier ':S,value,replaced,' is converted to
    217  1.12  rillig # lowercase, which turns 'S' into 's', thus producing an unknown modifier.
    218  1.12  rillig # In this case, make issues a warning, but in cases where the modifier
    219  1.12  rillig # includes a '=', the modifier would be interpreted as a SysV-style
    220  1.12  rillig # substitution like '.c=.o', and make would not issue a warning, leading to
    221  1.12  rillig # silent unexpected behavior.
    222  1.12  rillig #
    223  1.14  rillig # As of 2021-11-20, the actual behavior is unexpected.  Fixing it is not
    224  1.14  rillig # trivial.  When the assignment to 'indirect' takes place, the expressions
    225  1.14  rillig # from the nested expression could be preserved, like this:
    226  1.14  rillig #
    227  1.14  rillig #	Start with:
    228  1.14  rillig #
    229  1.14  rillig #		indirect:=	${INDIRECT:tl}
    230  1.14  rillig #
    231  1.14  rillig #	Since INDIRECT is defined, expand it, remembering that the modifier
    232  1.14  rillig #	':tl' must still be applied to the final result.
    233  1.14  rillig #
    234  1.14  rillig #		indirect:=	${LATER:S,value,replaced,} \
    235  1.14  rillig #				OK \
    236  1.14  rillig #				${LATER:value=sysv}
    237  1.14  rillig #
    238  1.14  rillig #	The variable 'LATER' is not defined.  An idea may be to append the
    239  1.14  rillig #	remaining modifier ':tl' to each expression that is starting with an
    240  1.14  rillig #	undefined variable, resulting in:
    241  1.14  rillig #
    242  1.14  rillig #		indirect:=	${LATER:S,value,replaced,:tl} \
    243  1.14  rillig #				OK \
    244  1.14  rillig #				${LATER:value=sysv:tl}
    245  1.14  rillig #
    246  1.14  rillig #	This would work for the first expression.  The second expression ends
    247  1.14  rillig #	with the SysV modifier ':from=to', and when this modifier is parsed,
    248  1.14  rillig #	it consumes all characters until the end of the expression, which in
    249  1.14  rillig #	this case would replace the suffix 'value' with the literal 'sysv:tl',
    250  1.14  rillig #	ignoring that the ':tl' was intended to be an additional modifier.
    251  1.14  rillig #
    252  1.14  rillig # Due to all of this, this surprising behavior is not easy to fix.
    253  1.14  rillig #
    254  1.12  rillig .undef LATER
    255  1.12  rillig .undef later
    256  1.13  rillig INDIRECT:=	${LATER:S,value,replaced,} OK ${LATER:value=sysv}
    257  1.12  rillig indirect:=	${INDIRECT:tl}
    258  1.12  rillig # expect+1: Unknown modifier "s,value,replaced,"
    259  1.13  rillig .if ${indirect} != " ok "
    260  1.12  rillig .  error
    261  1.12  rillig .else
    262  1.12  rillig .  warning	XXX Neither branch should be taken.
    263  1.12  rillig .endif
    264  1.12  rillig LATER=	uppercase-value
    265  1.12  rillig later=	lowercase-value
    266  1.12  rillig # expect+1: Unknown modifier "s,value,replaced,"
    267  1.13  rillig .if ${indirect} != "uppercase-replaced ok uppercase-sysv"
    268  1.12  rillig .  warning	XXX Neither branch should be taken.
    269  1.12  rillig .else
    270  1.12  rillig .  error
    271  1.12  rillig .endif
    272  1.12  rillig 
    273  1.12  rillig 
    274   1.1  rillig all:
    275   1.1  rillig 	@:;
    276