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