var-op-sunsh.mk revision 1.10 1 1.10 rillig # $NetBSD: var-op-sunsh.mk,v 1.10 2022/02/09 21:09:24 rillig Exp $
2 1.1 rillig #
3 1.1 rillig # Tests for the :sh= variable assignment operator, which runs its right-hand
4 1.1 rillig # side through the shell. It is a seldom-used alternative to the !=
5 1.10 rillig # assignment operator, adopted from Sun make.
6 1.1 rillig
7 1.1 rillig .MAKEFLAGS: -dL # Enable sane error messages
8 1.1 rillig
9 1.1 rillig # This is the idiomatic form of the Sun shell assignment operator.
10 1.1 rillig # The assignment operator is directly preceded by the ':sh'.
11 1.1 rillig VAR:sh= echo colon-sh
12 1.1 rillig .if ${VAR} != "colon-sh"
13 1.1 rillig . error
14 1.1 rillig .endif
15 1.1 rillig
16 1.2 rillig # It is also possible to have whitespace around the :sh assignment
17 1.2 rillig # operator modifier.
18 1.2 rillig VAR :sh = echo colon-sh-spaced
19 1.2 rillig .if ${VAR} != "colon-sh-spaced"
20 1.2 rillig . error
21 1.2 rillig .endif
22 1.2 rillig
23 1.2 rillig # Until 2020-10-04, the ':sh' could even be followed by other characters.
24 1.2 rillig # This was neither documented by NetBSD make nor by Solaris make and was
25 1.2 rillig # an implementation error.
26 1.2 rillig #
27 1.9 rillig # Since 2020-10-04, this is a normal variable assignment to the variable named
28 1.9 rillig # 'VAR:shell', using the '=' assignment operator.
29 1.1 rillig VAR:shell= echo colon-shell
30 1.9 rillig # The variable name needs to be generated using a ${:U...} expression because
31 1.9 rillig # it is not possible to express the ':' as part of a literal variable name,
32 1.9 rillig # see ParseVarname.
33 1.2 rillig .if ${${:UVAR\:shell}} != "echo colon-shell"
34 1.1 rillig . error
35 1.1 rillig .endif
36 1.1 rillig
37 1.2 rillig # Several colons can syntactically appear in a variable name.
38 1.2 rillig # Until 2020-10-04, the last of them was interpreted as the ':sh'
39 1.2 rillig # assignment operator.
40 1.2 rillig #
41 1.2 rillig # Since 2020-10-04, the colons are part of the variable name.
42 1.1 rillig VAR:shoe:shore= echo two-colons
43 1.2 rillig .if ${${:UVAR\:shoe\:shore}} != "echo two-colons"
44 1.1 rillig . error
45 1.1 rillig .endif
46 1.1 rillig
47 1.2 rillig # Until 2020-10-04, the following expression was wrongly marked as
48 1.2 rillig # a parse error. This was because the parser for variable assignments
49 1.2 rillig # just looked for the previous ":sh", without taking any contextual
50 1.2 rillig # information into account.
51 1.1 rillig #
52 1.1 rillig # There are two different syntactical elements that look exactly the same:
53 1.1 rillig # The variable modifier ':sh' and the assignment operator modifier ':sh'.
54 1.2 rillig # Intuitively this variable name contains the variable modifier, but until
55 1.2 rillig # 2020-10-04, the parser regarded it as an assignment operator modifier, in
56 1.8 rillig # Parse_Var.
57 1.2 rillig VAR.${:Uecho 123:sh}= ok-123
58 1.2 rillig .if ${VAR.123} != "ok-123"
59 1.1 rillig . error
60 1.1 rillig .endif
61 1.1 rillig
62 1.2 rillig # Same pattern here. Until 2020-10-04, the ':sh' inside the nested expression
63 1.2 rillig # was taken for the :sh assignment operator modifier, even though it was
64 1.2 rillig # escaped by a backslash.
65 1.2 rillig VAR.${:U echo\:shell}= ok-shell
66 1.2 rillig .if ${VAR.${:U echo\:shell}} != "ok-shell"
67 1.1 rillig . error
68 1.1 rillig .endif
69 1.1 rillig
70 1.2 rillig # Until 2020-10-04, the word 'shift' was also affected since it starts with
71 1.2 rillig # ':sh'.
72 1.2 rillig VAR.key:shift= Shift
73 1.2 rillig .if ${${:UVAR.key\:shift}} != "Shift"
74 1.1 rillig . error
75 1.1 rillig .endif
76 1.1 rillig
77 1.3 rillig # Just for fun: The code in Parse_IsVar allows for multiple appearances of
78 1.3 rillig # the ':sh' assignment operator modifier. Let's see what happens ...
79 1.3 rillig #
80 1.3 rillig # Well, the end result is correct but the way until there is rather
81 1.7 rillig # adventurous. This only works because the parser replaces each and every
82 1.8 rillig # whitespace character that is not nested with '\0' (see Parse_Var).
83 1.3 rillig # The variable name therefore ends before the first ':sh', and the last
84 1.3 rillig # ':sh' turns the assignment operator into the shell command evaluation.
85 1.8 rillig # Parse_Var completely trusts Parse_IsVar to properly verify the syntax.
86 1.3 rillig #
87 1.3 rillig # The ':sh' is the only word that may occur between the variable name and
88 1.5 rillig # the assignment operator at nesting level 0. All other words would lead
89 1.5 rillig # to a parse error since the left-hand side of an assignment must be
90 1.5 rillig # exactly one word.
91 1.3 rillig VAR :sh :sh :sh :sh= echo multiple
92 1.3 rillig .if ${VAR} != "multiple"
93 1.3 rillig . error
94 1.3 rillig .endif
95 1.3 rillig
96 1.4 rillig # The word ':sh' is not the only thing that can occur after a variable name.
97 1.4 rillig # Since the parser just counts braces and parentheses instead of properly
98 1.4 rillig # expanding nested expressions, the token ' :sh' can be used to add arbitrary
99 1.4 rillig # text between the variable name and the assignment operator, it just has to
100 1.4 rillig # be enclosed in braces or parentheses.
101 1.9 rillig #
102 1.9 rillig # Since the text to the left of the assignment operator '=' does not end with
103 1.9 rillig # ':sh', the effective assignment operator becomes '=', not '!='.
104 1.4 rillig VAR :sh(Put a comment here)= comment in parentheses
105 1.4 rillig .if ${VAR} != "comment in parentheses"
106 1.4 rillig . error
107 1.4 rillig .endif
108 1.4 rillig
109 1.4 rillig # The unintended comment can include multiple levels of nested braces and
110 1.9 rillig # parentheses. Braces and parentheses are interchangeable, that is, a '(' can
111 1.9 rillig # be closed by either ')' or '}'. These braces and parentheses are only
112 1.9 rillig # counted by Parse_IsVar, in particular Parse_Var doesn't see them.
113 1.4 rillig VAR :sh{Put}((((a}{comment}}}}{here}= comment in braces
114 1.4 rillig .if ${VAR} != "comment in braces"
115 1.4 rillig . error
116 1.4 rillig .endif
117 1.4 rillig
118 1.9 rillig # The assignment modifier ':sh' can be combined with the assignment operator
119 1.9 rillig # '+='. In such a case the ':sh' is silently ignored, and the effective
120 1.9 rillig # assignment operator is '+='.
121 1.5 rillig #
122 1.9 rillig # XXX: This combination should not be allowed at all, as it is confusing.
123 1.5 rillig VAR= one
124 1.5 rillig VAR :sh += echo two
125 1.5 rillig .if ${VAR} != "one echo two"
126 1.5 rillig . error ${VAR}
127 1.5 rillig .endif
128 1.5 rillig
129 1.9 rillig # The assignment modifier ':sh' can be combined with the assignment operator
130 1.9 rillig # '!='. In such a case the ':sh' is silently ignored, and the effective
131 1.9 rillig # assignment operator is '!=', just like with '+=' or the other compound
132 1.9 rillig # assignment operators.
133 1.9 rillig #
134 1.9 rillig # XXX: This combination should not be allowed at all, as it is confusing.
135 1.9 rillig VAR :sh != echo echo echo echo spaces-around
136 1.9 rillig .if ${VAR} != "echo echo echo spaces-around"
137 1.9 rillig . error ${VAR}
138 1.9 rillig .endif
139 1.9 rillig
140 1.9 rillig # If there is no space between the variable name and the assignment modifier
141 1.9 rillig # ':sh', the ':sh' becomes part of the variable name, as the parser only
142 1.9 rillig # expects a single assignment modifier to the left of the '=', which in this
143 1.9 rillig # case is the '!'.
144 1.9 rillig VAR:sh != echo echo echo echo space-after
145 1.9 rillig .if ${${:UVAR\:sh}} != "echo echo echo space-after"
146 1.9 rillig . error ${${:UVAR\:sh}}
147 1.9 rillig .endif
148 1.6 rillig
149 1.9 rillig all: .PHONY
150