1# $NetBSD: varparse-undef-partial.mk,v 1.3 2020/11/04 05:10:01 rillig Exp $ 2 3# When an undefined variable is expanded in a ':=' assignment, only the 4# initial '$' of the variable expression is skipped by the parser, while 5# the remaining expression is evaluated. In edge cases this can lead to 6# a completely different interpretation of the partially expanded text. 7 8LIST= ${DEF} ${UNDEF} ${VAR.${PARAM}} end 9DEF= defined 10PARAM= :Q 11 12# The expression ${VAR.${PARAM}} refers to the variable named "VAR.:Q", 13# with the ":Q" being part of the name. This variable is not defined, 14# therefore the initial '$' of that whole expression is skipped by the 15# parser (see Var_Subst, the Buf_AddByte in the else branch) and the rest 16# of the expression is expanded as usual. 17# 18# The resulting variable expression is ${VAR.:Q}, which means that the 19# interpretation of the ":Q" has changed from being part of the variable 20# name to being a variable modifier. This is a classical code injection. 21EVAL:= ${LIST} 22.if ${EVAL} != "defined end" 23. error ${EVAL} 24.endif 25 26# Define the possible outcomes, to see which of them gets expanded. 27VAR.= var-dot without parameter 28${:UVAR.\:Q}= var-dot with parameter :Q 29 30# At this point, the variable "VAR." is defined, therefore the expression 31# ${VAR.:Q} is expanded, consisting of the variable name "VAR." and the 32# modifier ":Q". 33.if ${EVAL} != "defined var-dot\\ without\\ parameter end" 34. error ${EVAL} 35.endif 36 37# In contrast to the previous line, evaluating the original LIST again now 38# produces a different result since the variable named "VAR.:Q" is now 39# defined. It is expanded as usual, interpreting the ":Q" as part of the 40# variable name, as would be expected from reading the variable expression. 41EVAL:= ${LIST} 42.if ${EVAL} != "defined var-dot with parameter :Q end" 43. error ${EVAL} 44.endif 45 46# It's difficult to decide what the best behavior is in this situation. 47# Should the whole expression be skipped for now, or should the inner 48# subexpressions be expanded already? 49# 50# Example 1: 51# CFLAGS:= ${CFLAGS:N-W*} ${COPTS.${COMPILER}} 52# 53# The variable COMPILER typically contains an identifier and the variable is 54# not modified later. In this practical case, it does not matter whether the 55# expression is expanded early, or whether the whole ${COPTS.${COMPILER}} is 56# expanded as soon as the variable COPTS.${COMPILER} becomes defined. The 57# expression ${COMPILER} would be expanded several times, but in this simple 58# scenario there would not be any side effects. 59# 60# TODO: Add a practical example where early/lazy expansion actually makes a 61# difference. 62 63all: 64 @: 65