directive-ifmake.mk revision 1.12 1 1.12 rillig # $NetBSD: directive-ifmake.mk,v 1.12 2023/11/19 21:47:52 rillig Exp $
2 1.1 rillig #
3 1.3 rillig # Tests for the .ifmake directive, which provides a shortcut for asking
4 1.3 rillig # whether a certain target is requested to be made from the command line.
5 1.8 rillig #
6 1.8 rillig # TODO: Describe why the shortcut may be useful (if it's useful at all),
7 1.10 rillig # instead of using the more general '.if make(target)'.
8 1.1 rillig
9 1.9 rillig .MAKEFLAGS: first second
10 1.7 rillig
11 1.3 rillig # This is the most basic form.
12 1.3 rillig .ifmake first
13 1.11 rillig # expect+1: ok: positive condition works
14 1.5 rillig . info ok: positive condition works
15 1.3 rillig .else
16 1.5 rillig . warning positive condition fails
17 1.3 rillig .endif
18 1.1 rillig
19 1.9 rillig # The '!' is interpreted as 'not'. A possible alternative interpretation of
20 1.9 rillig # this condition is whether the target named "!first" was requested. To
21 1.9 rillig # distinguish these cases, see the next test.
22 1.3 rillig .ifmake !first
23 1.5 rillig . warning unexpected
24 1.3 rillig .else
25 1.11 rillig # expect+1: ok: negation works
26 1.5 rillig . info ok: negation works
27 1.3 rillig .endif
28 1.3 rillig
29 1.3 rillig # See if the exclamation mark really means "not", or if it is just part of
30 1.8 rillig # the target name. Since it means 'not', the two exclamation marks are
31 1.8 rillig # effectively ignored, and 'first' is indeed a requested target. If the
32 1.8 rillig # exclamation mark were part of the name instead, the name would be '!!first',
33 1.8 rillig # and such a target was not requested to be made.
34 1.3 rillig .ifmake !!first
35 1.11 rillig # expect+1: ok: double negation works
36 1.5 rillig . info ok: double negation works
37 1.3 rillig .else
38 1.5 rillig . warning double negation fails
39 1.3 rillig .endif
40 1.3 rillig
41 1.3 rillig # Multiple targets can be combined using the && and || operators.
42 1.3 rillig .ifmake first && second
43 1.11 rillig # expect+1: ok: both mentioned
44 1.5 rillig . info ok: both mentioned
45 1.3 rillig .else
46 1.5 rillig . warning && does not work as expected
47 1.3 rillig .endif
48 1.3 rillig
49 1.3 rillig # Negation also works in complex conditions.
50 1.3 rillig .ifmake first && !unmentioned
51 1.11 rillig # expect+1: ok: only those mentioned
52 1.5 rillig . info ok: only those mentioned
53 1.3 rillig .else
54 1.5 rillig . warning && with ! does not work as expected
55 1.3 rillig .endif
56 1.3 rillig
57 1.4 rillig # Using the .MAKEFLAGS special dependency target, arbitrary command
58 1.4 rillig # line options can be added at parse time. This means that it is
59 1.4 rillig # possible to extend the targets to be made.
60 1.4 rillig .MAKEFLAGS: late-target
61 1.4 rillig .ifmake late-target
62 1.11 rillig # expect+1: Targets can even be added at parse time.
63 1.5 rillig . info Targets can even be added at parse time.
64 1.4 rillig .else
65 1.5 rillig . info No, targets cannot be added at parse time anymore.
66 1.4 rillig .endif
67 1.4 rillig
68 1.6 rillig # Numbers are interpreted as numbers, no matter whether the directive is
69 1.6 rillig # a plain .if or an .ifmake.
70 1.6 rillig .ifmake 0
71 1.6 rillig . error
72 1.6 rillig .endif
73 1.6 rillig .ifmake 1
74 1.6 rillig .else
75 1.6 rillig . error
76 1.6 rillig .endif
77 1.6 rillig
78 1.12 rillig # A condition that consists of an expression only (without any
79 1.7 rillig # comparison operator) can be used with .if and the other .ifxxx directives.
80 1.7 rillig .ifmake ${:Ufirst}
81 1.11 rillig # expect+1: ok
82 1.7 rillig . info ok
83 1.7 rillig .else
84 1.7 rillig . error
85 1.7 rillig .endif
86 1.7 rillig
87 1.7 rillig
88 1.9 rillig # As an edge case, a target can actually be named "!first" on the command
89 1.9 rillig # line. There is no way to define a target of this name though since in a
90 1.9 rillig # dependency line, a plain '!' is interpreted as a dependency operator.
91 1.9 rillig
92 1.9 rillig .MAKEFLAGS: !edge
93 1.9 rillig .ifmake edge
94 1.9 rillig . error
95 1.9 rillig .endif
96 1.9 rillig
97 1.9 rillig # The '\!edge' in the following condition is parsed as a bare word. For such
98 1.9 rillig # a bare word, there is no escaping mechanism so the backslash passes through.
99 1.9 rillig # Since the condition function 'make' accepts a pattern instead of a plain
100 1.9 rillig # target name, the '\' is finally discarded in Str_Match.
101 1.9 rillig .ifmake \!edge
102 1.9 rillig .else
103 1.9 rillig . error
104 1.9 rillig .endif
105 1.9 rillig
106 1.9 rillig # In a dependency line, a plain '!' is interpreted as a dependency operator
107 1.9 rillig # (the other two are ':' and '::'). If the '!' is escaped by a '\', as
108 1.9 rillig # implemented in ParseDependencyTargetWord, the additional backslash is never
109 1.9 rillig # removed though. The target name thus becomes '\!edge' instead of the
110 1.9 rillig # intended '!edge'. Defining a target whose name contains a '!' will either
111 1.9 rillig # require additional tricks, or it may even be impossible.
112 1.9 rillig
113 1.9 rillig first second unmentioned late-target \!edge:
114 1.3 rillig : $@
115