varmod-defined.mk revision 1.13 1 # $NetBSD: varmod-defined.mk,v 1.13 2022/08/24 20:22:10 rillig Exp $
2 #
3 # Tests for the :D variable modifier, which returns the given string
4 # if the variable is defined. It is closely related to the :U modifier.
5
6 # Force the test results to be independent of the default value of this
7 # setting, which is 'yes' for NetBSD's usr.bin/make but 'no' for the bmake
8 # distribution and pkgsrc/devel/bmake.
9 .MAKE.SAVE_DOLLARS= yes
10
11 DEF= defined
12 .undef UNDEF
13
14 # Since DEF is defined, the value of the expression is "value", not
15 # "defined".
16 #
17 .if ${DEF:Dvalue} != "value"
18 . error
19 .endif
20
21 # Since UNDEF is not defined, the "value" is ignored. Instead of leaving the
22 # expression undefined, it is set to "", exactly to allow the expression to
23 # be used in .if conditions. In this place, other undefined expressions
24 # would generate an error message.
25 # XXX: Ideally the error message would be "undefined variable", but as of
26 # 2020-08-25 it is "Malformed conditional".
27 #
28 .if ${UNDEF:Dvalue} != ""
29 . error
30 .endif
31
32 # The modifier text may contain plain text as well as expressions.
33 #
34 .if ${DEF:D<${DEF}>} != "<defined>"
35 . error
36 .endif
37
38 # Special characters that would be interpreted differently can be escaped.
39 # These are '}' (the closing character of the expression), ':', '$' and '\'.
40 # Any other backslash sequences are preserved.
41 #
42 # The escaping rules for string literals in conditions are completely
43 # different though. There, any character may be escaped using a backslash.
44 #
45 .if ${DEF:D \} \: \$ \\ \) \n } != " } : \$ \\ \\) \\n "
46 . error
47 .endif
48
49 # Like in several other places in variable expressions, when
50 # ApplyModifier_Defined calls Var_Parse, double dollars lead to a parse
51 # error that is silently ignored. This makes all dollar signs disappear,
52 # except for the last, which is a well-formed variable expression.
53 #
54 .if ${DEF:D$$$$$${DEF}} != "defined"
55 . error
56 .endif
57
58 # Any other text is written without any further escaping. In contrast
59 # to the :M modifier, parentheses and braces do not need to be nested.
60 # Instead, the :D modifier is implemented sanely by parsing nested
61 # expressions as such, without trying any shortcuts. See ApplyModifier_Match
62 # for an inferior variant.
63 #
64 .if ${DEF:D!&((((} != "!&(((("
65 . error
66 .endif
67
68 # The :D modifier is often used in combination with the :U modifier.
69 # It does not matter in which order the :D and :U modifiers appear.
70 .if ${UNDEF:Dyes:Uno} != no
71 . error
72 .endif
73 .if ${UNDEF:Uno:Dyes} != no
74 . error
75 .endif
76 .if ${DEF:Dyes:Uno} != yes
77 . error
78 .endif
79 .if ${DEF:Uno:Dyes} != yes
80 . error
81 .endif
82
83 # Since the variable with the empty name is never defined, the :D modifier
84 # can be used to add comments in the middle of an expression. That
85 # expression always evaluates to an empty string.
86 .if ${:D This is a comment. } != ""
87 . error
88 .endif
89
90 # TODO: Add more tests for parsing the plain text part, to cover each branch
91 # of ApplyModifier_Defined.
92
93 # The :D and :U modifiers behave differently from the :@var@ modifier in
94 # that they preserve dollars in a ':=' assignment. This is because
95 # ApplyModifier_Defined passes the emode unmodified to Var_Parse, unlike
96 # ApplyModifier_Loop, which uses ParseModifierPart, which in turn removes
97 # the keepDollar flag from emode.
98 #
99 # XXX: This inconsistency is documented nowhere.
100 .MAKEFLAGS: -dv
101 8_DOLLARS= $$$$$$$$
102 VAR:= ${8_DOLLARS}
103 VAR:= ${VAR:D${8_DOLLARS}}
104 VAR:= ${VAR:@var@${8_DOLLARS}@}
105 .MAKEFLAGS: -d0
106
107
108 # Before var.c 1.1030 from 2022-08-24, the following expression caused an
109 # out-of-bounds read when parsing the indirect ':D' modifier.
110 M_U_backslash:= ${:UU\\}
111 .if ${:${M_U_backslash}} != "\\"
112 . error
113 .endif
114
115
116 all: .PHONY
117