64 lines
2.5 KiB
Makefile
64 lines
2.5 KiB
Makefile
# $NetBSD: varparse-undef-partial.mk,v 1.5 2024/01/07 11:39:04 rillig Exp $
|
|
|
|
# When an undefined variable is expanded in a ':=' assignment, only the
|
|
# initial '$' of the expression is skipped by the parser, while
|
|
# the remaining expression is evaluated. In edge cases this can lead to
|
|
# a completely different interpretation of the partially expanded text.
|
|
|
|
LIST= ${DEF} ${UNDEF} ${VAR.${PARAM}} end
|
|
DEF= defined
|
|
PARAM= :Q
|
|
|
|
# The expression ${VAR.${PARAM}} refers to the variable named "VAR.:Q",
|
|
# with the ":Q" being part of the name. This variable is not defined,
|
|
# therefore the initial '$' of that whole expression is skipped by the parser
|
|
# (see VarSubstExpr) and the rest of the expression is expanded as usual.
|
|
#
|
|
# The resulting expression is ${VAR.:Q}, which means that the
|
|
# interpretation of the ":Q" has changed from being part of the variable
|
|
# name to being a variable modifier. This is a classical code injection.
|
|
EVAL:= ${LIST}
|
|
.if ${EVAL} != "defined end"
|
|
. error ${EVAL}
|
|
.endif
|
|
|
|
# Define the possible outcomes, to see which of them gets expanded.
|
|
VAR.= var-dot without parameter
|
|
${:UVAR.\:Q}= var-dot with parameter :Q
|
|
|
|
# At this point, the variable "VAR." is defined, therefore the expression
|
|
# ${VAR.:Q} is expanded, consisting of the variable name "VAR." and the
|
|
# modifier ":Q".
|
|
.if ${EVAL} != "defined var-dot\\ without\\ parameter end"
|
|
. error ${EVAL}
|
|
.endif
|
|
|
|
# In contrast to the previous line, evaluating the original LIST again now
|
|
# produces a different result since the variable named "VAR.:Q" is now
|
|
# defined. It is expanded as usual, interpreting the ":Q" as part of the
|
|
# variable name, as would be expected from reading the expression.
|
|
EVAL:= ${LIST}
|
|
.if ${EVAL} != "defined var-dot with parameter :Q end"
|
|
. error ${EVAL}
|
|
.endif
|
|
|
|
# It's difficult to decide what the best behavior is in this situation.
|
|
# Should the whole expression be skipped for now, or should the inner
|
|
# subexpressions be expanded already?
|
|
#
|
|
# Example 1:
|
|
# CFLAGS:= ${CFLAGS:N-W*} ${COPTS.${COMPILER}}
|
|
#
|
|
# The variable COMPILER typically contains an identifier and the variable is
|
|
# not modified later. In this practical case, it does not matter whether the
|
|
# expression is expanded early, or whether the whole ${COPTS.${COMPILER}} is
|
|
# expanded as soon as the variable COPTS.${COMPILER} becomes defined. The
|
|
# expression ${COMPILER} would be expanded several times, but in this simple
|
|
# scenario there would not be any side effects.
|
|
#
|
|
# TODO: Add a practical example where early/lazy expansion actually makes a
|
|
# difference.
|
|
|
|
all:
|
|
@:
|