make(1): negate NoExecute to GNode_ShouldExecutediff -r1.172 -r1.173 src/usr.bin/make/compat.c
(rillig)
--- src/usr.bin/make/compat.c 2020/10/31 18:20:00 1.172
+++ src/usr.bin/make/compat.c 2020/11/01 17:47:26 1.173
@@ -1,706 +1,706 @@ | @@ -1,706 +1,706 @@ | |||
1 | /* $NetBSD: compat.c,v 1.172 2020/10/31 18:20:00 rillig Exp $ */ | 1 | /* $NetBSD: compat.c,v 1.173 2020/11/01 17:47:26 rillig Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. | 4 | * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to Berkeley by | 7 | * This code is derived from software contributed to Berkeley by | |
8 | * Adam de Boor. | 8 | * Adam de Boor. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | 15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | 16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | 17 | * documentation and/or other materials provided with the distribution. | |
18 | * 3. Neither the name of the University nor the names of its contributors | 18 | * 3. Neither the name of the University nor the names of its contributors | |
19 | * may be used to endorse or promote products derived from this software | 19 | * may be used to endorse or promote products derived from this software | |
20 | * without specific prior written permission. | 20 | * without specific prior written permission. | |
21 | * | 21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
32 | * SUCH DAMAGE. | 32 | * SUCH DAMAGE. | |
33 | */ | 33 | */ | |
34 | 34 | |||
35 | /* | 35 | /* | |
36 | * Copyright (c) 1988, 1989 by Adam de Boor | 36 | * Copyright (c) 1988, 1989 by Adam de Boor | |
37 | * Copyright (c) 1989 by Berkeley Softworks | 37 | * Copyright (c) 1989 by Berkeley Softworks | |
38 | * All rights reserved. | 38 | * All rights reserved. | |
39 | * | 39 | * | |
40 | * This code is derived from software contributed to Berkeley by | 40 | * This code is derived from software contributed to Berkeley by | |
41 | * Adam de Boor. | 41 | * Adam de Boor. | |
42 | * | 42 | * | |
43 | * Redistribution and use in source and binary forms, with or without | 43 | * Redistribution and use in source and binary forms, with or without | |
44 | * modification, are permitted provided that the following conditions | 44 | * modification, are permitted provided that the following conditions | |
45 | * are met: | 45 | * are met: | |
46 | * 1. Redistributions of source code must retain the above copyright | 46 | * 1. Redistributions of source code must retain the above copyright | |
47 | * notice, this list of conditions and the following disclaimer. | 47 | * notice, this list of conditions and the following disclaimer. | |
48 | * 2. Redistributions in binary form must reproduce the above copyright | 48 | * 2. Redistributions in binary form must reproduce the above copyright | |
49 | * notice, this list of conditions and the following disclaimer in the | 49 | * notice, this list of conditions and the following disclaimer in the | |
50 | * documentation and/or other materials provided with the distribution. | 50 | * documentation and/or other materials provided with the distribution. | |
51 | * 3. All advertising materials mentioning features or use of this software | 51 | * 3. All advertising materials mentioning features or use of this software | |
52 | * must display the following acknowledgement: | 52 | * must display the following acknowledgement: | |
53 | * This product includes software developed by the University of | 53 | * This product includes software developed by the University of | |
54 | * California, Berkeley and its contributors. | 54 | * California, Berkeley and its contributors. | |
55 | * 4. Neither the name of the University nor the names of its contributors | 55 | * 4. Neither the name of the University nor the names of its contributors | |
56 | * may be used to endorse or promote products derived from this software | 56 | * may be used to endorse or promote products derived from this software | |
57 | * without specific prior written permission. | 57 | * without specific prior written permission. | |
58 | * | 58 | * | |
59 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 59 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
60 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 60 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
61 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 61 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
62 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 62 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
63 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 63 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
64 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 64 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
65 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 65 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
66 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 66 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
67 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 67 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
68 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 68 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
69 | * SUCH DAMAGE. | 69 | * SUCH DAMAGE. | |
70 | */ | 70 | */ | |
71 | 71 | |||
72 | /*- | 72 | /*- | |
73 | * compat.c -- | 73 | * compat.c -- | |
74 | * The routines in this file implement the full-compatibility | 74 | * The routines in this file implement the full-compatibility | |
75 | * mode of PMake. Most of the special functionality of PMake | 75 | * mode of PMake. Most of the special functionality of PMake | |
76 | * is available in this mode. Things not supported: | 76 | * is available in this mode. Things not supported: | |
77 | * - different shells. | 77 | * - different shells. | |
78 | * - friendly variable substitution. | 78 | * - friendly variable substitution. | |
79 | * | 79 | * | |
80 | * Interface: | 80 | * Interface: | |
81 | * Compat_Run Initialize things for this module and recreate | 81 | * Compat_Run Initialize things for this module and recreate | |
82 | * thems as need creatin' | 82 | * thems as need creatin' | |
83 | */ | 83 | */ | |
84 | 84 | |||
85 | #include <sys/types.h> | 85 | #include <sys/types.h> | |
86 | #include <sys/stat.h> | 86 | #include <sys/stat.h> | |
87 | #include <sys/wait.h> | 87 | #include <sys/wait.h> | |
88 | 88 | |||
89 | #include <errno.h> | 89 | #include <errno.h> | |
90 | #include <signal.h> | 90 | #include <signal.h> | |
91 | 91 | |||
92 | #include "make.h" | 92 | #include "make.h" | |
93 | #include "dir.h" | 93 | #include "dir.h" | |
94 | #include "job.h" | 94 | #include "job.h" | |
95 | #include "metachar.h" | 95 | #include "metachar.h" | |
96 | #include "pathnames.h" | 96 | #include "pathnames.h" | |
97 | 97 | |||
98 | /* "@(#)compat.c 8.2 (Berkeley) 3/19/94" */ | 98 | /* "@(#)compat.c 8.2 (Berkeley) 3/19/94" */ | |
99 | MAKE_RCSID("$NetBSD: compat.c,v 1.172 2020/10/31 18:20:00 rillig Exp $"); | 99 | MAKE_RCSID("$NetBSD: compat.c,v 1.173 2020/11/01 17:47:26 rillig Exp $"); | |
100 | 100 | |||
101 | static GNode *curTarg = NULL; | 101 | static GNode *curTarg = NULL; | |
102 | static pid_t compatChild; | 102 | static pid_t compatChild; | |
103 | static int compatSigno; | 103 | static int compatSigno; | |
104 | 104 | |||
105 | /* | 105 | /* | |
106 | * CompatDeleteTarget -- delete a failed, interrupted, or otherwise | 106 | * CompatDeleteTarget -- delete a failed, interrupted, or otherwise | |
107 | * duffed target if not inhibited by .PRECIOUS. | 107 | * duffed target if not inhibited by .PRECIOUS. | |
108 | */ | 108 | */ | |
109 | static void | 109 | static void | |
110 | CompatDeleteTarget(GNode *gn) | 110 | CompatDeleteTarget(GNode *gn) | |
111 | { | 111 | { | |
112 | if (gn != NULL && !Targ_Precious(gn)) { | 112 | if (gn != NULL && !Targ_Precious(gn)) { | |
113 | const char *file = GNode_VarTarget(gn); | 113 | const char *file = GNode_VarTarget(gn); | |
114 | 114 | |||
115 | if (!opts.noExecute && eunlink(file) != -1) { | 115 | if (!opts.noExecute && eunlink(file) != -1) { | |
116 | Error("*** %s removed", file); | 116 | Error("*** %s removed", file); | |
117 | } | 117 | } | |
118 | } | 118 | } | |
119 | } | 119 | } | |
120 | 120 | |||
121 | /* Interrupt the creation of the current target and remove it if it ain't | 121 | /* Interrupt the creation of the current target and remove it if it ain't | |
122 | * precious. Then exit. | 122 | * precious. Then exit. | |
123 | * | 123 | * | |
124 | * If .INTERRUPT exists, its commands are run first WITH INTERRUPTS IGNORED. | 124 | * If .INTERRUPT exists, its commands are run first WITH INTERRUPTS IGNORED. | |
125 | * | 125 | * | |
126 | * XXX: is .PRECIOUS supposed to inhibit .INTERRUPT? I doubt it, but I've | 126 | * XXX: is .PRECIOUS supposed to inhibit .INTERRUPT? I doubt it, but I've | |
127 | * left the logic alone for now. - dholland 20160826 | 127 | * left the logic alone for now. - dholland 20160826 | |
128 | */ | 128 | */ | |
129 | static void | 129 | static void | |
130 | CompatInterrupt(int signo) | 130 | CompatInterrupt(int signo) | |
131 | { | 131 | { | |
132 | GNode *gn; | 132 | GNode *gn; | |
133 | 133 | |||
134 | CompatDeleteTarget(curTarg); | 134 | CompatDeleteTarget(curTarg); | |
135 | 135 | |||
136 | if (curTarg != NULL && !Targ_Precious(curTarg)) { | 136 | if (curTarg != NULL && !Targ_Precious(curTarg)) { | |
137 | /* | 137 | /* | |
138 | * Run .INTERRUPT only if hit with interrupt signal | 138 | * Run .INTERRUPT only if hit with interrupt signal | |
139 | */ | 139 | */ | |
140 | if (signo == SIGINT) { | 140 | if (signo == SIGINT) { | |
141 | gn = Targ_FindNode(".INTERRUPT"); | 141 | gn = Targ_FindNode(".INTERRUPT"); | |
142 | if (gn != NULL) { | 142 | if (gn != NULL) { | |
143 | Compat_Make(gn, gn); | 143 | Compat_Make(gn, gn); | |
144 | } | 144 | } | |
145 | } | 145 | } | |
146 | } | 146 | } | |
147 | 147 | |||
148 | if (signo == SIGQUIT) | 148 | if (signo == SIGQUIT) | |
149 | _exit(signo); | 149 | _exit(signo); | |
150 | 150 | |||
151 | /* | 151 | /* | |
152 | * If there is a child running, pass the signal on. | 152 | * If there is a child running, pass the signal on. | |
153 | * We will exist after it has exited. | 153 | * We will exist after it has exited. | |
154 | */ | 154 | */ | |
155 | compatSigno = signo; | 155 | compatSigno = signo; | |
156 | if (compatChild > 0) { | 156 | if (compatChild > 0) { | |
157 | KILLPG(compatChild, signo); | 157 | KILLPG(compatChild, signo); | |
158 | } else { | 158 | } else { | |
159 | bmake_signal(signo, SIG_DFL); | 159 | bmake_signal(signo, SIG_DFL); | |
160 | kill(myPid, signo); | 160 | kill(myPid, signo); | |
161 | } | 161 | } | |
162 | } | 162 | } | |
163 | 163 | |||
164 | /* Execute the next command for a target. If the command returns an error, | 164 | /* Execute the next command for a target. If the command returns an error, | |
165 | * the node's made field is set to ERROR and creation stops. | 165 | * the node's made field is set to ERROR and creation stops. | |
166 | * | 166 | * | |
167 | * Input: | 167 | * Input: | |
168 | * cmdp Command to execute | 168 | * cmdp Command to execute | |
169 | * gnp Node from which the command came | 169 | * gnp Node from which the command came | |
170 | * | 170 | * | |
171 | * Results: | 171 | * Results: | |
172 | * 0 if the command succeeded, 1 if an error occurred. | 172 | * 0 if the command succeeded, 1 if an error occurred. | |
173 | */ | 173 | */ | |
174 | int | 174 | int | |
175 | Compat_RunCommand(const char *cmdp, GNode *gn) | 175 | Compat_RunCommand(const char *cmdp, GNode *gn) | |
176 | { | 176 | { | |
177 | char *cmdStart; /* Start of expanded command */ | 177 | char *cmdStart; /* Start of expanded command */ | |
178 | char *bp; | 178 | char *bp; | |
179 | Boolean silent; /* Don't print command */ | 179 | Boolean silent; /* Don't print command */ | |
180 | Boolean doIt; /* Execute even if -n */ | 180 | Boolean doIt; /* Execute even if -n */ | |
181 | volatile Boolean errCheck; /* Check errors */ | 181 | volatile Boolean errCheck; /* Check errors */ | |
182 | int reason; /* Reason for child's death */ | 182 | int reason; /* Reason for child's death */ | |
183 | int status; /* Description of child's death */ | 183 | int status; /* Description of child's death */ | |
184 | pid_t cpid; /* Child actually found */ | 184 | pid_t cpid; /* Child actually found */ | |
185 | pid_t retstat; /* Result of wait */ | 185 | pid_t retstat; /* Result of wait */ | |
186 | StringListNode *cmdNode; /* Node where current command is located */ | 186 | StringListNode *cmdNode; /* Node where current command is located */ | |
187 | const char **volatile av; /* Argument vector for thing to exec */ | 187 | const char **volatile av; /* Argument vector for thing to exec */ | |
188 | char **volatile mav; /* Copy of the argument vector for freeing */ | 188 | char **volatile mav; /* Copy of the argument vector for freeing */ | |
189 | Boolean useShell; /* TRUE if command should be executed | 189 | Boolean useShell; /* TRUE if command should be executed | |
190 | * using a shell */ | 190 | * using a shell */ | |
191 | const char *volatile cmd = cmdp; | 191 | const char *volatile cmd = cmdp; | |
192 | 192 | |||
193 | silent = (gn->type & OP_SILENT) != 0; | 193 | silent = (gn->type & OP_SILENT) != 0; | |
194 | errCheck = !(gn->type & OP_IGNORE); | 194 | errCheck = !(gn->type & OP_IGNORE); | |
195 | doIt = FALSE; | 195 | doIt = FALSE; | |
196 | 196 | |||
197 | /* Luckily the commands don't end up in a string pool, otherwise | 197 | /* Luckily the commands don't end up in a string pool, otherwise | |
198 | * this comparison could match too early, in a dependency using "..." | 198 | * this comparison could match too early, in a dependency using "..." | |
199 | * for delayed commands, run in parallel mode, using the same shell | 199 | * for delayed commands, run in parallel mode, using the same shell | |
200 | * command line more than once; see JobPrintCommand. | 200 | * command line more than once; see JobPrintCommand. | |
201 | * TODO: write a unit-test to protect against this potential bug. */ | 201 | * TODO: write a unit-test to protect against this potential bug. */ | |
202 | cmdNode = Lst_FindDatum(gn->commands, cmd); | 202 | cmdNode = Lst_FindDatum(gn->commands, cmd); | |
203 | (void)Var_Subst(cmd, gn, VARE_WANTRES, &cmdStart); | 203 | (void)Var_Subst(cmd, gn, VARE_WANTRES, &cmdStart); | |
204 | /* TODO: handle errors */ | 204 | /* TODO: handle errors */ | |
205 | 205 | |||
206 | if (*cmdStart == '\0') { | 206 | if (*cmdStart == '\0') { | |
207 | free(cmdStart); | 207 | free(cmdStart); | |
208 | return 0; | 208 | return 0; | |
209 | } | 209 | } | |
210 | cmd = cmdStart; | 210 | cmd = cmdStart; | |
211 | LstNode_Set(cmdNode, cmdStart); | 211 | LstNode_Set(cmdNode, cmdStart); | |
212 | 212 | |||
213 | if (gn->type & OP_SAVE_CMDS) { | 213 | if (gn->type & OP_SAVE_CMDS) { | |
214 | GNode *endNode = Targ_GetEndNode(); | 214 | GNode *endNode = Targ_GetEndNode(); | |
215 | if (gn != endNode) { | 215 | if (gn != endNode) { | |
216 | Lst_Append(endNode->commands, cmdStart); | 216 | Lst_Append(endNode->commands, cmdStart); | |
217 | return 0; | 217 | return 0; | |
218 | } | 218 | } | |
219 | } | 219 | } | |
220 | if (strcmp(cmdStart, "...") == 0) { | 220 | if (strcmp(cmdStart, "...") == 0) { | |
221 | gn->type |= OP_SAVE_CMDS; | 221 | gn->type |= OP_SAVE_CMDS; | |
222 | return 0; | 222 | return 0; | |
223 | } | 223 | } | |
224 | 224 | |||
225 | while (*cmd == '@' || *cmd == '-' || *cmd == '+') { | 225 | while (*cmd == '@' || *cmd == '-' || *cmd == '+') { | |
226 | switch (*cmd) { | 226 | switch (*cmd) { | |
227 | case '@': | 227 | case '@': | |
228 | silent = !DEBUG(LOUD); | 228 | silent = !DEBUG(LOUD); | |
229 | break; | 229 | break; | |
230 | case '-': | 230 | case '-': | |
231 | errCheck = FALSE; | 231 | errCheck = FALSE; | |
232 | break; | 232 | break; | |
233 | case '+': | 233 | case '+': | |
234 | doIt = TRUE; | 234 | doIt = TRUE; | |
235 | if (!shellName) /* we came here from jobs */ | 235 | if (!shellName) /* we came here from jobs */ | |
236 | Shell_Init(); | 236 | Shell_Init(); | |
237 | break; | 237 | break; | |
238 | } | 238 | } | |
239 | cmd++; | 239 | cmd++; | |
240 | } | 240 | } | |
241 | 241 | |||
242 | while (ch_isspace(*cmd)) | 242 | while (ch_isspace(*cmd)) | |
243 | cmd++; | 243 | cmd++; | |
244 | 244 | |||
245 | /* | 245 | /* | |
246 | * If we did not end up with a command, just skip it. | 246 | * If we did not end up with a command, just skip it. | |
247 | */ | 247 | */ | |
248 | if (!*cmd) | 248 | if (!*cmd) | |
249 | return 0; | 249 | return 0; | |
250 | 250 | |||
251 | #if !defined(MAKE_NATIVE) | 251 | #if !defined(MAKE_NATIVE) | |
252 | /* | 252 | /* | |
253 | * In a non-native build, the host environment might be weird enough | 253 | * In a non-native build, the host environment might be weird enough | |
254 | * that it's necessary to go through a shell to get the correct | 254 | * that it's necessary to go through a shell to get the correct | |
255 | * behaviour. Or perhaps the shell has been replaced with something | 255 | * behaviour. Or perhaps the shell has been replaced with something | |
256 | * that does extra logging, and that should not be bypassed. | 256 | * that does extra logging, and that should not be bypassed. | |
257 | */ | 257 | */ | |
258 | useShell = TRUE; | 258 | useShell = TRUE; | |
259 | #else | 259 | #else | |
260 | /* | 260 | /* | |
261 | * Search for meta characters in the command. If there are no meta | 261 | * Search for meta characters in the command. If there are no meta | |
262 | * characters, there's no need to execute a shell to execute the | 262 | * characters, there's no need to execute a shell to execute the | |
263 | * command. | 263 | * command. | |
264 | * | 264 | * | |
265 | * Additionally variable assignments and empty commands | 265 | * Additionally variable assignments and empty commands | |
266 | * go to the shell. Therefore treat '=' and ':' like shell | 266 | * go to the shell. Therefore treat '=' and ':' like shell | |
267 | * meta characters as documented in make(1). | 267 | * meta characters as documented in make(1). | |
268 | */ | 268 | */ | |
269 | 269 | |||
270 | useShell = needshell(cmd); | 270 | useShell = needshell(cmd); | |
271 | #endif | 271 | #endif | |
272 | 272 | |||
273 | /* | 273 | /* | |
274 | * Print the command before echoing if we're not supposed to be quiet for | 274 | * Print the command before echoing if we're not supposed to be quiet for | |
275 | * this one. We also print the command if -n given. | 275 | * this one. We also print the command if -n given. | |
276 | */ | 276 | */ | |
277 | if (!silent || NoExecute(gn)) { | 277 | if (!silent || !GNode_ShouldExecute(gn)) { | |
278 | printf("%s\n", cmd); | 278 | printf("%s\n", cmd); | |
279 | fflush(stdout); | 279 | fflush(stdout); | |
280 | } | 280 | } | |
281 | 281 | |||
282 | /* | 282 | /* | |
283 | * If we're not supposed to execute any commands, this is as far as | 283 | * If we're not supposed to execute any commands, this is as far as | |
284 | * we go... | 284 | * we go... | |
285 | */ | 285 | */ | |
286 | if (!doIt && NoExecute(gn)) { | 286 | if (!doIt && !GNode_ShouldExecute(gn)) { | |
287 | return 0; | 287 | return 0; | |
288 | } | 288 | } | |
289 | DEBUG1(JOB, "Execute: '%s'\n", cmd); | 289 | DEBUG1(JOB, "Execute: '%s'\n", cmd); | |
290 | 290 | |||
291 | if (useShell) { | 291 | if (useShell) { | |
292 | /* | 292 | /* | |
293 | * We need to pass the command off to the shell, typically | 293 | * We need to pass the command off to the shell, typically | |
294 | * because the command contains a "meta" character. | 294 | * because the command contains a "meta" character. | |
295 | */ | 295 | */ | |
296 | static const char *shargv[5]; | 296 | static const char *shargv[5]; | |
297 | int shargc; | 297 | int shargc; | |
298 | 298 | |||
299 | shargc = 0; | 299 | shargc = 0; | |
300 | shargv[shargc++] = shellPath; | 300 | shargv[shargc++] = shellPath; | |
301 | /* | 301 | /* | |
302 | * The following work for any of the builtin shell specs. | 302 | * The following work for any of the builtin shell specs. | |
303 | */ | 303 | */ | |
304 | if (errCheck && shellErrFlag) { | 304 | if (errCheck && shellErrFlag) { | |
305 | shargv[shargc++] = shellErrFlag; | 305 | shargv[shargc++] = shellErrFlag; | |
306 | } | 306 | } | |
307 | if (DEBUG(SHELL)) | 307 | if (DEBUG(SHELL)) | |
308 | shargv[shargc++] = "-xc"; | 308 | shargv[shargc++] = "-xc"; | |
309 | else | 309 | else | |
310 | shargv[shargc++] = "-c"; | 310 | shargv[shargc++] = "-c"; | |
311 | shargv[shargc++] = cmd; | 311 | shargv[shargc++] = cmd; | |
312 | shargv[shargc] = NULL; | 312 | shargv[shargc] = NULL; | |
313 | av = shargv; | 313 | av = shargv; | |
314 | bp = NULL; | 314 | bp = NULL; | |
315 | mav = NULL; | 315 | mav = NULL; | |
316 | } else { | 316 | } else { | |
317 | /* | 317 | /* | |
318 | * No meta-characters, so no need to exec a shell. Break the command | 318 | * No meta-characters, so no need to exec a shell. Break the command | |
319 | * into words to form an argument vector we can execute. | 319 | * into words to form an argument vector we can execute. | |
320 | */ | 320 | */ | |
321 | Words words = Str_Words(cmd, FALSE); | 321 | Words words = Str_Words(cmd, FALSE); | |
322 | mav = words.words; | 322 | mav = words.words; | |
323 | bp = words.freeIt; | 323 | bp = words.freeIt; | |
324 | av = (void *)mav; | 324 | av = (void *)mav; | |
325 | } | 325 | } | |
326 | 326 | |||
327 | #ifdef USE_META | 327 | #ifdef USE_META | |
328 | if (useMeta) { | 328 | if (useMeta) { | |
329 | meta_compat_start(); | 329 | meta_compat_start(); | |
330 | } | 330 | } | |
331 | #endif | 331 | #endif | |
332 | 332 | |||
333 | /* | 333 | /* | |
334 | * Fork and execute the single command. If the fork fails, we abort. | 334 | * Fork and execute the single command. If the fork fails, we abort. | |
335 | */ | 335 | */ | |
336 | compatChild = cpid = vFork(); | 336 | compatChild = cpid = vFork(); | |
337 | if (cpid < 0) { | 337 | if (cpid < 0) { | |
338 | Fatal("Could not fork"); | 338 | Fatal("Could not fork"); | |
339 | } | 339 | } | |
340 | if (cpid == 0) { | 340 | if (cpid == 0) { | |
341 | Var_ExportVars(); | 341 | Var_ExportVars(); | |
342 | #ifdef USE_META | 342 | #ifdef USE_META | |
343 | if (useMeta) { | 343 | if (useMeta) { | |
344 | meta_compat_child(); | 344 | meta_compat_child(); | |
345 | } | 345 | } | |
346 | #endif | 346 | #endif | |
347 | (void)execvp(av[0], (char *const *)UNCONST(av)); | 347 | (void)execvp(av[0], (char *const *)UNCONST(av)); | |
348 | execDie("exec", av[0]); | 348 | execDie("exec", av[0]); | |
349 | } | 349 | } | |
350 | 350 | |||
351 | free(mav); | 351 | free(mav); | |
352 | free(bp); | 352 | free(bp); | |
353 | 353 | |||
354 | /* XXX: Memory management looks suspicious here. */ | 354 | /* XXX: Memory management looks suspicious here. */ | |
355 | /* XXX: Setting a list item to NULL is unexpected. */ | 355 | /* XXX: Setting a list item to NULL is unexpected. */ | |
356 | LstNode_SetNull(cmdNode); | 356 | LstNode_SetNull(cmdNode); | |
357 | 357 | |||
358 | #ifdef USE_META | 358 | #ifdef USE_META | |
359 | if (useMeta) { | 359 | if (useMeta) { | |
360 | meta_compat_parent(cpid); | 360 | meta_compat_parent(cpid); | |
361 | } | 361 | } | |
362 | #endif | 362 | #endif | |
363 | 363 | |||
364 | /* | 364 | /* | |
365 | * The child is off and running. Now all we can do is wait... | 365 | * The child is off and running. Now all we can do is wait... | |
366 | */ | 366 | */ | |
367 | while ((retstat = wait(&reason)) != cpid) { | 367 | while ((retstat = wait(&reason)) != cpid) { | |
368 | if (retstat > 0) | 368 | if (retstat > 0) | |
369 | JobReapChild(retstat, reason, FALSE); /* not ours? */ | 369 | JobReapChild(retstat, reason, FALSE); /* not ours? */ | |
370 | if (retstat == -1 && errno != EINTR) { | 370 | if (retstat == -1 && errno != EINTR) { | |
371 | break; | 371 | break; | |
372 | } | 372 | } | |
373 | } | 373 | } | |
374 | 374 | |||
375 | if (retstat < 0) | 375 | if (retstat < 0) | |
376 | Fatal("error in wait: %d: %s", retstat, strerror(errno)); | 376 | Fatal("error in wait: %d: %s", retstat, strerror(errno)); | |
377 | 377 | |||
378 | if (WIFSTOPPED(reason)) { | 378 | if (WIFSTOPPED(reason)) { | |
379 | status = WSTOPSIG(reason); /* stopped */ | 379 | status = WSTOPSIG(reason); /* stopped */ | |
380 | } else if (WIFEXITED(reason)) { | 380 | } else if (WIFEXITED(reason)) { | |
381 | status = WEXITSTATUS(reason); /* exited */ | 381 | status = WEXITSTATUS(reason); /* exited */ | |
382 | #if defined(USE_META) && defined(USE_FILEMON_ONCE) | 382 | #if defined(USE_META) && defined(USE_FILEMON_ONCE) | |
383 | if (useMeta) { | 383 | if (useMeta) { | |
384 | meta_cmd_finish(NULL); | 384 | meta_cmd_finish(NULL); | |
385 | } | 385 | } | |
386 | #endif | 386 | #endif | |
387 | if (status != 0) { | 387 | if (status != 0) { | |
388 | if (DEBUG(ERROR)) { | 388 | if (DEBUG(ERROR)) { | |
389 | const char *cp; | 389 | const char *cp; | |
390 | debug_printf("\n*** Failed target: %s\n*** Failed command: ", | 390 | debug_printf("\n*** Failed target: %s\n*** Failed command: ", | |
391 | gn->name); | 391 | gn->name); | |
392 | for (cp = cmd; *cp; ) { | 392 | for (cp = cmd; *cp; ) { | |
393 | if (ch_isspace(*cp)) { | 393 | if (ch_isspace(*cp)) { | |
394 | debug_printf(" "); | 394 | debug_printf(" "); | |
395 | while (ch_isspace(*cp)) | 395 | while (ch_isspace(*cp)) | |
396 | cp++; | 396 | cp++; | |
397 | } else { | 397 | } else { | |
398 | debug_printf("%c", *cp); | 398 | debug_printf("%c", *cp); | |
399 | cp++; | 399 | cp++; | |
400 | } | 400 | } | |
401 | } | 401 | } | |
402 | debug_printf("\n"); | 402 | debug_printf("\n"); | |
403 | } | 403 | } | |
404 | printf("*** Error code %d", status); | 404 | printf("*** Error code %d", status); | |
405 | } | 405 | } | |
406 | } else { | 406 | } else { | |
407 | status = WTERMSIG(reason); /* signaled */ | 407 | status = WTERMSIG(reason); /* signaled */ | |
408 | printf("*** Signal %d", status); | 408 | printf("*** Signal %d", status); | |
409 | } | 409 | } | |
410 | 410 | |||
411 | 411 | |||
412 | if (!WIFEXITED(reason) || status != 0) { | 412 | if (!WIFEXITED(reason) || status != 0) { | |
413 | if (errCheck) { | 413 | if (errCheck) { | |
414 | #ifdef USE_META | 414 | #ifdef USE_META | |
415 | if (useMeta) { | 415 | if (useMeta) { | |
416 | meta_job_error(NULL, gn, 0, status); | 416 | meta_job_error(NULL, gn, 0, status); | |
417 | } | 417 | } | |
418 | #endif | 418 | #endif | |
419 | gn->made = ERROR; | 419 | gn->made = ERROR; | |
420 | if (opts.keepgoing) { | 420 | if (opts.keepgoing) { | |
421 | /* Abort the current target, but let others continue. */ | 421 | /* Abort the current target, but let others continue. */ | |
422 | printf(" (continuing)\n"); | 422 | printf(" (continuing)\n"); | |
423 | } else { | 423 | } else { | |
424 | printf("\n"); | 424 | printf("\n"); | |
425 | } | 425 | } | |
426 | if (deleteOnError) | 426 | if (deleteOnError) | |
427 | CompatDeleteTarget(gn); | 427 | CompatDeleteTarget(gn); | |
428 | } else { | 428 | } else { | |
429 | /* | 429 | /* | |
430 | * Continue executing commands for this target. | 430 | * Continue executing commands for this target. | |
431 | * If we return 0, this will happen... | 431 | * If we return 0, this will happen... | |
432 | */ | 432 | */ | |
433 | printf(" (ignored)\n"); | 433 | printf(" (ignored)\n"); | |
434 | status = 0; | 434 | status = 0; | |
435 | } | 435 | } | |
436 | } | 436 | } | |
437 | 437 | |||
438 | free(cmdStart); | 438 | free(cmdStart); | |
439 | compatChild = 0; | 439 | compatChild = 0; | |
440 | if (compatSigno) { | 440 | if (compatSigno) { | |
441 | bmake_signal(compatSigno, SIG_DFL); | 441 | bmake_signal(compatSigno, SIG_DFL); | |
442 | kill(myPid, compatSigno); | 442 | kill(myPid, compatSigno); | |
443 | } | 443 | } | |
444 | 444 | |||
445 | return status; | 445 | return status; | |
446 | } | 446 | } | |
447 | 447 | |||
448 | static void | 448 | static void | |
449 | RunCommands(GNode *gn) | 449 | RunCommands(GNode *gn) | |
450 | { | 450 | { | |
451 | StringListNode *ln; | 451 | StringListNode *ln; | |
452 | for (ln = gn->commands->first; ln != NULL; ln = ln->next) { | 452 | for (ln = gn->commands->first; ln != NULL; ln = ln->next) { | |
453 | const char *cmd = ln->datum; | 453 | const char *cmd = ln->datum; | |
454 | if (Compat_RunCommand(cmd, gn) != 0) | 454 | if (Compat_RunCommand(cmd, gn) != 0) | |
455 | break; | 455 | break; | |
456 | } | 456 | } | |
457 | } | 457 | } | |
458 | 458 | |||
459 | static void | 459 | static void | |
460 | MakeNodes(GNodeList *gnodes, GNode *pgn) | 460 | MakeNodes(GNodeList *gnodes, GNode *pgn) | |
461 | { | 461 | { | |
462 | GNodeListNode *ln; | 462 | GNodeListNode *ln; | |
463 | for (ln = gnodes->first; ln != NULL; ln = ln->next) { | 463 | for (ln = gnodes->first; ln != NULL; ln = ln->next) { | |
464 | GNode *cohort = ln->datum; | 464 | GNode *cohort = ln->datum; | |
465 | Compat_Make(cohort, pgn); | 465 | Compat_Make(cohort, pgn); | |
466 | } | 466 | } | |
467 | } | 467 | } | |
468 | 468 | |||
469 | /* Make a target. | 469 | /* Make a target. | |
470 | * | 470 | * | |
471 | * If an error is detected and not being ignored, the process exits. | 471 | * If an error is detected and not being ignored, the process exits. | |
472 | * | 472 | * | |
473 | * Input: | 473 | * Input: | |
474 | * gn The node to make | 474 | * gn The node to make | |
475 | * pgn Parent to abort if necessary | 475 | * pgn Parent to abort if necessary | |
476 | */ | 476 | */ | |
477 | void | 477 | void | |
478 | Compat_Make(GNode *gn, GNode *pgn) | 478 | Compat_Make(GNode *gn, GNode *pgn) | |
479 | { | 479 | { | |
480 | if (!shellName) /* we came here from jobs */ | 480 | if (!shellName) /* we came here from jobs */ | |
481 | Shell_Init(); | 481 | Shell_Init(); | |
482 | if (gn->made == UNMADE && (gn == pgn || !(pgn->type & OP_MADE))) { | 482 | if (gn->made == UNMADE && (gn == pgn || !(pgn->type & OP_MADE))) { | |
483 | /* | 483 | /* | |
484 | * First mark ourselves to be made, then apply whatever transformations | 484 | * First mark ourselves to be made, then apply whatever transformations | |
485 | * the suffix module thinks are necessary. Once that's done, we can | 485 | * the suffix module thinks are necessary. Once that's done, we can | |
486 | * descend and make all our children. If any of them has an error | 486 | * descend and make all our children. If any of them has an error | |
487 | * but the -k flag was given, our 'make' field will be set FALSE again. | 487 | * but the -k flag was given, our 'make' field will be set FALSE again. | |
488 | * This is our signal to not attempt to do anything but abort our | 488 | * This is our signal to not attempt to do anything but abort our | |
489 | * parent as well. | 489 | * parent as well. | |
490 | */ | 490 | */ | |
491 | gn->flags |= REMAKE; | 491 | gn->flags |= REMAKE; | |
492 | gn->made = BEINGMADE; | 492 | gn->made = BEINGMADE; | |
493 | if (!(gn->type & OP_MADE)) | 493 | if (!(gn->type & OP_MADE)) | |
494 | Suff_FindDeps(gn); | 494 | Suff_FindDeps(gn); | |
495 | MakeNodes(gn->children, gn); | 495 | MakeNodes(gn->children, gn); | |
496 | if (!(gn->flags & REMAKE)) { | 496 | if (!(gn->flags & REMAKE)) { | |
497 | gn->made = ABORTED; | 497 | gn->made = ABORTED; | |
498 | pgn->flags &= ~(unsigned)REMAKE; | 498 | pgn->flags &= ~(unsigned)REMAKE; | |
499 | goto cohorts; | 499 | goto cohorts; | |
500 | } | 500 | } | |
501 | 501 | |||
502 | if (Lst_FindDatum(gn->implicitParents, pgn) != NULL) | 502 | if (Lst_FindDatum(gn->implicitParents, pgn) != NULL) | |
503 | Var_Set(IMPSRC, GNode_VarTarget(gn), pgn); | 503 | Var_Set(IMPSRC, GNode_VarTarget(gn), pgn); | |
504 | 504 | |||
505 | /* | 505 | /* | |
506 | * All the children were made ok. Now youngestChild->mtime contains the | 506 | * All the children were made ok. Now youngestChild->mtime contains the | |
507 | * modification time of the newest child, we need to find out if we | 507 | * modification time of the newest child, we need to find out if we | |
508 | * exist and when we were modified last. The criteria for datedness | 508 | * exist and when we were modified last. The criteria for datedness | |
509 | * are defined by the Make_OODate function. | 509 | * are defined by the Make_OODate function. | |
510 | */ | 510 | */ | |
511 | DEBUG1(MAKE, "Examining %s...", gn->name); | 511 | DEBUG1(MAKE, "Examining %s...", gn->name); | |
512 | if (!Make_OODate(gn)) { | 512 | if (!Make_OODate(gn)) { | |
513 | gn->made = UPTODATE; | 513 | gn->made = UPTODATE; | |
514 | DEBUG0(MAKE, "up-to-date.\n"); | 514 | DEBUG0(MAKE, "up-to-date.\n"); | |
515 | goto cohorts; | 515 | goto cohorts; | |
516 | } else | 516 | } else | |
517 | DEBUG0(MAKE, "out-of-date.\n"); | 517 | DEBUG0(MAKE, "out-of-date.\n"); | |
518 | 518 | |||
519 | /* | 519 | /* | |
520 | * If the user is just seeing if something is out-of-date, exit now | 520 | * If the user is just seeing if something is out-of-date, exit now | |
521 | * to tell him/her "yes". | 521 | * to tell him/her "yes". | |
522 | */ | 522 | */ | |
523 | if (opts.queryFlag) { | 523 | if (opts.queryFlag) { | |
524 | exit(1); | 524 | exit(1); | |
525 | } | 525 | } | |
526 | 526 | |||
527 | /* | 527 | /* | |
528 | * We need to be re-made. We also have to make sure we've got a $? | 528 | * We need to be re-made. We also have to make sure we've got a $? | |
529 | * variable. To be nice, we also define the $> variable using | 529 | * variable. To be nice, we also define the $> variable using | |
530 | * Make_DoAllVar(). | 530 | * Make_DoAllVar(). | |
531 | */ | 531 | */ | |
532 | Make_DoAllVar(gn); | 532 | Make_DoAllVar(gn); | |
533 | 533 | |||
534 | /* | 534 | /* | |
535 | * Alter our type to tell if errors should be ignored or things | 535 | * Alter our type to tell if errors should be ignored or things | |
536 | * should not be printed so CompatRunCommand knows what to do. | 536 | * should not be printed so CompatRunCommand knows what to do. | |
537 | */ | 537 | */ | |
538 | if (Targ_Ignore(gn)) | 538 | if (Targ_Ignore(gn)) | |
539 | gn->type |= OP_IGNORE; | 539 | gn->type |= OP_IGNORE; | |
540 | if (Targ_Silent(gn)) | 540 | if (Targ_Silent(gn)) | |
541 | gn->type |= OP_SILENT; | 541 | gn->type |= OP_SILENT; | |
542 | 542 | |||
543 | if (Job_CheckCommands(gn, Fatal)) { | 543 | if (Job_CheckCommands(gn, Fatal)) { | |
544 | /* | 544 | /* | |
545 | * Our commands are ok, but we still have to worry about the -t | 545 | * Our commands are ok, but we still have to worry about the -t | |
546 | * flag... | 546 | * flag... | |
547 | */ | 547 | */ | |
548 | if (!opts.touchFlag || (gn->type & OP_MAKE)) { | 548 | if (!opts.touchFlag || (gn->type & OP_MAKE)) { | |
549 | curTarg = gn; | 549 | curTarg = gn; | |
550 | #ifdef USE_META | 550 | #ifdef USE_META | |
551 | if (useMeta && !NoExecute(gn)) { | 551 | if (useMeta && GNode_ShouldExecute(gn)) { | |
552 | meta_job_start(NULL, gn); | 552 | meta_job_start(NULL, gn); | |
553 | } | 553 | } | |
554 | #endif | 554 | #endif | |
555 | RunCommands(gn); | 555 | RunCommands(gn); | |
556 | curTarg = NULL; | 556 | curTarg = NULL; | |
557 | } else { | 557 | } else { | |
558 | Job_Touch(gn, (gn->type & OP_SILENT) != 0); | 558 | Job_Touch(gn, (gn->type & OP_SILENT) != 0); | |
559 | } | 559 | } | |
560 | } else { | 560 | } else { | |
561 | gn->made = ERROR; | 561 | gn->made = ERROR; | |
562 | } | 562 | } | |
563 | #ifdef USE_META | 563 | #ifdef USE_META | |
564 | if (useMeta && !NoExecute(gn)) { | 564 | if (useMeta && GNode_ShouldExecute(gn)) { | |
565 | if (meta_job_finish(NULL) != 0) | 565 | if (meta_job_finish(NULL) != 0) | |
566 | gn->made = ERROR; | 566 | gn->made = ERROR; | |
567 | } | 567 | } | |
568 | #endif | 568 | #endif | |
569 | 569 | |||
570 | if (gn->made != ERROR) { | 570 | if (gn->made != ERROR) { | |
571 | /* | 571 | /* | |
572 | * If the node was made successfully, mark it so, update | 572 | * If the node was made successfully, mark it so, update | |
573 | * its modification time and timestamp all its parents. Note | 573 | * its modification time and timestamp all its parents. Note | |
574 | * that for .ZEROTIME targets, the timestamping isn't done. | 574 | * that for .ZEROTIME targets, the timestamping isn't done. | |
575 | * This is to keep its state from affecting that of its parent. | 575 | * This is to keep its state from affecting that of its parent. | |
576 | */ | 576 | */ | |
577 | gn->made = MADE; | 577 | gn->made = MADE; | |
578 | pgn->flags |= Make_Recheck(gn) == 0 ? FORCE : 0; | 578 | pgn->flags |= Make_Recheck(gn) == 0 ? FORCE : 0; | |
579 | if (!(gn->type & OP_EXEC)) { | 579 | if (!(gn->type & OP_EXEC)) { | |
580 | pgn->flags |= CHILDMADE; | 580 | pgn->flags |= CHILDMADE; | |
581 | Make_TimeStamp(pgn, gn); | 581 | Make_TimeStamp(pgn, gn); | |
582 | } | 582 | } | |
583 | } else if (opts.keepgoing) { | 583 | } else if (opts.keepgoing) { | |
584 | pgn->flags &= ~(unsigned)REMAKE; | 584 | pgn->flags &= ~(unsigned)REMAKE; | |
585 | } else { | 585 | } else { | |
586 | PrintOnError(gn, "\nStop."); | 586 | PrintOnError(gn, "\nStop."); | |
587 | exit(1); | 587 | exit(1); | |
588 | } | 588 | } | |
589 | } else if (gn->made == ERROR) { | 589 | } else if (gn->made == ERROR) { | |
590 | /* Already had an error when making this. Tell the parent to abort. */ | 590 | /* Already had an error when making this. Tell the parent to abort. */ | |
591 | pgn->flags &= ~(unsigned)REMAKE; | 591 | pgn->flags &= ~(unsigned)REMAKE; | |
592 | } else { | 592 | } else { | |
593 | if (Lst_FindDatum(gn->implicitParents, pgn) != NULL) { | 593 | if (Lst_FindDatum(gn->implicitParents, pgn) != NULL) { | |
594 | const char *target = GNode_VarTarget(gn); | 594 | const char *target = GNode_VarTarget(gn); | |
595 | Var_Set(IMPSRC, target != NULL ? target : "", pgn); | 595 | Var_Set(IMPSRC, target != NULL ? target : "", pgn); | |
596 | } | 596 | } | |
597 | switch(gn->made) { | 597 | switch(gn->made) { | |
598 | case BEINGMADE: | 598 | case BEINGMADE: | |
599 | Error("Graph cycles through %s", gn->name); | 599 | Error("Graph cycles through %s", gn->name); | |
600 | gn->made = ERROR; | 600 | gn->made = ERROR; | |
601 | pgn->flags &= ~(unsigned)REMAKE; | 601 | pgn->flags &= ~(unsigned)REMAKE; | |
602 | break; | 602 | break; | |
603 | case MADE: | 603 | case MADE: | |
604 | if ((gn->type & OP_EXEC) == 0) { | 604 | if ((gn->type & OP_EXEC) == 0) { | |
605 | pgn->flags |= CHILDMADE; | 605 | pgn->flags |= CHILDMADE; | |
606 | Make_TimeStamp(pgn, gn); | 606 | Make_TimeStamp(pgn, gn); | |
607 | } | 607 | } | |
608 | break; | 608 | break; | |
609 | case UPTODATE: | 609 | case UPTODATE: | |
610 | if ((gn->type & OP_EXEC) == 0) { | 610 | if ((gn->type & OP_EXEC) == 0) { | |
611 | Make_TimeStamp(pgn, gn); | 611 | Make_TimeStamp(pgn, gn); | |
612 | } | 612 | } | |
613 | break; | 613 | break; | |
614 | default: | 614 | default: | |
615 | break; | 615 | break; | |
616 | } | 616 | } | |
617 | } | 617 | } | |
618 | 618 | |||
619 | cohorts: | 619 | cohorts: | |
620 | MakeNodes(gn->cohorts, pgn); | 620 | MakeNodes(gn->cohorts, pgn); | |
621 | } | 621 | } | |
622 | 622 | |||
623 | /* Initialize this module and start making. | 623 | /* Initialize this module and start making. | |
624 | * | 624 | * | |
625 | * Input: | 625 | * Input: | |
626 | * targs The target nodes to re-create | 626 | * targs The target nodes to re-create | |
627 | */ | 627 | */ | |
628 | void | 628 | void | |
629 | Compat_Run(GNodeList *targs) | 629 | Compat_Run(GNodeList *targs) | |
630 | { | 630 | { | |
631 | GNode *gn = NULL; /* Current root target */ | 631 | GNode *gn = NULL; /* Current root target */ | |
632 | int errors; /* Number of targets not remade due to errors */ | 632 | int errors; /* Number of targets not remade due to errors */ | |
633 | 633 | |||
634 | if (!shellName) | 634 | if (!shellName) | |
635 | Shell_Init(); | 635 | Shell_Init(); | |
636 | 636 | |||
637 | if (bmake_signal(SIGINT, SIG_IGN) != SIG_IGN) | 637 | if (bmake_signal(SIGINT, SIG_IGN) != SIG_IGN) | |
638 | bmake_signal(SIGINT, CompatInterrupt); | 638 | bmake_signal(SIGINT, CompatInterrupt); | |
639 | if (bmake_signal(SIGTERM, SIG_IGN) != SIG_IGN) | 639 | if (bmake_signal(SIGTERM, SIG_IGN) != SIG_IGN) | |
640 | bmake_signal(SIGTERM, CompatInterrupt); | 640 | bmake_signal(SIGTERM, CompatInterrupt); | |
641 | if (bmake_signal(SIGHUP, SIG_IGN) != SIG_IGN) | 641 | if (bmake_signal(SIGHUP, SIG_IGN) != SIG_IGN) | |
642 | bmake_signal(SIGHUP, CompatInterrupt); | 642 | bmake_signal(SIGHUP, CompatInterrupt); | |
643 | if (bmake_signal(SIGQUIT, SIG_IGN) != SIG_IGN) | 643 | if (bmake_signal(SIGQUIT, SIG_IGN) != SIG_IGN) | |
644 | bmake_signal(SIGQUIT, CompatInterrupt); | 644 | bmake_signal(SIGQUIT, CompatInterrupt); | |
645 | 645 | |||
646 | /* Create the .END node now, to keep the (debug) output of the | 646 | /* Create the .END node now, to keep the (debug) output of the | |
647 | * counter.mk test the same as before 2020-09-23. This implementation | 647 | * counter.mk test the same as before 2020-09-23. This implementation | |
648 | * detail probably doesn't matter though. */ | 648 | * detail probably doesn't matter though. */ | |
649 | (void)Targ_GetEndNode(); | 649 | (void)Targ_GetEndNode(); | |
650 | /* | 650 | /* | |
651 | * If the user has defined a .BEGIN target, execute the commands attached | 651 | * If the user has defined a .BEGIN target, execute the commands attached | |
652 | * to it. | 652 | * to it. | |
653 | */ | 653 | */ | |
654 | if (!opts.queryFlag) { | 654 | if (!opts.queryFlag) { | |
655 | gn = Targ_FindNode(".BEGIN"); | 655 | gn = Targ_FindNode(".BEGIN"); | |
656 | if (gn != NULL) { | 656 | if (gn != NULL) { | |
657 | Compat_Make(gn, gn); | 657 | Compat_Make(gn, gn); | |
658 | if (gn->made == ERROR) { | 658 | if (gn->made == ERROR) { | |
659 | PrintOnError(gn, "\nStop."); | 659 | PrintOnError(gn, "\nStop."); | |
660 | exit(1); | 660 | exit(1); | |
661 | } | 661 | } | |
662 | } | 662 | } | |
663 | } | 663 | } | |
664 | 664 | |||
665 | /* | 665 | /* | |
666 | * Expand .USE nodes right now, because they can modify the structure | 666 | * Expand .USE nodes right now, because they can modify the structure | |
667 | * of the tree. | 667 | * of the tree. | |
668 | */ | 668 | */ | |
669 | Make_ExpandUse(targs); | 669 | Make_ExpandUse(targs); | |
670 | 670 | |||
671 | /* | 671 | /* | |
672 | * For each entry in the list of targets to create, call Compat_Make on | 672 | * For each entry in the list of targets to create, call Compat_Make on | |
673 | * it to create the thing. Compat_Make will leave the 'made' field of gn | 673 | * it to create the thing. Compat_Make will leave the 'made' field of gn | |
674 | * in one of several states: | 674 | * in one of several states: | |
675 | * UPTODATE gn was already up-to-date | 675 | * UPTODATE gn was already up-to-date | |
676 | * MADE gn was recreated successfully | 676 | * MADE gn was recreated successfully | |
677 | * ERROR An error occurred while gn was being created | 677 | * ERROR An error occurred while gn was being created | |
678 | * ABORTED gn was not remade because one of its inferiors | 678 | * ABORTED gn was not remade because one of its inferiors | |
679 | * could not be made due to errors. | 679 | * could not be made due to errors. | |
680 | */ | 680 | */ | |
681 | errors = 0; | 681 | errors = 0; | |
682 | while (!Lst_IsEmpty(targs)) { | 682 | while (!Lst_IsEmpty(targs)) { | |
683 | gn = Lst_Dequeue(targs); | 683 | gn = Lst_Dequeue(targs); | |
684 | Compat_Make(gn, gn); | 684 | Compat_Make(gn, gn); | |
685 | 685 | |||
686 | if (gn->made == UPTODATE) { | 686 | if (gn->made == UPTODATE) { | |
687 | printf("`%s' is up to date.\n", gn->name); | 687 | printf("`%s' is up to date.\n", gn->name); | |
688 | } else if (gn->made == ABORTED) { | 688 | } else if (gn->made == ABORTED) { | |
689 | printf("`%s' not remade because of errors.\n", gn->name); | 689 | printf("`%s' not remade because of errors.\n", gn->name); | |
690 | errors++; | 690 | errors++; | |
691 | } | 691 | } | |
692 | } | 692 | } | |
693 | 693 | |||
694 | /* | 694 | /* | |
695 | * If the user has defined a .END target, run its commands. | 695 | * If the user has defined a .END target, run its commands. | |
696 | */ | 696 | */ | |
697 | if (errors == 0) { | 697 | if (errors == 0) { | |
698 | GNode *endNode = Targ_GetEndNode(); | 698 | GNode *endNode = Targ_GetEndNode(); | |
699 | Compat_Make(endNode, endNode); | 699 | Compat_Make(endNode, endNode); | |
700 | /* XXX: Did you mean endNode->made instead of gn->made? */ | 700 | /* XXX: Did you mean endNode->made instead of gn->made? */ | |
701 | if (gn->made == ERROR) { | 701 | if (gn->made == ERROR) { | |
702 | PrintOnError(gn, "\nStop."); | 702 | PrintOnError(gn, "\nStop."); | |
703 | exit(1); | 703 | exit(1); | |
704 | } | 704 | } | |
705 | } | 705 | } | |
706 | } | 706 | } |
--- src/usr.bin/make/job.c 2020/11/01 17:07:03 1.299
+++ src/usr.bin/make/job.c 2020/11/01 17:47:26 1.300
@@ -1,2602 +1,2602 @@ | @@ -1,2602 +1,2602 @@ | |||
1 | /* $NetBSD: job.c,v 1.299 2020/11/01 17:07:03 rillig Exp $ */ | 1 | /* $NetBSD: job.c,v 1.300 2020/11/01 17:47:26 rillig Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. | 4 | * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to Berkeley by | 7 | * This code is derived from software contributed to Berkeley by | |
8 | * Adam de Boor. | 8 | * Adam de Boor. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | 15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | 16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | 17 | * documentation and/or other materials provided with the distribution. | |
18 | * 3. Neither the name of the University nor the names of its contributors | 18 | * 3. Neither the name of the University nor the names of its contributors | |
19 | * may be used to endorse or promote products derived from this software | 19 | * may be used to endorse or promote products derived from this software | |
20 | * without specific prior written permission. | 20 | * without specific prior written permission. | |
21 | * | 21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
32 | * SUCH DAMAGE. | 32 | * SUCH DAMAGE. | |
33 | */ | 33 | */ | |
34 | 34 | |||
35 | /* | 35 | /* | |
36 | * Copyright (c) 1988, 1989 by Adam de Boor | 36 | * Copyright (c) 1988, 1989 by Adam de Boor | |
37 | * Copyright (c) 1989 by Berkeley Softworks | 37 | * Copyright (c) 1989 by Berkeley Softworks | |
38 | * All rights reserved. | 38 | * All rights reserved. | |
39 | * | 39 | * | |
40 | * This code is derived from software contributed to Berkeley by | 40 | * This code is derived from software contributed to Berkeley by | |
41 | * Adam de Boor. | 41 | * Adam de Boor. | |
42 | * | 42 | * | |
43 | * Redistribution and use in source and binary forms, with or without | 43 | * Redistribution and use in source and binary forms, with or without | |
44 | * modification, are permitted provided that the following conditions | 44 | * modification, are permitted provided that the following conditions | |
45 | * are met: | 45 | * are met: | |
46 | * 1. Redistributions of source code must retain the above copyright | 46 | * 1. Redistributions of source code must retain the above copyright | |
47 | * notice, this list of conditions and the following disclaimer. | 47 | * notice, this list of conditions and the following disclaimer. | |
48 | * 2. Redistributions in binary form must reproduce the above copyright | 48 | * 2. Redistributions in binary form must reproduce the above copyright | |
49 | * notice, this list of conditions and the following disclaimer in the | 49 | * notice, this list of conditions and the following disclaimer in the | |
50 | * documentation and/or other materials provided with the distribution. | 50 | * documentation and/or other materials provided with the distribution. | |
51 | * 3. All advertising materials mentioning features or use of this software | 51 | * 3. All advertising materials mentioning features or use of this software | |
52 | * must display the following acknowledgement: | 52 | * must display the following acknowledgement: | |
53 | * This product includes software developed by the University of | 53 | * This product includes software developed by the University of | |
54 | * California, Berkeley and its contributors. | 54 | * California, Berkeley and its contributors. | |
55 | * 4. Neither the name of the University nor the names of its contributors | 55 | * 4. Neither the name of the University nor the names of its contributors | |
56 | * may be used to endorse or promote products derived from this software | 56 | * may be used to endorse or promote products derived from this software | |
57 | * without specific prior written permission. | 57 | * without specific prior written permission. | |
58 | * | 58 | * | |
59 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 59 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
60 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 60 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
61 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 61 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
62 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 62 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
63 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 63 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
64 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 64 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
65 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 65 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
66 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 66 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
67 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 67 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
68 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 68 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
69 | * SUCH DAMAGE. | 69 | * SUCH DAMAGE. | |
70 | */ | 70 | */ | |
71 | 71 | |||
72 | /*- | 72 | /*- | |
73 | * job.c -- | 73 | * job.c -- | |
74 | * handle the creation etc. of our child processes. | 74 | * handle the creation etc. of our child processes. | |
75 | * | 75 | * | |
76 | * Interface: | 76 | * Interface: | |
77 | * Job_Init Called to initialize this module. In addition, | 77 | * Job_Init Called to initialize this module. In addition, | |
78 | * any commands attached to the .BEGIN target | 78 | * any commands attached to the .BEGIN target | |
79 | * are executed before this function returns. | 79 | * are executed before this function returns. | |
80 | * Hence, the makefiles must have been parsed | 80 | * Hence, the makefiles must have been parsed | |
81 | * before this function is called. | 81 | * before this function is called. | |
82 | * | 82 | * | |
83 | * Job_End Clean up any memory used. | 83 | * Job_End Clean up any memory used. | |
84 | * | 84 | * | |
85 | * Job_Make Start the creation of the given target. | 85 | * Job_Make Start the creation of the given target. | |
86 | * | 86 | * | |
87 | * Job_CatchChildren | 87 | * Job_CatchChildren | |
88 | * Check for and handle the termination of any | 88 | * Check for and handle the termination of any | |
89 | * children. This must be called reasonably | 89 | * children. This must be called reasonably | |
90 | * frequently to keep the whole make going at | 90 | * frequently to keep the whole make going at | |
91 | * a decent clip, since job table entries aren't | 91 | * a decent clip, since job table entries aren't | |
92 | * removed until their process is caught this way. | 92 | * removed until their process is caught this way. | |
93 | * | 93 | * | |
94 | * Job_CatchOutput | 94 | * Job_CatchOutput | |
95 | * Print any output our children have produced. | 95 | * Print any output our children have produced. | |
96 | * Should also be called fairly frequently to | 96 | * Should also be called fairly frequently to | |
97 | * keep the user informed of what's going on. | 97 | * keep the user informed of what's going on. | |
98 | * If no output is waiting, it will block for | 98 | * If no output is waiting, it will block for | |
99 | * a time given by the SEL_* constants, below, | 99 | * a time given by the SEL_* constants, below, | |
100 | * or until output is ready. | 100 | * or until output is ready. | |
101 | * | 101 | * | |
102 | * Job_ParseShell Given the line following a .SHELL target, parse | 102 | * Job_ParseShell Given the line following a .SHELL target, parse | |
103 | * the line as a shell specification. Returns | 103 | * the line as a shell specification. Returns | |
104 | * FALSE if the spec was incorrect. | 104 | * FALSE if the spec was incorrect. | |
105 | * | 105 | * | |
106 | * Job_Finish Perform any final processing which needs doing. | 106 | * Job_Finish Perform any final processing which needs doing. | |
107 | * This includes the execution of any commands | 107 | * This includes the execution of any commands | |
108 | * which have been/were attached to the .END | 108 | * which have been/were attached to the .END | |
109 | * target. It should only be called when the | 109 | * target. It should only be called when the | |
110 | * job table is empty. | 110 | * job table is empty. | |
111 | * | 111 | * | |
112 | * Job_AbortAll Abort all currently running jobs. It doesn't | 112 | * Job_AbortAll Abort all currently running jobs. It doesn't | |
113 | * handle output or do anything for the jobs, | 113 | * handle output or do anything for the jobs, | |
114 | * just kills them. It should only be called in | 114 | * just kills them. It should only be called in | |
115 | * an emergency. | 115 | * an emergency. | |
116 | * | 116 | * | |
117 | * Job_CheckCommands | 117 | * Job_CheckCommands | |
118 | * Verify that the commands for a target are | 118 | * Verify that the commands for a target are | |
119 | * ok. Provide them if necessary and possible. | 119 | * ok. Provide them if necessary and possible. | |
120 | * | 120 | * | |
121 | * Job_Touch Update a target without really updating it. | 121 | * Job_Touch Update a target without really updating it. | |
122 | * | 122 | * | |
123 | * Job_Wait Wait for all currently-running jobs to finish. | 123 | * Job_Wait Wait for all currently-running jobs to finish. | |
124 | */ | 124 | */ | |
125 | 125 | |||
126 | #include <sys/types.h> | 126 | #include <sys/types.h> | |
127 | #include <sys/stat.h> | 127 | #include <sys/stat.h> | |
128 | #include <sys/file.h> | 128 | #include <sys/file.h> | |
129 | #include <sys/time.h> | 129 | #include <sys/time.h> | |
130 | #include <sys/wait.h> | 130 | #include <sys/wait.h> | |
131 | 131 | |||
132 | #include <errno.h> | 132 | #include <errno.h> | |
133 | #ifndef USE_SELECT | 133 | #ifndef USE_SELECT | |
134 | #include <poll.h> | 134 | #include <poll.h> | |
135 | #endif | 135 | #endif | |
136 | #include <signal.h> | 136 | #include <signal.h> | |
137 | #include <utime.h> | 137 | #include <utime.h> | |
138 | 138 | |||
139 | #include "make.h" | 139 | #include "make.h" | |
140 | #include "dir.h" | 140 | #include "dir.h" | |
141 | #include "job.h" | 141 | #include "job.h" | |
142 | #include "pathnames.h" | 142 | #include "pathnames.h" | |
143 | #include "trace.h" | 143 | #include "trace.h" | |
144 | 144 | |||
145 | /* "@(#)job.c 8.2 (Berkeley) 3/19/94" */ | 145 | /* "@(#)job.c 8.2 (Berkeley) 3/19/94" */ | |
146 | MAKE_RCSID("$NetBSD: job.c,v 1.299 2020/11/01 17:07:03 rillig Exp $"); | 146 | MAKE_RCSID("$NetBSD: job.c,v 1.300 2020/11/01 17:47:26 rillig Exp $"); | |
147 | 147 | |||
148 | /* A shell defines how the commands are run. All commands for a target are | 148 | /* A shell defines how the commands are run. All commands for a target are | |
149 | * written into a single file, which is then given to the shell to execute | 149 | * written into a single file, which is then given to the shell to execute | |
150 | * the commands from it. The commands are written to the file using a few | 150 | * the commands from it. The commands are written to the file using a few | |
151 | * templates for echo control and error control. | 151 | * templates for echo control and error control. | |
152 | * | 152 | * | |
153 | * The name of the shell is the basename for the predefined shells, such as | 153 | * The name of the shell is the basename for the predefined shells, such as | |
154 | * "sh", "csh", "bash". For custom shells, it is the full pathname, and its | 154 | * "sh", "csh", "bash". For custom shells, it is the full pathname, and its | |
155 | * basename is used to select the type of shell; the longest match wins. | 155 | * basename is used to select the type of shell; the longest match wins. | |
156 | * So /usr/pkg/bin/bash has type sh, /usr/local/bin/tcsh has type csh. | 156 | * So /usr/pkg/bin/bash has type sh, /usr/local/bin/tcsh has type csh. | |
157 | * | 157 | * | |
158 | * The echoing of command lines is controlled using hasEchoCtl, echoOff, | 158 | * The echoing of command lines is controlled using hasEchoCtl, echoOff, | |
159 | * echoOn, noPrint and noPrintLen. When echoOff is executed by the shell, it | 159 | * echoOn, noPrint and noPrintLen. When echoOff is executed by the shell, it | |
160 | * still outputs something, but this something is not interesting, therefore | 160 | * still outputs something, but this something is not interesting, therefore | |
161 | * it is filtered out using noPrint and noPrintLen. | 161 | * it is filtered out using noPrint and noPrintLen. | |
162 | * | 162 | * | |
163 | * The error checking for individual commands is controlled using hasErrCtl, | 163 | * The error checking for individual commands is controlled using hasErrCtl, | |
164 | * errOnOrEcho, errOffOrExecIgnore and errExit. | 164 | * errOnOrEcho, errOffOrExecIgnore and errExit. | |
165 | * | 165 | * | |
166 | * If a shell doesn't have error control, errOnOrEcho becomes a printf template | 166 | * If a shell doesn't have error control, errOnOrEcho becomes a printf template | |
167 | * for echoing the command, should echoing be on; errOffOrExecIgnore becomes | 167 | * for echoing the command, should echoing be on; errOffOrExecIgnore becomes | |
168 | * another printf template for executing the command while ignoring the return | 168 | * another printf template for executing the command while ignoring the return | |
169 | * status. Finally errExit is a printf template for running the command and | 169 | * status. Finally errExit is a printf template for running the command and | |
170 | * causing the shell to exit on error. If any of these strings are empty when | 170 | * causing the shell to exit on error. If any of these strings are empty when | |
171 | * hasErrCtl is FALSE, the command will be executed anyway as is, and if it | 171 | * hasErrCtl is FALSE, the command will be executed anyway as is, and if it | |
172 | * causes an error, so be it. Any templates setup to echo the command will | 172 | * causes an error, so be it. Any templates setup to echo the command will | |
173 | * escape any '$ ` \ "' characters in the command string to avoid common | 173 | * escape any '$ ` \ "' characters in the command string to avoid common | |
174 | * problems with echo "%s\n" as a template. | 174 | * problems with echo "%s\n" as a template. | |
175 | * | 175 | * | |
176 | * The command-line flags "echo" and "exit" also control the behavior. The | 176 | * The command-line flags "echo" and "exit" also control the behavior. The | |
177 | * "echo" flag causes the shell to start echoing commands right away. The | 177 | * "echo" flag causes the shell to start echoing commands right away. The | |
178 | * "exit" flag causes the shell to exit when an error is detected in one of | 178 | * "exit" flag causes the shell to exit when an error is detected in one of | |
179 | * the commands. | 179 | * the commands. | |
180 | */ | 180 | */ | |
181 | typedef struct Shell { | 181 | typedef struct Shell { | |
182 | 182 | |||
183 | /* The name of the shell. For Bourne and C shells, this is used only to | 183 | /* The name of the shell. For Bourne and C shells, this is used only to | |
184 | * find the shell description when used as the single source of a .SHELL | 184 | * find the shell description when used as the single source of a .SHELL | |
185 | * target. For user-defined shells, this is the full path of the shell. */ | 185 | * target. For user-defined shells, this is the full path of the shell. */ | |
186 | const char *name; | 186 | const char *name; | |
187 | 187 | |||
188 | Boolean hasEchoCtl; /* True if both echoOff and echoOn defined */ | 188 | Boolean hasEchoCtl; /* True if both echoOff and echoOn defined */ | |
189 | const char *echoOff; /* command to turn off echo */ | 189 | const char *echoOff; /* command to turn off echo */ | |
190 | const char *echoOn; /* command to turn it back on again */ | 190 | const char *echoOn; /* command to turn it back on again */ | |
191 | const char *noPrint; /* text to skip when printing output from | 191 | const char *noPrint; /* text to skip when printing output from | |
192 | * shell. This is usually the same as echoOff */ | 192 | * shell. This is usually the same as echoOff */ | |
193 | size_t noPrintLen; /* length of noPrint command */ | 193 | size_t noPrintLen; /* length of noPrint command */ | |
194 | 194 | |||
195 | Boolean hasErrCtl; /* set if can control error checking for | 195 | Boolean hasErrCtl; /* set if can control error checking for | |
196 | * individual commands */ | 196 | * individual commands */ | |
197 | /* XXX: split into errOn and echoCmd */ | 197 | /* XXX: split into errOn and echoCmd */ | |
198 | const char *errOnOrEcho; /* template to turn on error checking */ | 198 | const char *errOnOrEcho; /* template to turn on error checking */ | |
199 | /* XXX: split into errOff and execIgnore */ | 199 | /* XXX: split into errOff and execIgnore */ | |
200 | const char *errOffOrExecIgnore; /* template to turn off error checking */ | 200 | const char *errOffOrExecIgnore; /* template to turn off error checking */ | |
201 | const char *errExit; /* template to use for testing exit code */ | 201 | const char *errExit; /* template to use for testing exit code */ | |
202 | 202 | |||
203 | /* string literal that results in a newline character when it appears | 203 | /* string literal that results in a newline character when it appears | |
204 | * outside of any 'quote' or "quote" characters */ | 204 | * outside of any 'quote' or "quote" characters */ | |
205 | const char *newline; | 205 | const char *newline; | |
206 | char commentChar; /* character used by shell for comment lines */ | 206 | char commentChar; /* character used by shell for comment lines */ | |
207 | 207 | |||
208 | /* | 208 | /* | |
209 | * command-line flags | 209 | * command-line flags | |
210 | */ | 210 | */ | |
211 | const char *echo; /* echo commands */ | 211 | const char *echo; /* echo commands */ | |
212 | const char *exit; /* exit on error */ | 212 | const char *exit; /* exit on error */ | |
213 | } Shell; | 213 | } Shell; | |
214 | 214 | |||
215 | /* | 215 | /* | |
216 | * error handling variables | 216 | * error handling variables | |
217 | */ | 217 | */ | |
218 | static int errors = 0; /* number of errors reported */ | 218 | static int errors = 0; /* number of errors reported */ | |
219 | typedef enum AbortReason { /* why is the make aborting? */ | 219 | typedef enum AbortReason { /* why is the make aborting? */ | |
220 | ABORT_NONE, | 220 | ABORT_NONE, | |
221 | ABORT_ERROR, /* Because of an error */ | 221 | ABORT_ERROR, /* Because of an error */ | |
222 | ABORT_INTERRUPT, /* Because it was interrupted */ | 222 | ABORT_INTERRUPT, /* Because it was interrupted */ | |
223 | ABORT_WAIT /* Waiting for jobs to finish */ | 223 | ABORT_WAIT /* Waiting for jobs to finish */ | |
224 | } AbortReason; | 224 | } AbortReason; | |
225 | static AbortReason aborting = ABORT_NONE; | 225 | static AbortReason aborting = ABORT_NONE; | |
226 | #define JOB_TOKENS "+EI+" /* Token to requeue for each abort state */ | 226 | #define JOB_TOKENS "+EI+" /* Token to requeue for each abort state */ | |
227 | 227 | |||
228 | /* | 228 | /* | |
229 | * this tracks the number of tokens currently "out" to build jobs. | 229 | * this tracks the number of tokens currently "out" to build jobs. | |
230 | */ | 230 | */ | |
231 | int jobTokensRunning = 0; | 231 | int jobTokensRunning = 0; | |
232 | 232 | |||
233 | /* The number of commands actually printed to the shell commands file for | 233 | /* The number of commands actually printed to the shell commands file for | |
234 | * the current job. Should this number be 0, no shell will be executed. */ | 234 | * the current job. Should this number be 0, no shell will be executed. */ | |
235 | static int numCommands; | 235 | static int numCommands; | |
236 | 236 | |||
237 | typedef enum JobStartResult { | 237 | typedef enum JobStartResult { | |
238 | JOB_RUNNING, /* Job is running */ | 238 | JOB_RUNNING, /* Job is running */ | |
239 | JOB_ERROR, /* Error in starting the job */ | 239 | JOB_ERROR, /* Error in starting the job */ | |
240 | JOB_FINISHED /* The job is already finished */ | 240 | JOB_FINISHED /* The job is already finished */ | |
241 | } JobStartResult; | 241 | } JobStartResult; | |
242 | 242 | |||
243 | /* | 243 | /* | |
244 | * Descriptions for various shells. | 244 | * Descriptions for various shells. | |
245 | * | 245 | * | |
246 | * The build environment may set DEFSHELL_INDEX to one of | 246 | * The build environment may set DEFSHELL_INDEX to one of | |
247 | * DEFSHELL_INDEX_SH, DEFSHELL_INDEX_KSH, or DEFSHELL_INDEX_CSH, to | 247 | * DEFSHELL_INDEX_SH, DEFSHELL_INDEX_KSH, or DEFSHELL_INDEX_CSH, to | |
248 | * select one of the predefined shells as the default shell. | 248 | * select one of the predefined shells as the default shell. | |
249 | * | 249 | * | |
250 | * Alternatively, the build environment may set DEFSHELL_CUSTOM to the | 250 | * Alternatively, the build environment may set DEFSHELL_CUSTOM to the | |
251 | * name or the full path of a sh-compatible shell, which will be used as | 251 | * name or the full path of a sh-compatible shell, which will be used as | |
252 | * the default shell. | 252 | * the default shell. | |
253 | * | 253 | * | |
254 | * ".SHELL" lines in Makefiles can choose the default shell from the | 254 | * ".SHELL" lines in Makefiles can choose the default shell from the | |
255 | * set defined here, or add additional shells. | 255 | * set defined here, or add additional shells. | |
256 | */ | 256 | */ | |
257 | 257 | |||
258 | #ifdef DEFSHELL_CUSTOM | 258 | #ifdef DEFSHELL_CUSTOM | |
259 | #define DEFSHELL_INDEX_CUSTOM 0 | 259 | #define DEFSHELL_INDEX_CUSTOM 0 | |
260 | #define DEFSHELL_INDEX_SH 1 | 260 | #define DEFSHELL_INDEX_SH 1 | |
261 | #define DEFSHELL_INDEX_KSH 2 | 261 | #define DEFSHELL_INDEX_KSH 2 | |
262 | #define DEFSHELL_INDEX_CSH 3 | 262 | #define DEFSHELL_INDEX_CSH 3 | |
263 | #else /* !DEFSHELL_CUSTOM */ | 263 | #else /* !DEFSHELL_CUSTOM */ | |
264 | #define DEFSHELL_INDEX_SH 0 | 264 | #define DEFSHELL_INDEX_SH 0 | |
265 | #define DEFSHELL_INDEX_KSH 1 | 265 | #define DEFSHELL_INDEX_KSH 1 | |
266 | #define DEFSHELL_INDEX_CSH 2 | 266 | #define DEFSHELL_INDEX_CSH 2 | |
267 | #endif /* !DEFSHELL_CUSTOM */ | 267 | #endif /* !DEFSHELL_CUSTOM */ | |
268 | 268 | |||
269 | #ifndef DEFSHELL_INDEX | 269 | #ifndef DEFSHELL_INDEX | |
270 | #define DEFSHELL_INDEX 0 /* DEFSHELL_INDEX_CUSTOM or DEFSHELL_INDEX_SH */ | 270 | #define DEFSHELL_INDEX 0 /* DEFSHELL_INDEX_CUSTOM or DEFSHELL_INDEX_SH */ | |
271 | #endif /* !DEFSHELL_INDEX */ | 271 | #endif /* !DEFSHELL_INDEX */ | |
272 | 272 | |||
273 | static Shell shells[] = { | 273 | static Shell shells[] = { | |
274 | #ifdef DEFSHELL_CUSTOM | 274 | #ifdef DEFSHELL_CUSTOM | |
275 | /* | 275 | /* | |
276 | * An sh-compatible shell with a non-standard name. | 276 | * An sh-compatible shell with a non-standard name. | |
277 | * | 277 | * | |
278 | * Keep this in sync with the "sh" description below, but avoid | 278 | * Keep this in sync with the "sh" description below, but avoid | |
279 | * non-portable features that might not be supplied by all | 279 | * non-portable features that might not be supplied by all | |
280 | * sh-compatible shells. | 280 | * sh-compatible shells. | |
281 | */ | 281 | */ | |
282 | { | 282 | { | |
283 | DEFSHELL_CUSTOM, /* .name */ | 283 | DEFSHELL_CUSTOM, /* .name */ | |
284 | FALSE, /* .hasEchoCtl */ | 284 | FALSE, /* .hasEchoCtl */ | |
285 | "", /* .echoOff */ | 285 | "", /* .echoOff */ | |
286 | "", /* .echoOn */ | 286 | "", /* .echoOn */ | |
287 | "", /* .noPrint */ | 287 | "", /* .noPrint */ | |
288 | 0, /* .noPrintLen */ | 288 | 0, /* .noPrintLen */ | |
289 | FALSE, /* .hasErrCtl */ | 289 | FALSE, /* .hasErrCtl */ | |
290 | "echo \"%s\"\n", /* .errOnOrEcho */ | 290 | "echo \"%s\"\n", /* .errOnOrEcho */ | |
291 | "%s\n", /* .errOffOrExecIgnore */ | 291 | "%s\n", /* .errOffOrExecIgnore */ | |
292 | "{ %s \n} || exit $?\n", /* .errExit */ | 292 | "{ %s \n} || exit $?\n", /* .errExit */ | |
293 | "'\n'", /* .newline */ | 293 | "'\n'", /* .newline */ | |
294 | '#', /* .commentChar */ | 294 | '#', /* .commentChar */ | |
295 | "", /* .echo */ | 295 | "", /* .echo */ | |
296 | "", /* .exit */ | 296 | "", /* .exit */ | |
297 | }, | 297 | }, | |
298 | #endif /* DEFSHELL_CUSTOM */ | 298 | #endif /* DEFSHELL_CUSTOM */ | |
299 | /* | 299 | /* | |
300 | * SH description. Echo control is also possible and, under | 300 | * SH description. Echo control is also possible and, under | |
301 | * sun UNIX anyway, one can even control error checking. | 301 | * sun UNIX anyway, one can even control error checking. | |
302 | */ | 302 | */ | |
303 | { | 303 | { | |
304 | "sh", /* .name */ | 304 | "sh", /* .name */ | |
305 | FALSE, /* .hasEchoCtl */ | 305 | FALSE, /* .hasEchoCtl */ | |
306 | "", /* .echoOff */ | 306 | "", /* .echoOff */ | |
307 | "", /* .echoOn */ | 307 | "", /* .echoOn */ | |
308 | "", /* .noPrint */ | 308 | "", /* .noPrint */ | |
309 | 0, /* .noPrintLen */ | 309 | 0, /* .noPrintLen */ | |
310 | FALSE, /* .hasErrCtl */ | 310 | FALSE, /* .hasErrCtl */ | |
311 | "echo \"%s\"\n", /* .errOnOrEcho */ | 311 | "echo \"%s\"\n", /* .errOnOrEcho */ | |
312 | "%s\n", /* .errOffOrExecIgnore */ | 312 | "%s\n", /* .errOffOrExecIgnore */ | |
313 | "{ %s \n} || exit $?\n", /* .errExit */ | 313 | "{ %s \n} || exit $?\n", /* .errExit */ | |
314 | "'\n'", /* .newline */ | 314 | "'\n'", /* .newline */ | |
315 | '#', /* .commentChar*/ | 315 | '#', /* .commentChar*/ | |
316 | #if defined(MAKE_NATIVE) && defined(__NetBSD__) | 316 | #if defined(MAKE_NATIVE) && defined(__NetBSD__) | |
317 | "q", /* .echo */ | 317 | "q", /* .echo */ | |
318 | #else | 318 | #else | |
319 | "", /* .echo */ | 319 | "", /* .echo */ | |
320 | #endif | 320 | #endif | |
321 | "", /* .exit */ | 321 | "", /* .exit */ | |
322 | }, | 322 | }, | |
323 | /* | 323 | /* | |
324 | * KSH description. | 324 | * KSH description. | |
325 | */ | 325 | */ | |
326 | { | 326 | { | |
327 | "ksh", /* .name */ | 327 | "ksh", /* .name */ | |
328 | TRUE, /* .hasEchoCtl */ | 328 | TRUE, /* .hasEchoCtl */ | |
329 | "set +v", /* .echoOff */ | 329 | "set +v", /* .echoOff */ | |
330 | "set -v", /* .echoOn */ | 330 | "set -v", /* .echoOn */ | |
331 | "set +v", /* .noPrint */ | 331 | "set +v", /* .noPrint */ | |
332 | 6, /* .noPrintLen */ | 332 | 6, /* .noPrintLen */ | |
333 | FALSE, /* .hasErrCtl */ | 333 | FALSE, /* .hasErrCtl */ | |
334 | "echo \"%s\"\n", /* .errOnOrEcho */ | 334 | "echo \"%s\"\n", /* .errOnOrEcho */ | |
335 | "%s\n", /* .errOffOrExecIgnore */ | 335 | "%s\n", /* .errOffOrExecIgnore */ | |
336 | "{ %s \n} || exit $?\n", /* .errExit */ | 336 | "{ %s \n} || exit $?\n", /* .errExit */ | |
337 | "'\n'", /* .newline */ | 337 | "'\n'", /* .newline */ | |
338 | '#', /* .commentChar */ | 338 | '#', /* .commentChar */ | |
339 | "v", /* .echo */ | 339 | "v", /* .echo */ | |
340 | "", /* .exit */ | 340 | "", /* .exit */ | |
341 | }, | 341 | }, | |
342 | /* | 342 | /* | |
343 | * CSH description. The csh can do echo control by playing | 343 | * CSH description. The csh can do echo control by playing | |
344 | * with the setting of the 'echo' shell variable. Sadly, | 344 | * with the setting of the 'echo' shell variable. Sadly, | |
345 | * however, it is unable to do error control nicely. | 345 | * however, it is unable to do error control nicely. | |
346 | */ | 346 | */ | |
347 | { | 347 | { | |
348 | "csh", /* .name */ | 348 | "csh", /* .name */ | |
349 | TRUE, /* .hasEchoCtl */ | 349 | TRUE, /* .hasEchoCtl */ | |
350 | "unset verbose", /* .echoOff */ | 350 | "unset verbose", /* .echoOff */ | |
351 | "set verbose", /* .echoOn */ | 351 | "set verbose", /* .echoOn */ | |
352 | "unset verbose", /* .noPrint */ | 352 | "unset verbose", /* .noPrint */ | |
353 | 13, /* .noPrintLen */ | 353 | 13, /* .noPrintLen */ | |
354 | FALSE, /* .hasErrCtl */ | 354 | FALSE, /* .hasErrCtl */ | |
355 | "echo \"%s\"\n", /* .errOnOrEcho */ | 355 | "echo \"%s\"\n", /* .errOnOrEcho */ | |
356 | /* XXX: Mismatch between errOn and execIgnore */ | 356 | /* XXX: Mismatch between errOn and execIgnore */ | |
357 | "csh -c \"%s || exit 0\"\n", /* .errOffOrExecIgnore */ | 357 | "csh -c \"%s || exit 0\"\n", /* .errOffOrExecIgnore */ | |
358 | "", /* .errExit */ | 358 | "", /* .errExit */ | |
359 | "'\\\n'", /* .newline */ | 359 | "'\\\n'", /* .newline */ | |
360 | '#', /* .commentChar */ | 360 | '#', /* .commentChar */ | |
361 | "v", /* .echo */ | 361 | "v", /* .echo */ | |
362 | "e", /* .exit */ | 362 | "e", /* .exit */ | |
363 | } | 363 | } | |
364 | }; | 364 | }; | |
365 | 365 | |||
366 | /* This is the shell to which we pass all commands in the Makefile. | 366 | /* This is the shell to which we pass all commands in the Makefile. | |
367 | * It is set by the Job_ParseShell function. */ | 367 | * It is set by the Job_ParseShell function. */ | |
368 | static Shell *commandShell = &shells[DEFSHELL_INDEX]; | 368 | static Shell *commandShell = &shells[DEFSHELL_INDEX]; | |
369 | const char *shellPath = NULL; /* full pathname of executable image */ | 369 | const char *shellPath = NULL; /* full pathname of executable image */ | |
370 | const char *shellName = NULL; /* last component of shellPath */ | 370 | const char *shellName = NULL; /* last component of shellPath */ | |
371 | char *shellErrFlag = NULL; | 371 | char *shellErrFlag = NULL; | |
372 | static char *shellArgv = NULL; /* Custom shell args */ | 372 | static char *shellArgv = NULL; /* Custom shell args */ | |
373 | 373 | |||
374 | 374 | |||
375 | static Job *job_table; /* The structures that describe them */ | 375 | static Job *job_table; /* The structures that describe them */ | |
376 | static Job *job_table_end; /* job_table + maxJobs */ | 376 | static Job *job_table_end; /* job_table + maxJobs */ | |
377 | static unsigned int wantToken; /* we want a token */ | 377 | static unsigned int wantToken; /* we want a token */ | |
378 | static int lurking_children = 0; | 378 | static int lurking_children = 0; | |
379 | static int make_suspended = 0; /* non-zero if we've seen a SIGTSTP (etc) */ | 379 | static int make_suspended = 0; /* non-zero if we've seen a SIGTSTP (etc) */ | |
380 | 380 | |||
381 | /* | 381 | /* | |
382 | * Set of descriptors of pipes connected to | 382 | * Set of descriptors of pipes connected to | |
383 | * the output channels of children | 383 | * the output channels of children | |
384 | */ | 384 | */ | |
385 | static struct pollfd *fds = NULL; | 385 | static struct pollfd *fds = NULL; | |
386 | static Job **jobfds = NULL; | 386 | static Job **jobfds = NULL; | |
387 | static nfds_t nfds = 0; | 387 | static nfds_t nfds = 0; | |
388 | static void watchfd(Job *); | 388 | static void watchfd(Job *); | |
389 | static void clearfd(Job *); | 389 | static void clearfd(Job *); | |
390 | static int readyfd(Job *); | 390 | static int readyfd(Job *); | |
391 | 391 | |||
392 | static GNode *lastNode; /* The node for which output was most recently | 392 | static GNode *lastNode; /* The node for which output was most recently | |
393 | * produced. */ | 393 | * produced. */ | |
394 | static char *targPrefix = NULL; /* What we print at the start of TARG_FMT */ | 394 | static char *targPrefix = NULL; /* What we print at the start of TARG_FMT */ | |
395 | static Job tokenWaitJob; /* token wait pseudo-job */ | 395 | static Job tokenWaitJob; /* token wait pseudo-job */ | |
396 | 396 | |||
397 | static Job childExitJob; /* child exit pseudo-job */ | 397 | static Job childExitJob; /* child exit pseudo-job */ | |
398 | #define CHILD_EXIT "." | 398 | #define CHILD_EXIT "." | |
399 | #define DO_JOB_RESUME "R" | 399 | #define DO_JOB_RESUME "R" | |
400 | 400 | |||
401 | enum { npseudojobs = 2 }; /* number of pseudo-jobs */ | 401 | enum { npseudojobs = 2 }; /* number of pseudo-jobs */ | |
402 | 402 | |||
403 | #define TARG_FMT "%s %s ---\n" /* Default format */ | 403 | #define TARG_FMT "%s %s ---\n" /* Default format */ | |
404 | #define MESSAGE(fp, gn) \ | 404 | #define MESSAGE(fp, gn) \ | |
405 | if (opts.maxJobs != 1 && targPrefix && *targPrefix) \ | 405 | if (opts.maxJobs != 1 && targPrefix && *targPrefix) \ | |
406 | (void)fprintf(fp, TARG_FMT, targPrefix, gn->name) | 406 | (void)fprintf(fp, TARG_FMT, targPrefix, gn->name) | |
407 | 407 | |||
408 | static sigset_t caught_signals; /* Set of signals we handle */ | 408 | static sigset_t caught_signals; /* Set of signals we handle */ | |
409 | 409 | |||
410 | static void JobDoOutput(Job *, Boolean); | 410 | static void JobDoOutput(Job *, Boolean); | |
411 | static void JobInterrupt(int, int) MAKE_ATTR_DEAD; | 411 | static void JobInterrupt(int, int) MAKE_ATTR_DEAD; | |
412 | static void JobRestartJobs(void); | 412 | static void JobRestartJobs(void); | |
413 | static void JobSigReset(void); | 413 | static void JobSigReset(void); | |
414 | 414 | |||
415 | static unsigned | 415 | static unsigned | |
416 | nfds_per_job(void) | 416 | nfds_per_job(void) | |
417 | { | 417 | { | |
418 | #if defined(USE_FILEMON) && !defined(USE_FILEMON_DEV) | 418 | #if defined(USE_FILEMON) && !defined(USE_FILEMON_DEV) | |
419 | if (useMeta) | 419 | if (useMeta) | |
420 | return 2; | 420 | return 2; | |
421 | #endif | 421 | #endif | |
422 | return 1; | 422 | return 1; | |
423 | } | 423 | } | |
424 | 424 | |||
425 | static void | 425 | static void | |
426 | job_table_dump(const char *where) | 426 | job_table_dump(const char *where) | |
427 | { | 427 | { | |
428 | Job *job; | 428 | Job *job; | |
429 | 429 | |||
430 | debug_printf("job table @ %s\n", where); | 430 | debug_printf("job table @ %s\n", where); | |
431 | for (job = job_table; job < job_table_end; job++) { | 431 | for (job = job_table; job < job_table_end; job++) { | |
432 | debug_printf("job %d, status %d, flags %d, pid %d\n", | 432 | debug_printf("job %d, status %d, flags %d, pid %d\n", | |
433 | (int)(job - job_table), job->job_state, job->flags, job->pid); | 433 | (int)(job - job_table), job->job_state, job->flags, job->pid); | |
434 | } | 434 | } | |
435 | } | 435 | } | |
436 | 436 | |||
437 | /* | 437 | /* | |
438 | * Delete the target of a failed, interrupted, or otherwise | 438 | * Delete the target of a failed, interrupted, or otherwise | |
439 | * unsuccessful job unless inhibited by .PRECIOUS. | 439 | * unsuccessful job unless inhibited by .PRECIOUS. | |
440 | */ | 440 | */ | |
441 | static void | 441 | static void | |
442 | JobDeleteTarget(GNode *gn) | 442 | JobDeleteTarget(GNode *gn) | |
443 | { | 443 | { | |
444 | const char *file; | 444 | const char *file; | |
445 | 445 | |||
446 | if (gn->type & OP_JOIN) | 446 | if (gn->type & OP_JOIN) | |
447 | return; | 447 | return; | |
448 | if (gn->type & OP_PHONY) | 448 | if (gn->type & OP_PHONY) | |
449 | return; | 449 | return; | |
450 | if (Targ_Precious(gn)) | 450 | if (Targ_Precious(gn)) | |
451 | return; | 451 | return; | |
452 | if (opts.noExecute) | 452 | if (opts.noExecute) | |
453 | return; | 453 | return; | |
454 | 454 | |||
455 | file = GNode_Path(gn); | 455 | file = GNode_Path(gn); | |
456 | if (eunlink(file) != -1) | 456 | if (eunlink(file) != -1) | |
457 | Error("*** %s removed", file); | 457 | Error("*** %s removed", file); | |
458 | } | 458 | } | |
459 | 459 | |||
460 | /* | 460 | /* | |
461 | * JobSigLock/JobSigUnlock | 461 | * JobSigLock/JobSigUnlock | |
462 | * | 462 | * | |
463 | * Signal lock routines to get exclusive access. Currently used to | 463 | * Signal lock routines to get exclusive access. Currently used to | |
464 | * protect `jobs' and `stoppedJobs' list manipulations. | 464 | * protect `jobs' and `stoppedJobs' list manipulations. | |
465 | */ | 465 | */ | |
466 | static void JobSigLock(sigset_t *omaskp) | 466 | static void JobSigLock(sigset_t *omaskp) | |
467 | { | 467 | { | |
468 | if (sigprocmask(SIG_BLOCK, &caught_signals, omaskp) != 0) { | 468 | if (sigprocmask(SIG_BLOCK, &caught_signals, omaskp) != 0) { | |
469 | Punt("JobSigLock: sigprocmask: %s", strerror(errno)); | 469 | Punt("JobSigLock: sigprocmask: %s", strerror(errno)); | |
470 | sigemptyset(omaskp); | 470 | sigemptyset(omaskp); | |
471 | } | 471 | } | |
472 | } | 472 | } | |
473 | 473 | |||
474 | static void JobSigUnlock(sigset_t *omaskp) | 474 | static void JobSigUnlock(sigset_t *omaskp) | |
475 | { | 475 | { | |
476 | (void)sigprocmask(SIG_SETMASK, omaskp, NULL); | 476 | (void)sigprocmask(SIG_SETMASK, omaskp, NULL); | |
477 | } | 477 | } | |
478 | 478 | |||
479 | static void | 479 | static void | |
480 | JobCreatePipe(Job *job, int minfd) | 480 | JobCreatePipe(Job *job, int minfd) | |
481 | { | 481 | { | |
482 | int i, fd, flags; | 482 | int i, fd, flags; | |
483 | int pipe_fds[2]; | 483 | int pipe_fds[2]; | |
484 | 484 | |||
485 | if (pipe(pipe_fds) == -1) | 485 | if (pipe(pipe_fds) == -1) | |
486 | Punt("Cannot create pipe: %s", strerror(errno)); | 486 | Punt("Cannot create pipe: %s", strerror(errno)); | |
487 | 487 | |||
488 | for (i = 0; i < 2; i++) { | 488 | for (i = 0; i < 2; i++) { | |
489 | /* Avoid using low numbered fds */ | 489 | /* Avoid using low numbered fds */ | |
490 | fd = fcntl(pipe_fds[i], F_DUPFD, minfd); | 490 | fd = fcntl(pipe_fds[i], F_DUPFD, minfd); | |
491 | if (fd != -1) { | 491 | if (fd != -1) { | |
492 | close(pipe_fds[i]); | 492 | close(pipe_fds[i]); | |
493 | pipe_fds[i] = fd; | 493 | pipe_fds[i] = fd; | |
494 | } | 494 | } | |
495 | } | 495 | } | |
496 | 496 | |||
497 | job->inPipe = pipe_fds[0]; | 497 | job->inPipe = pipe_fds[0]; | |
498 | job->outPipe = pipe_fds[1]; | 498 | job->outPipe = pipe_fds[1]; | |
499 | 499 | |||
500 | /* Set close-on-exec flag for both */ | 500 | /* Set close-on-exec flag for both */ | |
501 | if (fcntl(job->inPipe, F_SETFD, FD_CLOEXEC) == -1) | 501 | if (fcntl(job->inPipe, F_SETFD, FD_CLOEXEC) == -1) | |
502 | Punt("Cannot set close-on-exec: %s", strerror(errno)); | 502 | Punt("Cannot set close-on-exec: %s", strerror(errno)); | |
503 | if (fcntl(job->outPipe, F_SETFD, FD_CLOEXEC) == -1) | 503 | if (fcntl(job->outPipe, F_SETFD, FD_CLOEXEC) == -1) | |
504 | Punt("Cannot set close-on-exec: %s", strerror(errno)); | 504 | Punt("Cannot set close-on-exec: %s", strerror(errno)); | |
505 | 505 | |||
506 | /* | 506 | /* | |
507 | * We mark the input side of the pipe non-blocking; we poll(2) the | 507 | * We mark the input side of the pipe non-blocking; we poll(2) the | |
508 | * pipe when we're waiting for a job token, but we might lose the | 508 | * pipe when we're waiting for a job token, but we might lose the | |
509 | * race for the token when a new one becomes available, so the read | 509 | * race for the token when a new one becomes available, so the read | |
510 | * from the pipe should not block. | 510 | * from the pipe should not block. | |
511 | */ | 511 | */ | |
512 | flags = fcntl(job->inPipe, F_GETFL, 0); | 512 | flags = fcntl(job->inPipe, F_GETFL, 0); | |
513 | if (flags == -1) | 513 | if (flags == -1) | |
514 | Punt("Cannot get flags: %s", strerror(errno)); | 514 | Punt("Cannot get flags: %s", strerror(errno)); | |
515 | flags |= O_NONBLOCK; | 515 | flags |= O_NONBLOCK; | |
516 | if (fcntl(job->inPipe, F_SETFL, flags) == -1) | 516 | if (fcntl(job->inPipe, F_SETFL, flags) == -1) | |
517 | Punt("Cannot set flags: %s", strerror(errno)); | 517 | Punt("Cannot set flags: %s", strerror(errno)); | |
518 | } | 518 | } | |
519 | 519 | |||
520 | /* Pass the signal to each running job. */ | 520 | /* Pass the signal to each running job. */ | |
521 | static void | 521 | static void | |
522 | JobCondPassSig(int signo) | 522 | JobCondPassSig(int signo) | |
523 | { | 523 | { | |
524 | Job *job; | 524 | Job *job; | |
525 | 525 | |||
526 | DEBUG1(JOB, "JobCondPassSig(%d) called.\n", signo); | 526 | DEBUG1(JOB, "JobCondPassSig(%d) called.\n", signo); | |
527 | 527 | |||
528 | for (job = job_table; job < job_table_end; job++) { | 528 | for (job = job_table; job < job_table_end; job++) { | |
529 | if (job->job_state != JOB_ST_RUNNING) | 529 | if (job->job_state != JOB_ST_RUNNING) | |
530 | continue; | 530 | continue; | |
531 | DEBUG2(JOB, "JobCondPassSig passing signal %d to child %d.\n", | 531 | DEBUG2(JOB, "JobCondPassSig passing signal %d to child %d.\n", | |
532 | signo, job->pid); | 532 | signo, job->pid); | |
533 | KILLPG(job->pid, signo); | 533 | KILLPG(job->pid, signo); | |
534 | } | 534 | } | |
535 | } | 535 | } | |
536 | 536 | |||
537 | /* SIGCHLD handler. | 537 | /* SIGCHLD handler. | |
538 | * | 538 | * | |
539 | * Sends a token on the child exit pipe to wake us up from select()/poll(). */ | 539 | * Sends a token on the child exit pipe to wake us up from select()/poll(). */ | |
540 | static void | 540 | static void | |
541 | JobChildSig(int signo MAKE_ATTR_UNUSED) | 541 | JobChildSig(int signo MAKE_ATTR_UNUSED) | |
542 | { | 542 | { | |
543 | while (write(childExitJob.outPipe, CHILD_EXIT, 1) == -1 && errno == EAGAIN) | 543 | while (write(childExitJob.outPipe, CHILD_EXIT, 1) == -1 && errno == EAGAIN) | |
544 | continue; | 544 | continue; | |
545 | } | 545 | } | |
546 | 546 | |||
547 | 547 | |||
548 | /* Resume all stopped jobs. */ | 548 | /* Resume all stopped jobs. */ | |
549 | static void | 549 | static void | |
550 | JobContinueSig(int signo MAKE_ATTR_UNUSED) | 550 | JobContinueSig(int signo MAKE_ATTR_UNUSED) | |
551 | { | 551 | { | |
552 | /* | 552 | /* | |
553 | * Defer sending SIGCONT to our stopped children until we return | 553 | * Defer sending SIGCONT to our stopped children until we return | |
554 | * from the signal handler. | 554 | * from the signal handler. | |
555 | */ | 555 | */ | |
556 | while (write(childExitJob.outPipe, DO_JOB_RESUME, 1) == -1 && | 556 | while (write(childExitJob.outPipe, DO_JOB_RESUME, 1) == -1 && | |
557 | errno == EAGAIN) | 557 | errno == EAGAIN) | |
558 | continue; | 558 | continue; | |
559 | } | 559 | } | |
560 | 560 | |||
561 | /* Pass a signal on to all jobs, then resend to ourselves. | 561 | /* Pass a signal on to all jobs, then resend to ourselves. | |
562 | * We die by the same signal. */ | 562 | * We die by the same signal. */ | |
563 | MAKE_ATTR_DEAD static void | 563 | MAKE_ATTR_DEAD static void | |
564 | JobPassSig_int(int signo) | 564 | JobPassSig_int(int signo) | |
565 | { | 565 | { | |
566 | /* Run .INTERRUPT target then exit */ | 566 | /* Run .INTERRUPT target then exit */ | |
567 | JobInterrupt(TRUE, signo); | 567 | JobInterrupt(TRUE, signo); | |
568 | } | 568 | } | |
569 | 569 | |||
570 | /* Pass a signal on to all jobs, then resend to ourselves. | 570 | /* Pass a signal on to all jobs, then resend to ourselves. | |
571 | * We die by the same signal. */ | 571 | * We die by the same signal. */ | |
572 | MAKE_ATTR_DEAD static void | 572 | MAKE_ATTR_DEAD static void | |
573 | JobPassSig_term(int signo) | 573 | JobPassSig_term(int signo) | |
574 | { | 574 | { | |
575 | /* Dont run .INTERRUPT target then exit */ | 575 | /* Dont run .INTERRUPT target then exit */ | |
576 | JobInterrupt(FALSE, signo); | 576 | JobInterrupt(FALSE, signo); | |
577 | } | 577 | } | |
578 | 578 | |||
579 | static void | 579 | static void | |
580 | JobPassSig_suspend(int signo) | 580 | JobPassSig_suspend(int signo) | |
581 | { | 581 | { | |
582 | sigset_t nmask, omask; | 582 | sigset_t nmask, omask; | |
583 | struct sigaction act; | 583 | struct sigaction act; | |
584 | 584 | |||
585 | /* Suppress job started/continued messages */ | 585 | /* Suppress job started/continued messages */ | |
586 | make_suspended = 1; | 586 | make_suspended = 1; | |
587 | 587 | |||
588 | /* Pass the signal onto every job */ | 588 | /* Pass the signal onto every job */ | |
589 | JobCondPassSig(signo); | 589 | JobCondPassSig(signo); | |
590 | 590 | |||
591 | /* | 591 | /* | |
592 | * Send ourselves the signal now we've given the message to everyone else. | 592 | * Send ourselves the signal now we've given the message to everyone else. | |
593 | * Note we block everything else possible while we're getting the signal. | 593 | * Note we block everything else possible while we're getting the signal. | |
594 | * This ensures that all our jobs get continued when we wake up before | 594 | * This ensures that all our jobs get continued when we wake up before | |
595 | * we take any other signal. | 595 | * we take any other signal. | |
596 | */ | 596 | */ | |
597 | sigfillset(&nmask); | 597 | sigfillset(&nmask); | |
598 | sigdelset(&nmask, signo); | 598 | sigdelset(&nmask, signo); | |
599 | (void)sigprocmask(SIG_SETMASK, &nmask, &omask); | 599 | (void)sigprocmask(SIG_SETMASK, &nmask, &omask); | |
600 | 600 | |||
601 | act.sa_handler = SIG_DFL; | 601 | act.sa_handler = SIG_DFL; | |
602 | sigemptyset(&act.sa_mask); | 602 | sigemptyset(&act.sa_mask); | |
603 | act.sa_flags = 0; | 603 | act.sa_flags = 0; | |
604 | (void)sigaction(signo, &act, NULL); | 604 | (void)sigaction(signo, &act, NULL); | |
605 | 605 | |||
606 | if (DEBUG(JOB)) | 606 | if (DEBUG(JOB)) | |
607 | debug_printf("JobPassSig passing signal %d to self.\n", signo); | 607 | debug_printf("JobPassSig passing signal %d to self.\n", signo); | |
608 | 608 | |||
609 | (void)kill(getpid(), signo); | 609 | (void)kill(getpid(), signo); | |
610 | 610 | |||
611 | /* | 611 | /* | |
612 | * We've been continued. | 612 | * We've been continued. | |
613 | * | 613 | * | |
614 | * A whole host of signals continue to happen! | 614 | * A whole host of signals continue to happen! | |
615 | * SIGCHLD for any processes that actually suspended themselves. | 615 | * SIGCHLD for any processes that actually suspended themselves. | |
616 | * SIGCHLD for any processes that exited while we were alseep. | 616 | * SIGCHLD for any processes that exited while we were alseep. | |
617 | * The SIGCONT that actually caused us to wakeup. | 617 | * The SIGCONT that actually caused us to wakeup. | |
618 | * | 618 | * | |
619 | * Since we defer passing the SIGCONT on to our children until | 619 | * Since we defer passing the SIGCONT on to our children until | |
620 | * the main processing loop, we can be sure that all the SIGCHLD | 620 | * the main processing loop, we can be sure that all the SIGCHLD | |
621 | * events will have happened by then - and that the waitpid() will | 621 | * events will have happened by then - and that the waitpid() will | |
622 | * collect the child 'suspended' events. | 622 | * collect the child 'suspended' events. | |
623 | * For correct sequencing we just need to ensure we process the | 623 | * For correct sequencing we just need to ensure we process the | |
624 | * waitpid() before passing on the SIGCONT. | 624 | * waitpid() before passing on the SIGCONT. | |
625 | * | 625 | * | |
626 | * In any case nothing else is needed here. | 626 | * In any case nothing else is needed here. | |
627 | */ | 627 | */ | |
628 | 628 | |||
629 | /* Restore handler and signal mask */ | 629 | /* Restore handler and signal mask */ | |
630 | act.sa_handler = JobPassSig_suspend; | 630 | act.sa_handler = JobPassSig_suspend; | |
631 | (void)sigaction(signo, &act, NULL); | 631 | (void)sigaction(signo, &act, NULL); | |
632 | (void)sigprocmask(SIG_SETMASK, &omask, NULL); | 632 | (void)sigprocmask(SIG_SETMASK, &omask, NULL); | |
633 | } | 633 | } | |
634 | 634 | |||
635 | static Job * | 635 | static Job * | |
636 | JobFindPid(int pid, JobState status, Boolean isJobs) | 636 | JobFindPid(int pid, JobState status, Boolean isJobs) | |
637 | { | 637 | { | |
638 | Job *job; | 638 | Job *job; | |
639 | 639 | |||
640 | for (job = job_table; job < job_table_end; job++) { | 640 | for (job = job_table; job < job_table_end; job++) { | |
641 | if ((job->job_state == status) && job->pid == pid) | 641 | if ((job->job_state == status) && job->pid == pid) | |
642 | return job; | 642 | return job; | |
643 | } | 643 | } | |
644 | if (DEBUG(JOB) && isJobs) | 644 | if (DEBUG(JOB) && isJobs) | |
645 | job_table_dump("no pid"); | 645 | job_table_dump("no pid"); | |
646 | return NULL; | 646 | return NULL; | |
647 | } | 647 | } | |
648 | 648 | |||
649 | /* Parse leading '@', '-' and '+', which control the exact execution mode. */ | 649 | /* Parse leading '@', '-' and '+', which control the exact execution mode. */ | |
650 | static void | 650 | static void | |
651 | ParseRunOptions( | 651 | ParseRunOptions( | |
652 | char **pp, | 652 | char **pp, | |
653 | Boolean *out_shutUp, Boolean *out_errOff, Boolean *out_runAlways) | 653 | Boolean *out_shutUp, Boolean *out_errOff, Boolean *out_runAlways) | |
654 | { | 654 | { | |
655 | char *p = *pp; | 655 | char *p = *pp; | |
656 | *out_shutUp = FALSE; | 656 | *out_shutUp = FALSE; | |
657 | *out_errOff = FALSE; | 657 | *out_errOff = FALSE; | |
658 | *out_runAlways = FALSE; | 658 | *out_runAlways = FALSE; | |
659 | 659 | |||
660 | for (;;) { | 660 | for (;;) { | |
661 | if (*p == '@') | 661 | if (*p == '@') | |
662 | *out_shutUp = !DEBUG(LOUD); | 662 | *out_shutUp = !DEBUG(LOUD); | |
663 | else if (*p == '-') | 663 | else if (*p == '-') | |
664 | *out_errOff = TRUE; | 664 | *out_errOff = TRUE; | |
665 | else if (*p == '+') | 665 | else if (*p == '+') | |
666 | *out_runAlways = TRUE; | 666 | *out_runAlways = TRUE; | |
667 | else | 667 | else | |
668 | break; | 668 | break; | |
669 | p++; | 669 | p++; | |
670 | } | 670 | } | |
671 | 671 | |||
672 | pp_skip_whitespace(&p); | 672 | pp_skip_whitespace(&p); | |
673 | 673 | |||
674 | *pp = p; | 674 | *pp = p; | |
675 | } | 675 | } | |
676 | 676 | |||
677 | /* Escape a string for a double-quoted string literal in sh, csh and ksh. */ | 677 | /* Escape a string for a double-quoted string literal in sh, csh and ksh. */ | |
678 | static char * | 678 | static char * | |
679 | EscapeShellDblQuot(const char *cmd) | 679 | EscapeShellDblQuot(const char *cmd) | |
680 | { | 680 | { | |
681 | size_t i, j; | 681 | size_t i, j; | |
682 | 682 | |||
683 | /* Worst that could happen is every char needs escaping. */ | 683 | /* Worst that could happen is every char needs escaping. */ | |
684 | char *esc = bmake_malloc(strlen(cmd) * 2 + 1); | 684 | char *esc = bmake_malloc(strlen(cmd) * 2 + 1); | |
685 | for (i = 0, j = 0; cmd[i] != '\0'; i++, j++) { | 685 | for (i = 0, j = 0; cmd[i] != '\0'; i++, j++) { | |
686 | if (cmd[i] == '$' || cmd[i] == '`' || cmd[i] == '\\' || cmd[i] == '"') | 686 | if (cmd[i] == '$' || cmd[i] == '`' || cmd[i] == '\\' || cmd[i] == '"') | |
687 | esc[j++] = '\\'; | 687 | esc[j++] = '\\'; | |
688 | esc[j] = cmd[i]; | 688 | esc[j] = cmd[i]; | |
689 | } | 689 | } | |
690 | esc[j] = '\0'; | 690 | esc[j] = '\0'; | |
691 | 691 | |||
692 | return esc; | 692 | return esc; | |
693 | } | 693 | } | |
694 | 694 | |||
695 | /*- | 695 | /*- | |
696 | *----------------------------------------------------------------------- | 696 | *----------------------------------------------------------------------- | |
697 | * JobPrintCommand -- | 697 | * JobPrintCommand -- | |
698 | * Put out another command for the given job. If the command starts | 698 | * Put out another command for the given job. If the command starts | |
699 | * with an @ or a - we process it specially. In the former case, | 699 | * with an @ or a - we process it specially. In the former case, | |
700 | * so long as the -s and -n flags weren't given to make, we stick | 700 | * so long as the -s and -n flags weren't given to make, we stick | |
701 | * a shell-specific echoOff command in the script. In the latter, | 701 | * a shell-specific echoOff command in the script. In the latter, | |
702 | * we ignore errors for the entire job, unless the shell has error | 702 | * we ignore errors for the entire job, unless the shell has error | |
703 | * control. | 703 | * control. | |
704 | * If the command is just "..." we take all future commands for this | 704 | * If the command is just "..." we take all future commands for this | |
705 | * job to be commands to be executed once the entire graph has been | 705 | * job to be commands to be executed once the entire graph has been | |
706 | * made and return non-zero to signal that the end of the commands | 706 | * made and return non-zero to signal that the end of the commands | |
707 | * was reached. These commands are later attached to the postCommands | 707 | * was reached. These commands are later attached to the postCommands | |
708 | * node and executed by Job_End when all things are done. | 708 | * node and executed by Job_End when all things are done. | |
709 | * | 709 | * | |
710 | * Side Effects: | 710 | * Side Effects: | |
711 | * If the command begins with a '-' and the shell has no error control, | 711 | * If the command begins with a '-' and the shell has no error control, | |
712 | * the JOB_IGNERR flag is set in the job descriptor. | 712 | * the JOB_IGNERR flag is set in the job descriptor. | |
713 | * numCommands is incremented if the command is actually printed. | 713 | * numCommands is incremented if the command is actually printed. | |
714 | *----------------------------------------------------------------------- | 714 | *----------------------------------------------------------------------- | |
715 | */ | 715 | */ | |
716 | static void | 716 | static void | |
717 | JobPrintCommand(Job *job, char *cmd) | 717 | JobPrintCommand(Job *job, char *cmd) | |
718 | { | 718 | { | |
719 | const char *const cmdp = cmd; | 719 | const char *const cmdp = cmd; | |
720 | Boolean noSpecials; /* true if we shouldn't worry about | 720 | Boolean noSpecials; /* true if we shouldn't worry about | |
721 | * inserting special commands into | 721 | * inserting special commands into | |
722 | * the input stream. */ | 722 | * the input stream. */ | |
723 | Boolean shutUp; /* true if we put a no echo command | 723 | Boolean shutUp; /* true if we put a no echo command | |
724 | * into the command file */ | 724 | * into the command file */ | |
725 | Boolean errOff; /* true if we turned error checking | 725 | Boolean errOff; /* true if we turned error checking | |
726 | * off before printing the command | 726 | * off before printing the command | |
727 | * and need to turn it back on */ | 727 | * and need to turn it back on */ | |
728 | Boolean runAlways; | 728 | Boolean runAlways; | |
729 | const char *cmdTemplate; /* Template to use when printing the | 729 | const char *cmdTemplate; /* Template to use when printing the | |
730 | * command */ | 730 | * command */ | |
731 | char *cmdStart; /* Start of expanded command */ | 731 | char *cmdStart; /* Start of expanded command */ | |
732 | char *escCmd = NULL; /* Command with quotes/backticks escaped */ | 732 | char *escCmd = NULL; /* Command with quotes/backticks escaped */ | |
733 | 733 | |||
734 | noSpecials = NoExecute(job->node); | 734 | noSpecials = !GNode_ShouldExecute(job->node); | |
735 | 735 | |||
736 | #define DBPRINTF(fmt, arg) if (DEBUG(JOB)) { \ | 736 | #define DBPRINTF(fmt, arg) if (DEBUG(JOB)) { \ | |
737 | debug_printf(fmt, arg); \ | 737 | debug_printf(fmt, arg); \ | |
738 | } \ | 738 | } \ | |
739 | (void)fprintf(job->cmdFILE, fmt, arg); \ | 739 | (void)fprintf(job->cmdFILE, fmt, arg); \ | |
740 | (void)fflush(job->cmdFILE); | 740 | (void)fflush(job->cmdFILE); | |
741 | 741 | |||
742 | numCommands++; | 742 | numCommands++; | |
743 | 743 | |||
744 | Var_Subst(cmd, job->node, VARE_WANTRES, &cmd); | 744 | Var_Subst(cmd, job->node, VARE_WANTRES, &cmd); | |
745 | /* TODO: handle errors */ | 745 | /* TODO: handle errors */ | |
746 | cmdStart = cmd; | 746 | cmdStart = cmd; | |
747 | 747 | |||
748 | cmdTemplate = "%s\n"; | 748 | cmdTemplate = "%s\n"; | |
749 | 749 | |||
750 | ParseRunOptions(&cmd, &shutUp, &errOff, &runAlways); | 750 | ParseRunOptions(&cmd, &shutUp, &errOff, &runAlways); | |
751 | 751 | |||
752 | if (runAlways && noSpecials) { | 752 | if (runAlways && noSpecials) { | |
753 | /* | 753 | /* | |
754 | * We're not actually executing anything... | 754 | * We're not actually executing anything... | |
755 | * but this one needs to be - use compat mode just for it. | 755 | * but this one needs to be - use compat mode just for it. | |
756 | */ | 756 | */ | |
757 | Compat_RunCommand(cmdp, job->node); | 757 | Compat_RunCommand(cmdp, job->node); | |
758 | free(cmdStart); | 758 | free(cmdStart); | |
759 | return; | 759 | return; | |
760 | } | 760 | } | |
761 | 761 | |||
762 | /* | 762 | /* | |
763 | * If the shell doesn't have error control the alternate echo'ing will | 763 | * If the shell doesn't have error control the alternate echo'ing will | |
764 | * be done (to avoid showing additional error checking code) | 764 | * be done (to avoid showing additional error checking code) | |
765 | * and this will need the characters '$ ` \ "' escaped | 765 | * and this will need the characters '$ ` \ "' escaped | |
766 | */ | 766 | */ | |
767 | 767 | |||
768 | if (!commandShell->hasErrCtl) | 768 | if (!commandShell->hasErrCtl) | |
769 | escCmd = EscapeShellDblQuot(cmd); | 769 | escCmd = EscapeShellDblQuot(cmd); | |
770 | 770 | |||
771 | if (shutUp) { | 771 | if (shutUp) { | |
772 | if (!(job->flags & JOB_SILENT) && !noSpecials && | 772 | if (!(job->flags & JOB_SILENT) && !noSpecials && | |
773 | commandShell->hasEchoCtl) { | 773 | commandShell->hasEchoCtl) { | |
774 | DBPRINTF("%s\n", commandShell->echoOff); | 774 | DBPRINTF("%s\n", commandShell->echoOff); | |
775 | } else { | 775 | } else { | |
776 | if (commandShell->hasErrCtl) | 776 | if (commandShell->hasErrCtl) | |
777 | shutUp = FALSE; | 777 | shutUp = FALSE; | |
778 | } | 778 | } | |
779 | } | 779 | } | |
780 | 780 | |||
781 | if (errOff) { | 781 | if (errOff) { | |
782 | if (!noSpecials) { | 782 | if (!noSpecials) { | |
783 | if (commandShell->hasErrCtl) { | 783 | if (commandShell->hasErrCtl) { | |
784 | /* | 784 | /* | |
785 | * we don't want the error-control commands showing | 785 | * we don't want the error-control commands showing | |
786 | * up either, so we turn off echoing while executing | 786 | * up either, so we turn off echoing while executing | |
787 | * them. We could put another field in the shell | 787 | * them. We could put another field in the shell | |
788 | * structure to tell JobDoOutput to look for this | 788 | * structure to tell JobDoOutput to look for this | |
789 | * string too, but why make it any more complex than | 789 | * string too, but why make it any more complex than | |
790 | * it already is? | 790 | * it already is? | |
791 | */ | 791 | */ | |
792 | if (!(job->flags & JOB_SILENT) && !shutUp && | 792 | if (!(job->flags & JOB_SILENT) && !shutUp && | |
793 | commandShell->hasEchoCtl) { | 793 | commandShell->hasEchoCtl) { | |
794 | DBPRINTF("%s\n", commandShell->echoOff); | 794 | DBPRINTF("%s\n", commandShell->echoOff); | |
795 | DBPRINTF("%s\n", commandShell->errOffOrExecIgnore); | 795 | DBPRINTF("%s\n", commandShell->errOffOrExecIgnore); | |
796 | DBPRINTF("%s\n", commandShell->echoOn); | 796 | DBPRINTF("%s\n", commandShell->echoOn); | |
797 | } else { | 797 | } else { | |
798 | DBPRINTF("%s\n", commandShell->errOffOrExecIgnore); | 798 | DBPRINTF("%s\n", commandShell->errOffOrExecIgnore); | |
799 | } | 799 | } | |
800 | } else if (commandShell->errOffOrExecIgnore && | 800 | } else if (commandShell->errOffOrExecIgnore && | |
801 | commandShell->errOffOrExecIgnore[0] != '\0') | 801 | commandShell->errOffOrExecIgnore[0] != '\0') | |
802 | { | 802 | { | |
803 | /* | 803 | /* | |
804 | * The shell has no error control, so we need to be | 804 | * The shell has no error control, so we need to be | |
805 | * weird to get it to ignore any errors from the command. | 805 | * weird to get it to ignore any errors from the command. | |
806 | * If echoing is turned on, we turn it off and use the | 806 | * If echoing is turned on, we turn it off and use the | |
807 | * errOnOrEcho template to echo the command. Leave echoing | 807 | * errOnOrEcho template to echo the command. Leave echoing | |
808 | * off so the user doesn't see the weirdness we go through | 808 | * off so the user doesn't see the weirdness we go through | |
809 | * to ignore errors. Set cmdTemplate to use the weirdness | 809 | * to ignore errors. Set cmdTemplate to use the weirdness | |
810 | * instead of the simple "%s\n" template. | 810 | * instead of the simple "%s\n" template. | |
811 | */ | 811 | */ | |
812 | job->flags |= JOB_IGNERR; | 812 | job->flags |= JOB_IGNERR; | |
813 | if (!(job->flags & JOB_SILENT) && !shutUp) { | 813 | if (!(job->flags & JOB_SILENT) && !shutUp) { | |
814 | if (commandShell->hasEchoCtl) { | 814 | if (commandShell->hasEchoCtl) { | |
815 | DBPRINTF("%s\n", commandShell->echoOff); | 815 | DBPRINTF("%s\n", commandShell->echoOff); | |
816 | } | 816 | } | |
817 | DBPRINTF(commandShell->errOnOrEcho, escCmd); | 817 | DBPRINTF(commandShell->errOnOrEcho, escCmd); | |
818 | shutUp = TRUE; | 818 | shutUp = TRUE; | |
819 | } else { | 819 | } else { | |
820 | if (!shutUp) { | 820 | if (!shutUp) { | |
821 | DBPRINTF(commandShell->errOnOrEcho, escCmd); | 821 | DBPRINTF(commandShell->errOnOrEcho, escCmd); | |
822 | } | 822 | } | |
823 | } | 823 | } | |
824 | cmdTemplate = commandShell->errOffOrExecIgnore; | 824 | cmdTemplate = commandShell->errOffOrExecIgnore; | |
825 | /* | 825 | /* | |
826 | * The error ignoration (hee hee) is already taken care | 826 | * The error ignoration (hee hee) is already taken care | |
827 | * of by the errOffOrExecIgnore template, so pretend error | 827 | * of by the errOffOrExecIgnore template, so pretend error | |
828 | * checking is still on. | 828 | * checking is still on. | |
829 | */ | 829 | */ | |
830 | errOff = FALSE; | 830 | errOff = FALSE; | |
831 | } else { | 831 | } else { | |
832 | errOff = FALSE; | 832 | errOff = FALSE; | |
833 | } | 833 | } | |
834 | } else { | 834 | } else { | |
835 | errOff = FALSE; | 835 | errOff = FALSE; | |
836 | } | 836 | } | |
837 | } else { | 837 | } else { | |
838 | 838 | |||
839 | /* | 839 | /* | |
840 | * If errors are being checked and the shell doesn't have error control | 840 | * If errors are being checked and the shell doesn't have error control | |
841 | * but does supply an errExit template, then setup commands to run | 841 | * but does supply an errExit template, then setup commands to run | |
842 | * through it. | 842 | * through it. | |
843 | */ | 843 | */ | |
844 | 844 | |||
845 | if (!commandShell->hasErrCtl && commandShell->errExit && | 845 | if (!commandShell->hasErrCtl && commandShell->errExit && | |
846 | commandShell->errExit[0] != '\0') { | 846 | commandShell->errExit[0] != '\0') { | |
847 | if (!(job->flags & JOB_SILENT) && !shutUp) { | 847 | if (!(job->flags & JOB_SILENT) && !shutUp) { | |
848 | if (commandShell->hasEchoCtl) { | 848 | if (commandShell->hasEchoCtl) { | |
849 | DBPRINTF("%s\n", commandShell->echoOff); | 849 | DBPRINTF("%s\n", commandShell->echoOff); | |
850 | } | 850 | } | |
851 | DBPRINTF(commandShell->errOnOrEcho, escCmd); | 851 | DBPRINTF(commandShell->errOnOrEcho, escCmd); | |
852 | shutUp = TRUE; | 852 | shutUp = TRUE; | |
853 | } | 853 | } | |
854 | /* If it's a comment line or blank, treat as an ignored error */ | 854 | /* If it's a comment line or blank, treat as an ignored error */ | |
855 | if ((escCmd[0] == commandShell->commentChar) || | 855 | if ((escCmd[0] == commandShell->commentChar) || | |
856 | (escCmd[0] == 0)) | 856 | (escCmd[0] == 0)) | |
857 | cmdTemplate = commandShell->errOffOrExecIgnore; | 857 | cmdTemplate = commandShell->errOffOrExecIgnore; | |
858 | else | 858 | else | |
859 | cmdTemplate = commandShell->errExit; | 859 | cmdTemplate = commandShell->errExit; | |
860 | errOff = FALSE; | 860 | errOff = FALSE; | |
861 | } | 861 | } | |
862 | } | 862 | } | |
863 | 863 | |||
864 | if (DEBUG(SHELL) && strcmp(shellName, "sh") == 0 && | 864 | if (DEBUG(SHELL) && strcmp(shellName, "sh") == 0 && | |
865 | (job->flags & JOB_TRACED) == 0) { | 865 | (job->flags & JOB_TRACED) == 0) { | |
866 | DBPRINTF("set -%s\n", "x"); | 866 | DBPRINTF("set -%s\n", "x"); | |
867 | job->flags |= JOB_TRACED; | 867 | job->flags |= JOB_TRACED; | |
868 | } | 868 | } | |
869 | 869 | |||
870 | DBPRINTF(cmdTemplate, cmd); | 870 | DBPRINTF(cmdTemplate, cmd); | |
871 | free(cmdStart); | 871 | free(cmdStart); | |
872 | free(escCmd); | 872 | free(escCmd); | |
873 | if (errOff) { | 873 | if (errOff) { | |
874 | /* | 874 | /* | |
875 | * If echoing is already off, there's no point in issuing the | 875 | * If echoing is already off, there's no point in issuing the | |
876 | * echoOff command. Otherwise we issue it and pretend it was on | 876 | * echoOff command. Otherwise we issue it and pretend it was on | |
877 | * for the whole command... | 877 | * for the whole command... | |
878 | */ | 878 | */ | |
879 | if (!shutUp && !(job->flags & JOB_SILENT) && commandShell->hasEchoCtl){ | 879 | if (!shutUp && !(job->flags & JOB_SILENT) && commandShell->hasEchoCtl){ | |
880 | DBPRINTF("%s\n", commandShell->echoOff); | 880 | DBPRINTF("%s\n", commandShell->echoOff); | |
881 | shutUp = TRUE; | 881 | shutUp = TRUE; | |
882 | } | 882 | } | |
883 | DBPRINTF("%s\n", commandShell->errOnOrEcho); | 883 | DBPRINTF("%s\n", commandShell->errOnOrEcho); | |
884 | } | 884 | } | |
885 | if (shutUp && commandShell->hasEchoCtl) { | 885 | if (shutUp && commandShell->hasEchoCtl) { | |
886 | DBPRINTF("%s\n", commandShell->echoOn); | 886 | DBPRINTF("%s\n", commandShell->echoOn); | |
887 | } | 887 | } | |
888 | } | 888 | } | |
889 | 889 | |||
890 | /* Print all commands to the shell file that is later executed. | 890 | /* Print all commands to the shell file that is later executed. | |
891 | * | 891 | * | |
892 | * The special command "..." stops printing and saves the remaining commands | 892 | * The special command "..." stops printing and saves the remaining commands | |
893 | * to be executed later. */ | 893 | * to be executed later. */ | |
894 | static void | 894 | static void | |
895 | JobPrintCommands(Job *job) | 895 | JobPrintCommands(Job *job) | |
896 | { | 896 | { | |
897 | StringListNode *ln; | 897 | StringListNode *ln; | |
898 | 898 | |||
899 | for (ln = job->node->commands->first; ln != NULL; ln = ln->next) { | 899 | for (ln = job->node->commands->first; ln != NULL; ln = ln->next) { | |
900 | const char *cmd = ln->datum; | 900 | const char *cmd = ln->datum; | |
901 | 901 | |||
902 | if (strcmp(cmd, "...") == 0) { | 902 | if (strcmp(cmd, "...") == 0) { | |
903 | job->node->type |= OP_SAVE_CMDS; | 903 | job->node->type |= OP_SAVE_CMDS; | |
904 | if ((job->flags & JOB_IGNDOTS) == 0) { | 904 | if ((job->flags & JOB_IGNDOTS) == 0) { | |
905 | job->tailCmds = ln->next; | 905 | job->tailCmds = ln->next; | |
906 | break; | 906 | break; | |
907 | } | 907 | } | |
908 | } else | 908 | } else | |
909 | JobPrintCommand(job, ln->datum); | 909 | JobPrintCommand(job, ln->datum); | |
910 | } | 910 | } | |
911 | } | 911 | } | |
912 | 912 | |||
913 | /* Save the delayed commands, to be executed when everything else is done. */ | 913 | /* Save the delayed commands, to be executed when everything else is done. */ | |
914 | static void | 914 | static void | |
915 | JobSaveCommands(Job *job) | 915 | JobSaveCommands(Job *job) | |
916 | { | 916 | { | |
917 | StringListNode *node; | 917 | StringListNode *node; | |
918 | 918 | |||
919 | for (node = job->tailCmds; node != NULL; node = node->next) { | 919 | for (node = job->tailCmds; node != NULL; node = node->next) { | |
920 | const char *cmd = node->datum; | 920 | const char *cmd = node->datum; | |
921 | char *expanded_cmd; | 921 | char *expanded_cmd; | |
922 | /* XXX: This Var_Subst is only intended to expand the dynamic | 922 | /* XXX: This Var_Subst is only intended to expand the dynamic | |
923 | * variables such as .TARGET, .IMPSRC. It is not intended to | 923 | * variables such as .TARGET, .IMPSRC. It is not intended to | |
924 | * expand the other variables as well; see deptgt-end.mk. */ | 924 | * expand the other variables as well; see deptgt-end.mk. */ | |
925 | (void)Var_Subst(cmd, job->node, VARE_WANTRES, &expanded_cmd); | 925 | (void)Var_Subst(cmd, job->node, VARE_WANTRES, &expanded_cmd); | |
926 | /* TODO: handle errors */ | 926 | /* TODO: handle errors */ | |
927 | Lst_Append(Targ_GetEndNode()->commands, expanded_cmd); | 927 | Lst_Append(Targ_GetEndNode()->commands, expanded_cmd); | |
928 | } | 928 | } | |
929 | } | 929 | } | |
930 | 930 | |||
931 | 931 | |||
932 | /* Called to close both input and output pipes when a job is finished. */ | 932 | /* Called to close both input and output pipes when a job is finished. */ | |
933 | static void | 933 | static void | |
934 | JobClose(Job *job) | 934 | JobClose(Job *job) | |
935 | { | 935 | { | |
936 | clearfd(job); | 936 | clearfd(job); | |
937 | (void)close(job->outPipe); | 937 | (void)close(job->outPipe); | |
938 | job->outPipe = -1; | 938 | job->outPipe = -1; | |
939 | 939 | |||
940 | JobDoOutput(job, TRUE); | 940 | JobDoOutput(job, TRUE); | |
941 | (void)close(job->inPipe); | 941 | (void)close(job->inPipe); | |
942 | job->inPipe = -1; | 942 | job->inPipe = -1; | |
943 | } | 943 | } | |
944 | 944 | |||
945 | /*- | 945 | /*- | |
946 | *----------------------------------------------------------------------- | 946 | *----------------------------------------------------------------------- | |
947 | * JobFinish -- | 947 | * JobFinish -- | |
948 | * Do final processing for the given job including updating | 948 | * Do final processing for the given job including updating | |
949 | * parents and starting new jobs as available/necessary. Note | 949 | * parents and starting new jobs as available/necessary. Note | |
950 | * that we pay no attention to the JOB_IGNERR flag here. | 950 | * that we pay no attention to the JOB_IGNERR flag here. | |
951 | * This is because when we're called because of a noexecute flag | 951 | * This is because when we're called because of a noexecute flag | |
952 | * or something, jstat.w_status is 0 and when called from | 952 | * or something, jstat.w_status is 0 and when called from | |
953 | * Job_CatchChildren, the status is zeroed if it s/b ignored. | 953 | * Job_CatchChildren, the status is zeroed if it s/b ignored. | |
954 | * | 954 | * | |
955 | * Input: | 955 | * Input: | |
956 | * job job to finish | 956 | * job job to finish | |
957 | * status sub-why job went away | 957 | * status sub-why job went away | |
958 | * | 958 | * | |
959 | * Side Effects: | 959 | * Side Effects: | |
960 | * Final commands for the job are placed on postCommands. | 960 | * Final commands for the job are placed on postCommands. | |
961 | * | 961 | * | |
962 | * If we got an error and are aborting (aborting == ABORT_ERROR) and | 962 | * If we got an error and are aborting (aborting == ABORT_ERROR) and | |
963 | * the job list is now empty, we are done for the day. | 963 | * the job list is now empty, we are done for the day. | |
964 | * If we recognized an error (errors !=0), we set the aborting flag | 964 | * If we recognized an error (errors !=0), we set the aborting flag | |
965 | * to ABORT_ERROR so no more jobs will be started. | 965 | * to ABORT_ERROR so no more jobs will be started. | |
966 | *----------------------------------------------------------------------- | 966 | *----------------------------------------------------------------------- | |
967 | */ | 967 | */ | |
968 | static void | 968 | static void | |
969 | JobFinish(Job *job, int status) | 969 | JobFinish(Job *job, int status) | |
970 | { | 970 | { | |
971 | Boolean done, return_job_token; | 971 | Boolean done, return_job_token; | |
972 | 972 | |||
973 | DEBUG3(JOB, "JobFinish: %d [%s], status %d\n", | 973 | DEBUG3(JOB, "JobFinish: %d [%s], status %d\n", | |
974 | job->pid, job->node->name, status); | 974 | job->pid, job->node->name, status); | |
975 | 975 | |||
976 | if ((WIFEXITED(status) && | 976 | if ((WIFEXITED(status) && | |
977 | (((WEXITSTATUS(status) != 0) && !(job->flags & JOB_IGNERR)))) || | 977 | (((WEXITSTATUS(status) != 0) && !(job->flags & JOB_IGNERR)))) || | |
978 | WIFSIGNALED(status)) | 978 | WIFSIGNALED(status)) | |
979 | { | 979 | { | |
980 | /* | 980 | /* | |
981 | * If it exited non-zero and either we're doing things our | 981 | * If it exited non-zero and either we're doing things our | |
982 | * way or we're not ignoring errors, the job is finished. | 982 | * way or we're not ignoring errors, the job is finished. | |
983 | * Similarly, if the shell died because of a signal | 983 | * Similarly, if the shell died because of a signal | |
984 | * the job is also finished. In these | 984 | * the job is also finished. In these | |
985 | * cases, finish out the job's output before printing the exit | 985 | * cases, finish out the job's output before printing the exit | |
986 | * status... | 986 | * status... | |
987 | */ | 987 | */ | |
988 | JobClose(job); | 988 | JobClose(job); | |
989 | if (job->cmdFILE != NULL && job->cmdFILE != stdout) { | 989 | if (job->cmdFILE != NULL && job->cmdFILE != stdout) { | |
990 | (void)fclose(job->cmdFILE); | 990 | (void)fclose(job->cmdFILE); | |
991 | job->cmdFILE = NULL; | 991 | job->cmdFILE = NULL; | |
992 | } | 992 | } | |
993 | done = TRUE; | 993 | done = TRUE; | |
994 | } else if (WIFEXITED(status)) { | 994 | } else if (WIFEXITED(status)) { | |
995 | /* | 995 | /* | |
996 | * Deal with ignored errors in -B mode. We need to print a message | 996 | * Deal with ignored errors in -B mode. We need to print a message | |
997 | * telling of the ignored error as well as setting status.w_status | 997 | * telling of the ignored error as well as setting status.w_status | |
998 | * to 0 so the next command gets run. To do this, we set done to be | 998 | * to 0 so the next command gets run. To do this, we set done to be | |
999 | * TRUE if in -B mode and the job exited non-zero. | 999 | * TRUE if in -B mode and the job exited non-zero. | |
1000 | */ | 1000 | */ | |
1001 | done = WEXITSTATUS(status) != 0; | 1001 | done = WEXITSTATUS(status) != 0; | |
1002 | /* | 1002 | /* | |
1003 | * Old comment said: "Note we don't | 1003 | * Old comment said: "Note we don't | |
1004 | * want to close down any of the streams until we know we're at the | 1004 | * want to close down any of the streams until we know we're at the | |
1005 | * end." | 1005 | * end." | |
1006 | * But we do. Otherwise when are we going to print the rest of the | 1006 | * But we do. Otherwise when are we going to print the rest of the | |
1007 | * stuff? | 1007 | * stuff? | |
1008 | */ | 1008 | */ | |
1009 | JobClose(job); | 1009 | JobClose(job); | |
1010 | } else { | 1010 | } else { | |
1011 | /* | 1011 | /* | |
1012 | * No need to close things down or anything. | 1012 | * No need to close things down or anything. | |
1013 | */ | 1013 | */ | |
1014 | done = FALSE; | 1014 | done = FALSE; | |
1015 | } | 1015 | } | |
1016 | 1016 | |||
1017 | if (done) { | 1017 | if (done) { | |
1018 | if (WIFEXITED(status)) { | 1018 | if (WIFEXITED(status)) { | |
1019 | DEBUG2(JOB, "Process %d [%s] exited.\n", | 1019 | DEBUG2(JOB, "Process %d [%s] exited.\n", | |
1020 | job->pid, job->node->name); | 1020 | job->pid, job->node->name); | |
1021 | if (WEXITSTATUS(status) != 0) { | 1021 | if (WEXITSTATUS(status) != 0) { | |
1022 | if (job->node != lastNode) { | 1022 | if (job->node != lastNode) { | |
1023 | MESSAGE(stdout, job->node); | 1023 | MESSAGE(stdout, job->node); | |
1024 | lastNode = job->node; | 1024 | lastNode = job->node; | |
1025 | } | 1025 | } | |
1026 | #ifdef USE_META | 1026 | #ifdef USE_META | |
1027 | if (useMeta) { | 1027 | if (useMeta) { | |
1028 | meta_job_error(job, job->node, job->flags, WEXITSTATUS(status)); | 1028 | meta_job_error(job, job->node, job->flags, WEXITSTATUS(status)); | |
1029 | } | 1029 | } | |
1030 | #endif | 1030 | #endif | |
1031 | if (!dieQuietly(job->node, -1)) | 1031 | if (!dieQuietly(job->node, -1)) | |
1032 | (void)printf("*** [%s] Error code %d%s\n", | 1032 | (void)printf("*** [%s] Error code %d%s\n", | |
1033 | job->node->name, | 1033 | job->node->name, | |
1034 | WEXITSTATUS(status), | 1034 | WEXITSTATUS(status), | |
1035 | (job->flags & JOB_IGNERR) ? " (ignored)" : ""); | 1035 | (job->flags & JOB_IGNERR) ? " (ignored)" : ""); | |
1036 | if (job->flags & JOB_IGNERR) { | 1036 | if (job->flags & JOB_IGNERR) { | |
1037 | status = 0; | 1037 | status = 0; | |
1038 | } else { | 1038 | } else { | |
1039 | if (deleteOnError) { | 1039 | if (deleteOnError) { | |
1040 | JobDeleteTarget(job->node); | 1040 | JobDeleteTarget(job->node); | |
1041 | } | 1041 | } | |
1042 | PrintOnError(job->node, NULL); | 1042 | PrintOnError(job->node, NULL); | |
1043 | } | 1043 | } | |
1044 | } else if (DEBUG(JOB)) { | 1044 | } else if (DEBUG(JOB)) { | |
1045 | if (job->node != lastNode) { | 1045 | if (job->node != lastNode) { | |
1046 | MESSAGE(stdout, job->node); | 1046 | MESSAGE(stdout, job->node); | |
1047 | lastNode = job->node; | 1047 | lastNode = job->node; | |
1048 | } | 1048 | } | |
1049 | (void)printf("*** [%s] Completed successfully\n", | 1049 | (void)printf("*** [%s] Completed successfully\n", | |
1050 | job->node->name); | 1050 | job->node->name); | |
1051 | } | 1051 | } | |
1052 | } else { | 1052 | } else { | |
1053 | if (job->node != lastNode) { | 1053 | if (job->node != lastNode) { | |
1054 | MESSAGE(stdout, job->node); | 1054 | MESSAGE(stdout, job->node); | |
1055 | lastNode = job->node; | 1055 | lastNode = job->node; | |
1056 | } | 1056 | } | |
1057 | (void)printf("*** [%s] Signal %d\n", | 1057 | (void)printf("*** [%s] Signal %d\n", | |
1058 | job->node->name, WTERMSIG(status)); | 1058 | job->node->name, WTERMSIG(status)); | |
1059 | if (deleteOnError) { | 1059 | if (deleteOnError) { | |
1060 | JobDeleteTarget(job->node); | 1060 | JobDeleteTarget(job->node); | |
1061 | } | 1061 | } | |
1062 | } | 1062 | } | |
1063 | (void)fflush(stdout); | 1063 | (void)fflush(stdout); | |
1064 | } | 1064 | } | |
1065 | 1065 | |||
1066 | #ifdef USE_META | 1066 | #ifdef USE_META | |
1067 | if (useMeta) { | 1067 | if (useMeta) { | |
1068 | int x; | 1068 | int x; | |
1069 | 1069 | |||
1070 | if ((x = meta_job_finish(job)) != 0 && status == 0) { | 1070 | if ((x = meta_job_finish(job)) != 0 && status == 0) { | |
1071 | status = x; | 1071 | status = x; | |
1072 | } | 1072 | } | |
1073 | } | 1073 | } | |
1074 | #endif | 1074 | #endif | |
1075 | 1075 | |||
1076 | return_job_token = FALSE; | 1076 | return_job_token = FALSE; | |
1077 | 1077 | |||
1078 | Trace_Log(JOBEND, job); | 1078 | Trace_Log(JOBEND, job); | |
1079 | if (!(job->flags & JOB_SPECIAL)) { | 1079 | if (!(job->flags & JOB_SPECIAL)) { | |
1080 | if ((status != 0) || | 1080 | if ((status != 0) || | |
1081 | (aborting == ABORT_ERROR) || | 1081 | (aborting == ABORT_ERROR) || | |
1082 | (aborting == ABORT_INTERRUPT)) | 1082 | (aborting == ABORT_INTERRUPT)) | |
1083 | return_job_token = TRUE; | 1083 | return_job_token = TRUE; | |
1084 | } | 1084 | } | |
1085 | 1085 | |||
1086 | if ((aborting != ABORT_ERROR) && (aborting != ABORT_INTERRUPT) && (status == 0)) { | 1086 | if ((aborting != ABORT_ERROR) && (aborting != ABORT_INTERRUPT) && (status == 0)) { | |
1087 | /* | 1087 | /* | |
1088 | * As long as we aren't aborting and the job didn't return a non-zero | 1088 | * As long as we aren't aborting and the job didn't return a non-zero | |
1089 | * status that we shouldn't ignore, we call Make_Update to update | 1089 | * status that we shouldn't ignore, we call Make_Update to update | |
1090 | * the parents. | 1090 | * the parents. | |
1091 | */ | 1091 | */ | |
1092 | JobSaveCommands(job); | 1092 | JobSaveCommands(job); | |
1093 | job->node->made = MADE; | 1093 | job->node->made = MADE; | |
1094 | if (!(job->flags & JOB_SPECIAL)) | 1094 | if (!(job->flags & JOB_SPECIAL)) | |
1095 | return_job_token = TRUE; | 1095 | return_job_token = TRUE; | |
1096 | Make_Update(job->node); | 1096 | Make_Update(job->node); | |
1097 | job->job_state = JOB_ST_FREE; | 1097 | job->job_state = JOB_ST_FREE; | |
1098 | } else if (status != 0) { | 1098 | } else if (status != 0) { | |
1099 | errors++; | 1099 | errors++; | |
1100 | job->job_state = JOB_ST_FREE; | 1100 | job->job_state = JOB_ST_FREE; | |
1101 | } | 1101 | } | |
1102 | 1102 | |||
1103 | /* | 1103 | /* | |
1104 | * Set aborting if any error. | 1104 | * Set aborting if any error. | |
1105 | */ | 1105 | */ | |
1106 | if (errors && !opts.keepgoing && (aborting != ABORT_INTERRUPT)) { | 1106 | if (errors && !opts.keepgoing && (aborting != ABORT_INTERRUPT)) { | |
1107 | /* | 1107 | /* | |
1108 | * If we found any errors in this batch of children and the -k flag | 1108 | * If we found any errors in this batch of children and the -k flag | |
1109 | * wasn't given, we set the aborting flag so no more jobs get | 1109 | * wasn't given, we set the aborting flag so no more jobs get | |
1110 | * started. | 1110 | * started. | |
1111 | */ | 1111 | */ | |
1112 | aborting = ABORT_ERROR; | 1112 | aborting = ABORT_ERROR; | |
1113 | } | 1113 | } | |
1114 | 1114 | |||
1115 | if (return_job_token) | 1115 | if (return_job_token) | |
1116 | Job_TokenReturn(); | 1116 | Job_TokenReturn(); | |
1117 | 1117 | |||
1118 | if (aborting == ABORT_ERROR && jobTokensRunning == 0) { | 1118 | if (aborting == ABORT_ERROR && jobTokensRunning == 0) { | |
1119 | /* | 1119 | /* | |
1120 | * If we are aborting and the job table is now empty, we finish. | 1120 | * If we are aborting and the job table is now empty, we finish. | |
1121 | */ | 1121 | */ | |
1122 | Finish(errors); | 1122 | Finish(errors); | |
1123 | } | 1123 | } | |
1124 | } | 1124 | } | |
1125 | 1125 | |||
1126 | /* Touch the given target. Called by JobStart when the -t flag was given. | 1126 | /* Touch the given target. Called by JobStart when the -t flag was given. | |
1127 | * | 1127 | * | |
1128 | * The modification date of the file is changed. | 1128 | * The modification date of the file is changed. | |
1129 | * If the file did not exist, it is created. */ | 1129 | * If the file did not exist, it is created. */ | |
1130 | void | 1130 | void | |
1131 | Job_Touch(GNode *gn, Boolean silent) | 1131 | Job_Touch(GNode *gn, Boolean silent) | |
1132 | { | 1132 | { | |
1133 | int streamID; /* ID of stream opened to do the touch */ | 1133 | int streamID; /* ID of stream opened to do the touch */ | |
1134 | struct utimbuf times; /* Times for utime() call */ | 1134 | struct utimbuf times; /* Times for utime() call */ | |
1135 | 1135 | |||
1136 | if (gn->type & (OP_JOIN|OP_USE|OP_USEBEFORE|OP_EXEC|OP_OPTIONAL| | 1136 | if (gn->type & (OP_JOIN|OP_USE|OP_USEBEFORE|OP_EXEC|OP_OPTIONAL| | |
1137 | OP_SPECIAL|OP_PHONY)) { | 1137 | OP_SPECIAL|OP_PHONY)) { | |
1138 | /* | 1138 | /* | |
1139 | * .JOIN, .USE, .ZEROTIME and .OPTIONAL targets are "virtual" targets | 1139 | * .JOIN, .USE, .ZEROTIME and .OPTIONAL targets are "virtual" targets | |
1140 | * and, as such, shouldn't really be created. | 1140 | * and, as such, shouldn't really be created. | |
1141 | */ | 1141 | */ | |
1142 | return; | 1142 | return; | |
1143 | } | 1143 | } | |
1144 | 1144 | |||
1145 | if (!silent || NoExecute(gn)) { | 1145 | if (!silent || !GNode_ShouldExecute(gn)) { | |
1146 | (void)fprintf(stdout, "touch %s\n", gn->name); | 1146 | (void)fprintf(stdout, "touch %s\n", gn->name); | |
1147 | (void)fflush(stdout); | 1147 | (void)fflush(stdout); | |
1148 | } | 1148 | } | |
1149 | 1149 | |||
1150 | if (NoExecute(gn)) { | 1150 | if (!GNode_ShouldExecute(gn)) { | |
1151 | return; | 1151 | return; | |
1152 | } | 1152 | } | |
1153 | 1153 | |||
1154 | if (gn->type & OP_ARCHV) { | 1154 | if (gn->type & OP_ARCHV) { | |
1155 | Arch_Touch(gn); | 1155 | Arch_Touch(gn); | |
1156 | } else if (gn->type & OP_LIB) { | 1156 | } else if (gn->type & OP_LIB) { | |
1157 | Arch_TouchLib(gn); | 1157 | Arch_TouchLib(gn); | |
1158 | } else { | 1158 | } else { | |
1159 | const char *file = GNode_Path(gn); | 1159 | const char *file = GNode_Path(gn); | |
1160 | 1160 | |||
1161 | times.actime = times.modtime = now; | 1161 | times.actime = times.modtime = now; | |
1162 | if (utime(file, ×) < 0){ | 1162 | if (utime(file, ×) < 0){ | |
1163 | streamID = open(file, O_RDWR | O_CREAT, 0666); | 1163 | streamID = open(file, O_RDWR | O_CREAT, 0666); | |
1164 | 1164 | |||
1165 | if (streamID >= 0) { | 1165 | if (streamID >= 0) { | |
1166 | char c; | 1166 | char c; | |
1167 | 1167 | |||
1168 | /* | 1168 | /* | |
1169 | * Read and write a byte to the file to change the | 1169 | * Read and write a byte to the file to change the | |
1170 | * modification time, then close the file. | 1170 | * modification time, then close the file. | |
1171 | */ | 1171 | */ | |
1172 | if (read(streamID, &c, 1) == 1) { | 1172 | if (read(streamID, &c, 1) == 1) { | |
1173 | (void)lseek(streamID, (off_t)0, SEEK_SET); | 1173 | (void)lseek(streamID, (off_t)0, SEEK_SET); | |
1174 | while (write(streamID, &c, 1) == -1 && errno == EAGAIN) | 1174 | while (write(streamID, &c, 1) == -1 && errno == EAGAIN) | |
1175 | continue; | 1175 | continue; | |
1176 | } | 1176 | } | |
1177 | 1177 | |||
1178 | (void)close(streamID); | 1178 | (void)close(streamID); | |
1179 | } else { | 1179 | } else { | |
1180 | (void)fprintf(stdout, "*** couldn't touch %s: %s", | 1180 | (void)fprintf(stdout, "*** couldn't touch %s: %s", | |
1181 | file, strerror(errno)); | 1181 | file, strerror(errno)); | |
1182 | (void)fflush(stdout); | 1182 | (void)fflush(stdout); | |
1183 | } | 1183 | } | |
1184 | } | 1184 | } | |
1185 | } | 1185 | } | |
1186 | } | 1186 | } | |
1187 | 1187 | |||
1188 | /* Make sure the given node has all the commands it needs. | 1188 | /* Make sure the given node has all the commands it needs. | |
1189 | * | 1189 | * | |
1190 | * The node will have commands from the .DEFAULT rule added to it if it | 1190 | * The node will have commands from the .DEFAULT rule added to it if it | |
1191 | * needs them. | 1191 | * needs them. | |
1192 | * | 1192 | * | |
1193 | * Input: | 1193 | * Input: | |
1194 | * gn The target whose commands need verifying | 1194 | * gn The target whose commands need verifying | |
1195 | * abortProc Function to abort with message | 1195 | * abortProc Function to abort with message | |
1196 | * | 1196 | * | |
1197 | * Results: | 1197 | * Results: | |
1198 | * TRUE if the commands list is/was ok. | 1198 | * TRUE if the commands list is/was ok. | |
1199 | */ | 1199 | */ | |
1200 | Boolean | 1200 | Boolean | |
1201 | Job_CheckCommands(GNode *gn, void (*abortProc)(const char *, ...)) | 1201 | Job_CheckCommands(GNode *gn, void (*abortProc)(const char *, ...)) | |
1202 | { | 1202 | { | |
1203 | if (GNode_IsTarget(gn)) | 1203 | if (GNode_IsTarget(gn)) | |
1204 | return TRUE; | 1204 | return TRUE; | |
1205 | if (!Lst_IsEmpty(gn->commands)) | 1205 | if (!Lst_IsEmpty(gn->commands)) | |
1206 | return TRUE; | 1206 | return TRUE; | |
1207 | if ((gn->type & OP_LIB) && !Lst_IsEmpty(gn->children)) | 1207 | if ((gn->type & OP_LIB) && !Lst_IsEmpty(gn->children)) | |
1208 | return TRUE; | 1208 | return TRUE; | |
1209 | 1209 | |||
1210 | /* | 1210 | /* | |
1211 | * No commands. Look for .DEFAULT rule from which we might infer | 1211 | * No commands. Look for .DEFAULT rule from which we might infer | |
1212 | * commands | 1212 | * commands | |
1213 | */ | 1213 | */ | |
1214 | if ((DEFAULT != NULL) && !Lst_IsEmpty(DEFAULT->commands) && | 1214 | if ((DEFAULT != NULL) && !Lst_IsEmpty(DEFAULT->commands) && | |
1215 | (gn->type & OP_SPECIAL) == 0) { | 1215 | (gn->type & OP_SPECIAL) == 0) { | |
1216 | /* | 1216 | /* | |
1217 | * Make only looks for a .DEFAULT if the node was never the | 1217 | * Make only looks for a .DEFAULT if the node was never the | |
1218 | * target of an operator, so that's what we do too. If | 1218 | * target of an operator, so that's what we do too. If | |
1219 | * a .DEFAULT was given, we substitute its commands for gn's | 1219 | * a .DEFAULT was given, we substitute its commands for gn's | |
1220 | * commands and set the IMPSRC variable to be the target's name | 1220 | * commands and set the IMPSRC variable to be the target's name | |
1221 | * The DEFAULT node acts like a transformation rule, in that | 1221 | * The DEFAULT node acts like a transformation rule, in that | |
1222 | * gn also inherits any attributes or sources attached to | 1222 | * gn also inherits any attributes or sources attached to | |
1223 | * .DEFAULT itself. | 1223 | * .DEFAULT itself. | |
1224 | */ | 1224 | */ | |
1225 | Make_HandleUse(DEFAULT, gn); | 1225 | Make_HandleUse(DEFAULT, gn); | |
1226 | Var_Set(IMPSRC, GNode_VarTarget(gn), gn); | 1226 | Var_Set(IMPSRC, GNode_VarTarget(gn), gn); | |
1227 | return TRUE; | 1227 | return TRUE; | |
1228 | } | 1228 | } | |
1229 | 1229 | |||
1230 | if (Dir_MTime(gn, 0) != 0 || (gn->type & OP_SPECIAL)) | 1230 | if (Dir_MTime(gn, 0) != 0 || (gn->type & OP_SPECIAL)) | |
1231 | return TRUE; | 1231 | return TRUE; | |
1232 | 1232 | |||
1233 | /* | 1233 | /* | |
1234 | * The node wasn't the target of an operator. We have no .DEFAULT | 1234 | * The node wasn't the target of an operator. We have no .DEFAULT | |
1235 | * rule to go on and the target doesn't already exist. There's | 1235 | * rule to go on and the target doesn't already exist. There's | |
1236 | * nothing more we can do for this branch. If the -k flag wasn't | 1236 | * nothing more we can do for this branch. If the -k flag wasn't | |
1237 | * given, we stop in our tracks, otherwise we just don't update | 1237 | * given, we stop in our tracks, otherwise we just don't update | |
1238 | * this node's parents so they never get examined. | 1238 | * this node's parents so they never get examined. | |
1239 | */ | 1239 | */ | |
1240 | 1240 | |||
1241 | if (gn->flags & FROM_DEPEND) { | 1241 | if (gn->flags & FROM_DEPEND) { | |
1242 | if (!Job_RunTarget(".STALE", gn->fname)) | 1242 | if (!Job_RunTarget(".STALE", gn->fname)) | |
1243 | fprintf(stdout, "%s: %s, %d: ignoring stale %s for %s\n", | 1243 | fprintf(stdout, "%s: %s, %d: ignoring stale %s for %s\n", | |
1244 | progname, gn->fname, gn->lineno, makeDependfile, | 1244 | progname, gn->fname, gn->lineno, makeDependfile, | |
1245 | gn->name); | 1245 | gn->name); | |
1246 | return TRUE; | 1246 | return TRUE; | |
1247 | } | 1247 | } | |
1248 | 1248 | |||
1249 | if (gn->type & OP_OPTIONAL) { | 1249 | if (gn->type & OP_OPTIONAL) { | |
1250 | (void)fprintf(stdout, "%s: don't know how to make %s (%s)\n", | 1250 | (void)fprintf(stdout, "%s: don't know how to make %s (%s)\n", | |
1251 | progname, gn->name, "ignored"); | 1251 | progname, gn->name, "ignored"); | |
1252 | (void)fflush(stdout); | 1252 | (void)fflush(stdout); | |
1253 | return TRUE; | 1253 | return TRUE; | |
1254 | } | 1254 | } | |
1255 | 1255 | |||
1256 | if (opts.keepgoing) { | 1256 | if (opts.keepgoing) { | |
1257 | (void)fprintf(stdout, "%s: don't know how to make %s (%s)\n", | 1257 | (void)fprintf(stdout, "%s: don't know how to make %s (%s)\n", | |
1258 | progname, gn->name, "continuing"); | 1258 | progname, gn->name, "continuing"); | |
1259 | (void)fflush(stdout); | 1259 | (void)fflush(stdout); | |
1260 | return FALSE; | 1260 | return FALSE; | |
1261 | } | 1261 | } | |
1262 | 1262 | |||
1263 | abortProc("%s: don't know how to make %s. Stop", progname, gn->name); | 1263 | abortProc("%s: don't know how to make %s. Stop", progname, gn->name); | |
1264 | return FALSE; | 1264 | return FALSE; | |
1265 | } | 1265 | } | |
1266 | 1266 | |||
1267 | /* Execute the shell for the given job. | 1267 | /* Execute the shell for the given job. | |
1268 | * | 1268 | * | |
1269 | * A shell is executed, its output is altered and the Job structure added | 1269 | * A shell is executed, its output is altered and the Job structure added | |
1270 | * to the job table. | 1270 | * to the job table. | |
1271 | */ | 1271 | */ | |
1272 | static void | 1272 | static void | |
1273 | JobExec(Job *job, char **argv) | 1273 | JobExec(Job *job, char **argv) | |
1274 | { | 1274 | { | |
1275 | int cpid; /* ID of new child */ | 1275 | int cpid; /* ID of new child */ | |
1276 | sigset_t mask; | 1276 | sigset_t mask; | |
1277 | 1277 | |||
1278 | job->flags &= ~JOB_TRACED; | 1278 | job->flags &= ~JOB_TRACED; | |
1279 | 1279 | |||
1280 | if (DEBUG(JOB)) { | 1280 | if (DEBUG(JOB)) { | |
1281 | int i; | 1281 | int i; | |
1282 | 1282 | |||
1283 | debug_printf("Running %s %sly\n", job->node->name, "local"); | 1283 | debug_printf("Running %s %sly\n", job->node->name, "local"); | |
1284 | debug_printf("\tCommand: "); | 1284 | debug_printf("\tCommand: "); | |
1285 | for (i = 0; argv[i] != NULL; i++) { | 1285 | for (i = 0; argv[i] != NULL; i++) { | |
1286 | debug_printf("%s ", argv[i]); | 1286 | debug_printf("%s ", argv[i]); | |
1287 | } | 1287 | } | |
1288 | debug_printf("\n"); | 1288 | debug_printf("\n"); | |
1289 | } | 1289 | } | |
1290 | 1290 | |||
1291 | /* | 1291 | /* | |
1292 | * Some jobs produce no output and it's disconcerting to have | 1292 | * Some jobs produce no output and it's disconcerting to have | |
1293 | * no feedback of their running (since they produce no output, the | 1293 | * no feedback of their running (since they produce no output, the | |
1294 | * banner with their name in it never appears). This is an attempt to | 1294 | * banner with their name in it never appears). This is an attempt to | |
1295 | * provide that feedback, even if nothing follows it. | 1295 | * provide that feedback, even if nothing follows it. | |
1296 | */ | 1296 | */ | |
1297 | if ((lastNode != job->node) && !(job->flags & JOB_SILENT)) { | 1297 | if ((lastNode != job->node) && !(job->flags & JOB_SILENT)) { | |
1298 | MESSAGE(stdout, job->node); | 1298 | MESSAGE(stdout, job->node); | |
1299 | lastNode = job->node; | 1299 | lastNode = job->node; | |
1300 | } | 1300 | } | |
1301 | 1301 | |||
1302 | /* No interruptions until this job is on the `jobs' list */ | 1302 | /* No interruptions until this job is on the `jobs' list */ | |
1303 | JobSigLock(&mask); | 1303 | JobSigLock(&mask); | |
1304 | 1304 | |||
1305 | /* Pre-emptively mark job running, pid still zero though */ | 1305 | /* Pre-emptively mark job running, pid still zero though */ | |
1306 | job->job_state = JOB_ST_RUNNING; | 1306 | job->job_state = JOB_ST_RUNNING; | |
1307 | 1307 | |||
1308 | cpid = vFork(); | 1308 | cpid = vFork(); | |
1309 | if (cpid == -1) | 1309 | if (cpid == -1) | |
1310 | Punt("Cannot vfork: %s", strerror(errno)); | 1310 | Punt("Cannot vfork: %s", strerror(errno)); | |
1311 | 1311 | |||
1312 | if (cpid == 0) { | 1312 | if (cpid == 0) { | |
1313 | /* Child */ | 1313 | /* Child */ | |
1314 | sigset_t tmask; | 1314 | sigset_t tmask; | |
1315 | 1315 | |||
1316 | #ifdef USE_META | 1316 | #ifdef USE_META | |
1317 | if (useMeta) { | 1317 | if (useMeta) { | |
1318 | meta_job_child(job); | 1318 | meta_job_child(job); | |
1319 | } | 1319 | } | |
1320 | #endif | 1320 | #endif | |
1321 | /* | 1321 | /* | |
1322 | * Reset all signal handlers; this is necessary because we also | 1322 | * Reset all signal handlers; this is necessary because we also | |
1323 | * need to unblock signals before we exec(2). | 1323 | * need to unblock signals before we exec(2). | |
1324 | */ | 1324 | */ | |
1325 | JobSigReset(); | 1325 | JobSigReset(); | |
1326 | 1326 | |||
1327 | /* Now unblock signals */ | 1327 | /* Now unblock signals */ | |
1328 | sigemptyset(&tmask); | 1328 | sigemptyset(&tmask); | |
1329 | JobSigUnlock(&tmask); | 1329 | JobSigUnlock(&tmask); | |
1330 | 1330 | |||
1331 | /* | 1331 | /* | |
1332 | * Must duplicate the input stream down to the child's input and | 1332 | * Must duplicate the input stream down to the child's input and | |
1333 | * reset it to the beginning (again). Since the stream was marked | 1333 | * reset it to the beginning (again). Since the stream was marked | |
1334 | * close-on-exec, we must clear that bit in the new input. | 1334 | * close-on-exec, we must clear that bit in the new input. | |
1335 | */ | 1335 | */ | |
1336 | if (dup2(fileno(job->cmdFILE), 0) == -1) | 1336 | if (dup2(fileno(job->cmdFILE), 0) == -1) | |
1337 | execDie("dup2", "job->cmdFILE"); | 1337 | execDie("dup2", "job->cmdFILE"); | |
1338 | if (fcntl(0, F_SETFD, 0) == -1) | 1338 | if (fcntl(0, F_SETFD, 0) == -1) | |
1339 | execDie("fcntl clear close-on-exec", "stdin"); | 1339 | execDie("fcntl clear close-on-exec", "stdin"); | |
1340 | if (lseek(0, (off_t)0, SEEK_SET) == -1) | 1340 | if (lseek(0, (off_t)0, SEEK_SET) == -1) | |
1341 | execDie("lseek to 0", "stdin"); | 1341 | execDie("lseek to 0", "stdin"); | |
1342 | 1342 | |||
1343 | if (job->node->type & (OP_MAKE | OP_SUBMAKE)) { | 1343 | if (job->node->type & (OP_MAKE | OP_SUBMAKE)) { | |
1344 | /* | 1344 | /* | |
1345 | * Pass job token pipe to submakes. | 1345 | * Pass job token pipe to submakes. | |
1346 | */ | 1346 | */ | |
1347 | if (fcntl(tokenWaitJob.inPipe, F_SETFD, 0) == -1) | 1347 | if (fcntl(tokenWaitJob.inPipe, F_SETFD, 0) == -1) | |
1348 | execDie("clear close-on-exec", "tokenWaitJob.inPipe"); | 1348 | execDie("clear close-on-exec", "tokenWaitJob.inPipe"); | |
1349 | if (fcntl(tokenWaitJob.outPipe, F_SETFD, 0) == -1) | 1349 | if (fcntl(tokenWaitJob.outPipe, F_SETFD, 0) == -1) | |
1350 | execDie("clear close-on-exec", "tokenWaitJob.outPipe"); | 1350 | execDie("clear close-on-exec", "tokenWaitJob.outPipe"); | |
1351 | } | 1351 | } | |
1352 | 1352 | |||
1353 | /* | 1353 | /* | |
1354 | * Set up the child's output to be routed through the pipe | 1354 | * Set up the child's output to be routed through the pipe | |
1355 | * we've created for it. | 1355 | * we've created for it. | |
1356 | */ | 1356 | */ | |
1357 | if (dup2(job->outPipe, 1) == -1) | 1357 | if (dup2(job->outPipe, 1) == -1) | |
1358 | execDie("dup2", "job->outPipe"); | 1358 | execDie("dup2", "job->outPipe"); | |
1359 | 1359 | |||
1360 | /* | 1360 | /* | |
1361 | * The output channels are marked close on exec. This bit was | 1361 | * The output channels are marked close on exec. This bit was | |
1362 | * duplicated by the dup2(on some systems), so we have to clear | 1362 | * duplicated by the dup2(on some systems), so we have to clear | |
1363 | * it before routing the shell's error output to the same place as | 1363 | * it before routing the shell's error output to the same place as | |
1364 | * its standard output. | 1364 | * its standard output. | |
1365 | */ | 1365 | */ | |
1366 | if (fcntl(1, F_SETFD, 0) == -1) | 1366 | if (fcntl(1, F_SETFD, 0) == -1) | |
1367 | execDie("clear close-on-exec", "stdout"); | 1367 | execDie("clear close-on-exec", "stdout"); | |
1368 | if (dup2(1, 2) == -1) | 1368 | if (dup2(1, 2) == -1) | |
1369 | execDie("dup2", "1, 2"); | 1369 | execDie("dup2", "1, 2"); | |
1370 | 1370 | |||
1371 | /* | 1371 | /* | |
1372 | * We want to switch the child into a different process family so | 1372 | * We want to switch the child into a different process family so | |
1373 | * we can kill it and all its descendants in one fell swoop, | 1373 | * we can kill it and all its descendants in one fell swoop, | |
1374 | * by killing its process family, but not commit suicide. | 1374 | * by killing its process family, but not commit suicide. | |
1375 | */ | 1375 | */ | |
1376 | #if defined(MAKE_NATIVE) || defined(HAVE_SETPGID) | 1376 | #if defined(MAKE_NATIVE) || defined(HAVE_SETPGID) | |
1377 | #if defined(SYSV) | 1377 | #if defined(SYSV) | |
1378 | /* XXX: dsl - I'm sure this should be setpgrp()... */ | 1378 | /* XXX: dsl - I'm sure this should be setpgrp()... */ | |
1379 | (void)setsid(); | 1379 | (void)setsid(); | |
1380 | #else | 1380 | #else | |
1381 | (void)setpgid(0, getpid()); | 1381 | (void)setpgid(0, getpid()); | |
1382 | #endif | 1382 | #endif | |
1383 | #endif | 1383 | #endif | |
1384 | 1384 | |||
1385 | Var_ExportVars(); | 1385 | Var_ExportVars(); | |
1386 | 1386 | |||
1387 | (void)execv(shellPath, argv); | 1387 | (void)execv(shellPath, argv); | |
1388 | execDie("exec", shellPath); | 1388 | execDie("exec", shellPath); | |
1389 | } | 1389 | } | |
1390 | 1390 | |||
1391 | /* Parent, continuing after the child exec */ | 1391 | /* Parent, continuing after the child exec */ | |
1392 | job->pid = cpid; | 1392 | job->pid = cpid; | |
1393 | 1393 | |||
1394 | Trace_Log(JOBSTART, job); | 1394 | Trace_Log(JOBSTART, job); | |
1395 | 1395 | |||
1396 | #ifdef USE_META | 1396 | #ifdef USE_META | |
1397 | if (useMeta) { | 1397 | if (useMeta) { | |
1398 | meta_job_parent(job, cpid); | 1398 | meta_job_parent(job, cpid); | |
1399 | } | 1399 | } | |
1400 | #endif | 1400 | #endif | |
1401 | 1401 | |||
1402 | /* | 1402 | /* | |
1403 | * Set the current position in the buffer to the beginning | 1403 | * Set the current position in the buffer to the beginning | |
1404 | * and mark another stream to watch in the outputs mask | 1404 | * and mark another stream to watch in the outputs mask | |
1405 | */ | 1405 | */ | |
1406 | job->curPos = 0; | 1406 | job->curPos = 0; | |
1407 | 1407 | |||
1408 | watchfd(job); | 1408 | watchfd(job); | |
1409 | 1409 | |||
1410 | if (job->cmdFILE != NULL && job->cmdFILE != stdout) { | 1410 | if (job->cmdFILE != NULL && job->cmdFILE != stdout) { | |
1411 | (void)fclose(job->cmdFILE); | 1411 | (void)fclose(job->cmdFILE); | |
1412 | job->cmdFILE = NULL; | 1412 | job->cmdFILE = NULL; | |
1413 | } | 1413 | } | |
1414 | 1414 | |||
1415 | /* | 1415 | /* | |
1416 | * Now the job is actually running, add it to the table. | 1416 | * Now the job is actually running, add it to the table. | |
1417 | */ | 1417 | */ | |
1418 | if (DEBUG(JOB)) { | 1418 | if (DEBUG(JOB)) { | |
1419 | debug_printf("JobExec(%s): pid %d added to jobs table\n", | 1419 | debug_printf("JobExec(%s): pid %d added to jobs table\n", | |
1420 | job->node->name, job->pid); | 1420 | job->node->name, job->pid); | |
1421 | job_table_dump("job started"); | 1421 | job_table_dump("job started"); | |
1422 | } | 1422 | } | |
1423 | JobSigUnlock(&mask); | 1423 | JobSigUnlock(&mask); | |
1424 | } | 1424 | } | |
1425 | 1425 | |||
1426 | /* Create the argv needed to execute the shell for a given job. */ | 1426 | /* Create the argv needed to execute the shell for a given job. */ | |
1427 | static void | 1427 | static void | |
1428 | JobMakeArgv(Job *job, char **argv) | 1428 | JobMakeArgv(Job *job, char **argv) | |
1429 | { | 1429 | { | |
1430 | int argc; | 1430 | int argc; | |
1431 | static char args[10]; /* For merged arguments */ | 1431 | static char args[10]; /* For merged arguments */ | |
1432 | 1432 | |||
1433 | argv[0] = UNCONST(shellName); | 1433 | argv[0] = UNCONST(shellName); | |
1434 | argc = 1; | 1434 | argc = 1; | |
1435 | 1435 | |||
1436 | if ((commandShell->exit && commandShell->exit[0] != '-') || | 1436 | if ((commandShell->exit && commandShell->exit[0] != '-') || | |
1437 | (commandShell->echo && commandShell->echo[0] != '-')) | 1437 | (commandShell->echo && commandShell->echo[0] != '-')) | |
1438 | { | 1438 | { | |
1439 | /* | 1439 | /* | |
1440 | * At least one of the flags doesn't have a minus before it, so | 1440 | * At least one of the flags doesn't have a minus before it, so | |
1441 | * merge them together. Have to do this because the *(&(@*#*&#$# | 1441 | * merge them together. Have to do this because the *(&(@*#*&#$# | |
1442 | * Bourne shell thinks its second argument is a file to source. | 1442 | * Bourne shell thinks its second argument is a file to source. | |
1443 | * Grrrr. Note the ten-character limitation on the combined arguments. | 1443 | * Grrrr. Note the ten-character limitation on the combined arguments. | |
1444 | */ | 1444 | */ | |
1445 | (void)snprintf(args, sizeof(args), "-%s%s", | 1445 | (void)snprintf(args, sizeof(args), "-%s%s", | |
1446 | ((job->flags & JOB_IGNERR) ? "" : | 1446 | ((job->flags & JOB_IGNERR) ? "" : | |
1447 | (commandShell->exit ? commandShell->exit : "")), | 1447 | (commandShell->exit ? commandShell->exit : "")), | |
1448 | ((job->flags & JOB_SILENT) ? "" : | 1448 | ((job->flags & JOB_SILENT) ? "" : | |
1449 | (commandShell->echo ? commandShell->echo : ""))); | 1449 | (commandShell->echo ? commandShell->echo : ""))); | |
1450 | 1450 | |||
1451 | if (args[1]) { | 1451 | if (args[1]) { | |
1452 | argv[argc] = args; | 1452 | argv[argc] = args; | |
1453 | argc++; | 1453 | argc++; | |
1454 | } | 1454 | } | |
1455 | } else { | 1455 | } else { | |
1456 | if (!(job->flags & JOB_IGNERR) && commandShell->exit) { | 1456 | if (!(job->flags & JOB_IGNERR) && commandShell->exit) { | |
1457 | argv[argc] = UNCONST(commandShell->exit); | 1457 | argv[argc] = UNCONST(commandShell->exit); | |
1458 | argc++; | 1458 | argc++; | |
1459 | } | 1459 | } | |
1460 | if (!(job->flags & JOB_SILENT) && commandShell->echo) { | 1460 | if (!(job->flags & JOB_SILENT) && commandShell->echo) { | |
1461 | argv[argc] = UNCONST(commandShell->echo); | 1461 | argv[argc] = UNCONST(commandShell->echo); | |
1462 | argc++; | 1462 | argc++; | |
1463 | } | 1463 | } | |
1464 | } | 1464 | } | |
1465 | argv[argc] = NULL; | 1465 | argv[argc] = NULL; | |
1466 | } | 1466 | } | |
1467 | 1467 | |||
1468 | /*- | 1468 | /*- | |
1469 | *----------------------------------------------------------------------- | 1469 | *----------------------------------------------------------------------- | |
1470 | * JobStart -- | 1470 | * JobStart -- | |
1471 | * Start a target-creation process going for the target described | 1471 | * Start a target-creation process going for the target described | |
1472 | * by the graph node gn. | 1472 | * by the graph node gn. | |
1473 | * | 1473 | * | |
1474 | * Input: | 1474 | * Input: | |
1475 | * gn target to create | 1475 | * gn target to create | |
1476 | * flags flags for the job to override normal ones. | 1476 | * flags flags for the job to override normal ones. | |
1477 | * e.g. JOB_SPECIAL or JOB_IGNDOTS | 1477 | * e.g. JOB_SPECIAL or JOB_IGNDOTS | |
1478 | * previous The previous Job structure for this node, if any. | 1478 | * previous The previous Job structure for this node, if any. | |
1479 | * | 1479 | * | |
1480 | * Results: | 1480 | * Results: | |
1481 | * JOB_ERROR if there was an error in the commands, JOB_FINISHED | 1481 | * JOB_ERROR if there was an error in the commands, JOB_FINISHED | |
1482 | * if there isn't actually anything left to do for the job and | 1482 | * if there isn't actually anything left to do for the job and | |
1483 | * JOB_RUNNING if the job has been started. | 1483 | * JOB_RUNNING if the job has been started. | |
1484 | * | 1484 | * | |
1485 | * Side Effects: | 1485 | * Side Effects: | |
1486 | * A new Job node is created and added to the list of running | 1486 | * A new Job node is created and added to the list of running | |
1487 | * jobs. PMake is forked and a child shell created. | 1487 | * jobs. PMake is forked and a child shell created. | |
1488 | * | 1488 | * | |
1489 | * NB: I'm fairly sure that this code is never called with JOB_SPECIAL set | 1489 | * NB: I'm fairly sure that this code is never called with JOB_SPECIAL set | |
1490 | * JOB_IGNDOTS is never set (dsl) | 1490 | * JOB_IGNDOTS is never set (dsl) | |
1491 | * Also the return value is ignored by everyone. | 1491 | * Also the return value is ignored by everyone. | |
1492 | *----------------------------------------------------------------------- | 1492 | *----------------------------------------------------------------------- | |
1493 | */ | 1493 | */ | |
1494 | static JobStartResult | 1494 | static JobStartResult | |
1495 | JobStart(GNode *gn, int flags) | 1495 | JobStart(GNode *gn, int flags) | |
1496 | { | 1496 | { | |
1497 | Job *job; /* new job descriptor */ | 1497 | Job *job; /* new job descriptor */ | |
1498 | char *argv[10]; /* Argument vector to shell */ | 1498 | char *argv[10]; /* Argument vector to shell */ | |
1499 | Boolean cmdsOK; /* true if the nodes commands were all right */ | 1499 | Boolean cmdsOK; /* true if the nodes commands were all right */ | |
1500 | Boolean noExec; /* Set true if we decide not to run the job */ | 1500 | Boolean noExec; /* Set true if we decide not to run the job */ | |
1501 | int tfd; /* File descriptor to the temp file */ | 1501 | int tfd; /* File descriptor to the temp file */ | |
1502 | 1502 | |||
1503 | for (job = job_table; job < job_table_end; job++) { | 1503 | for (job = job_table; job < job_table_end; job++) { | |
1504 | if (job->job_state == JOB_ST_FREE) | 1504 | if (job->job_state == JOB_ST_FREE) | |
1505 | break; | 1505 | break; | |
1506 | } | 1506 | } | |
1507 | if (job >= job_table_end) | 1507 | if (job >= job_table_end) | |
1508 | Punt("JobStart no job slots vacant"); | 1508 | Punt("JobStart no job slots vacant"); | |
1509 | 1509 | |||
1510 | memset(job, 0, sizeof *job); | 1510 | memset(job, 0, sizeof *job); | |
1511 | job->job_state = JOB_ST_SETUP; | 1511 | job->job_state = JOB_ST_SETUP; | |
1512 | if (gn->type & OP_SPECIAL) | 1512 | if (gn->type & OP_SPECIAL) | |
1513 | flags |= JOB_SPECIAL; | 1513 | flags |= JOB_SPECIAL; | |
1514 | 1514 | |||
1515 | job->node = gn; | 1515 | job->node = gn; | |
1516 | job->tailCmds = NULL; | 1516 | job->tailCmds = NULL; | |
1517 | 1517 | |||
1518 | /* | 1518 | /* | |
1519 | * Set the initial value of the flags for this job based on the global | 1519 | * Set the initial value of the flags for this job based on the global | |
1520 | * ones and the node's attributes... Any flags supplied by the caller | 1520 | * ones and the node's attributes... Any flags supplied by the caller | |
1521 | * are also added to the field. | 1521 | * are also added to the field. | |
1522 | */ | 1522 | */ | |
1523 | job->flags = 0; | 1523 | job->flags = 0; | |
1524 | if (Targ_Ignore(gn)) { | 1524 | if (Targ_Ignore(gn)) { | |
1525 | job->flags |= JOB_IGNERR; | 1525 | job->flags |= JOB_IGNERR; | |
1526 | } | 1526 | } | |
1527 | if (Targ_Silent(gn)) { | 1527 | if (Targ_Silent(gn)) { | |
1528 | job->flags |= JOB_SILENT; | 1528 | job->flags |= JOB_SILENT; | |
1529 | } | 1529 | } | |
1530 | job->flags |= flags; | 1530 | job->flags |= flags; | |
1531 | 1531 | |||
1532 | /* | 1532 | /* | |
1533 | * Check the commands now so any attributes from .DEFAULT have a chance | 1533 | * Check the commands now so any attributes from .DEFAULT have a chance | |
1534 | * to migrate to the node | 1534 | * to migrate to the node | |
1535 | */ | 1535 | */ | |
1536 | cmdsOK = Job_CheckCommands(gn, Error); | 1536 | cmdsOK = Job_CheckCommands(gn, Error); | |
1537 | 1537 | |||
1538 | job->inPollfd = NULL; | 1538 | job->inPollfd = NULL; | |
1539 | /* | 1539 | /* | |
1540 | * If the -n flag wasn't given, we open up OUR (not the child's) | 1540 | * If the -n flag wasn't given, we open up OUR (not the child's) | |
1541 | * temporary file to stuff commands in it. The thing is rd/wr so we don't | 1541 | * temporary file to stuff commands in it. The thing is rd/wr so we don't | |
1542 | * need to reopen it to feed it to the shell. If the -n flag *was* given, | 1542 | * need to reopen it to feed it to the shell. If the -n flag *was* given, | |
1543 | * we just set the file to be stdout. Cute, huh? | 1543 | * we just set the file to be stdout. Cute, huh? | |
1544 | */ | 1544 | */ | |
1545 | if (((gn->type & OP_MAKE) && !opts.noRecursiveExecute) || | 1545 | if (((gn->type & OP_MAKE) && !opts.noRecursiveExecute) || | |
1546 | (!opts.noExecute && !opts.touchFlag)) { | 1546 | (!opts.noExecute && !opts.touchFlag)) { | |
1547 | /* | 1547 | /* | |
1548 | * tfile is the name of a file into which all shell commands are | 1548 | * tfile is the name of a file into which all shell commands are | |
1549 | * put. It is removed before the child shell is executed, unless | 1549 | * put. It is removed before the child shell is executed, unless | |
1550 | * DEBUG(SCRIPT) is set. | 1550 | * DEBUG(SCRIPT) is set. | |
1551 | */ | 1551 | */ | |
1552 | char *tfile; | 1552 | char *tfile; | |
1553 | sigset_t mask; | 1553 | sigset_t mask; | |
1554 | /* | 1554 | /* | |
1555 | * We're serious here, but if the commands were bogus, we're | 1555 | * We're serious here, but if the commands were bogus, we're | |
1556 | * also dead... | 1556 | * also dead... | |
1557 | */ | 1557 | */ | |
1558 | if (!cmdsOK) { | 1558 | if (!cmdsOK) { | |
1559 | PrintOnError(gn, NULL); /* provide some clue */ | 1559 | PrintOnError(gn, NULL); /* provide some clue */ | |
1560 | DieHorribly(); | 1560 | DieHorribly(); | |
1561 | } | 1561 | } | |
1562 | 1562 | |||
1563 | JobSigLock(&mask); | 1563 | JobSigLock(&mask); | |
1564 | tfd = mkTempFile(TMPPAT, &tfile); | 1564 | tfd = mkTempFile(TMPPAT, &tfile); | |
1565 | if (!DEBUG(SCRIPT)) | 1565 | if (!DEBUG(SCRIPT)) | |
1566 | (void)eunlink(tfile); | 1566 | (void)eunlink(tfile); | |
1567 | JobSigUnlock(&mask); | 1567 | JobSigUnlock(&mask); | |
1568 | 1568 | |||
1569 | job->cmdFILE = fdopen(tfd, "w+"); | 1569 | job->cmdFILE = fdopen(tfd, "w+"); | |
1570 | if (job->cmdFILE == NULL) { | 1570 | if (job->cmdFILE == NULL) { | |
1571 | Punt("Could not fdopen %s", tfile); | 1571 | Punt("Could not fdopen %s", tfile); | |
1572 | } | 1572 | } | |
1573 | (void)fcntl(fileno(job->cmdFILE), F_SETFD, FD_CLOEXEC); | 1573 | (void)fcntl(fileno(job->cmdFILE), F_SETFD, FD_CLOEXEC); | |
1574 | /* | 1574 | /* | |
1575 | * Send the commands to the command file, flush all its buffers then | 1575 | * Send the commands to the command file, flush all its buffers then | |
1576 | * rewind and remove the thing. | 1576 | * rewind and remove the thing. | |
1577 | */ | 1577 | */ | |
1578 | noExec = FALSE; | 1578 | noExec = FALSE; | |
1579 | 1579 | |||
1580 | #ifdef USE_META | 1580 | #ifdef USE_META | |
1581 | if (useMeta) { | 1581 | if (useMeta) { | |
1582 | meta_job_start(job, gn); | 1582 | meta_job_start(job, gn); | |
1583 | if (Targ_Silent(gn)) { /* might have changed */ | 1583 | if (Targ_Silent(gn)) { /* might have changed */ | |
1584 | job->flags |= JOB_SILENT; | 1584 | job->flags |= JOB_SILENT; | |
1585 | } | 1585 | } | |
1586 | } | 1586 | } | |
1587 | #endif | 1587 | #endif | |
1588 | /* | 1588 | /* | |
1589 | * We can do all the commands at once. hooray for sanity | 1589 | * We can do all the commands at once. hooray for sanity | |
1590 | */ | 1590 | */ | |
1591 | numCommands = 0; | 1591 | numCommands = 0; | |
1592 | JobPrintCommands(job); | 1592 | JobPrintCommands(job); | |
1593 | 1593 | |||
1594 | /* | 1594 | /* | |
1595 | * If we didn't print out any commands to the shell script, | 1595 | * If we didn't print out any commands to the shell script, | |
1596 | * there's not much point in executing the shell, is there? | 1596 | * there's not much point in executing the shell, is there? | |
1597 | */ | 1597 | */ | |
1598 | if (numCommands == 0) { | 1598 | if (numCommands == 0) { | |
1599 | noExec = TRUE; | 1599 | noExec = TRUE; | |
1600 | } | 1600 | } | |
1601 | 1601 | |||
1602 | free(tfile); | 1602 | free(tfile); | |
1603 | } else if (NoExecute(gn)) { | 1603 | } else if (!GNode_ShouldExecute(gn)) { | |
1604 | /* | 1604 | /* | |
1605 | * Not executing anything -- just print all the commands to stdout | 1605 | * Not executing anything -- just print all the commands to stdout | |
1606 | * in one fell swoop. This will still set up job->tailCmds correctly. | 1606 | * in one fell swoop. This will still set up job->tailCmds correctly. | |
1607 | */ | 1607 | */ | |
1608 | if (lastNode != gn) { | 1608 | if (lastNode != gn) { | |
1609 | MESSAGE(stdout, gn); | 1609 | MESSAGE(stdout, gn); | |
1610 | lastNode = gn; | 1610 | lastNode = gn; | |
1611 | } | 1611 | } | |
1612 | job->cmdFILE = stdout; | 1612 | job->cmdFILE = stdout; | |
1613 | /* | 1613 | /* | |
1614 | * Only print the commands if they're ok, but don't die if they're | 1614 | * Only print the commands if they're ok, but don't die if they're | |
1615 | * not -- just let the user know they're bad and keep going. It | 1615 | * not -- just let the user know they're bad and keep going. It | |
1616 | * doesn't do any harm in this case and may do some good. | 1616 | * doesn't do any harm in this case and may do some good. | |
1617 | */ | 1617 | */ | |
1618 | if (cmdsOK) | 1618 | if (cmdsOK) | |
1619 | JobPrintCommands(job); | 1619 | JobPrintCommands(job); | |
1620 | /* | 1620 | /* | |
1621 | * Don't execute the shell, thank you. | 1621 | * Don't execute the shell, thank you. | |
1622 | */ | 1622 | */ | |
1623 | noExec = TRUE; | 1623 | noExec = TRUE; | |
1624 | } else { | 1624 | } else { | |
1625 | /* | 1625 | /* | |
1626 | * Just touch the target and note that no shell should be executed. | 1626 | * Just touch the target and note that no shell should be executed. | |
1627 | * Set cmdFILE to stdout to make life easier. Check the commands, too, | 1627 | * Set cmdFILE to stdout to make life easier. Check the commands, too, | |
1628 | * but don't die if they're no good -- it does no harm to keep working | 1628 | * but don't die if they're no good -- it does no harm to keep working | |
1629 | * up the graph. | 1629 | * up the graph. | |
1630 | */ | 1630 | */ | |
1631 | job->cmdFILE = stdout; | 1631 | job->cmdFILE = stdout; | |
1632 | Job_Touch(gn, job->flags&JOB_SILENT); | 1632 | Job_Touch(gn, job->flags&JOB_SILENT); | |
1633 | noExec = TRUE; | 1633 | noExec = TRUE; | |
1634 | } | 1634 | } | |
1635 | /* Just in case it isn't already... */ | 1635 | /* Just in case it isn't already... */ | |
1636 | (void)fflush(job->cmdFILE); | 1636 | (void)fflush(job->cmdFILE); | |
1637 | 1637 | |||
1638 | /* | 1638 | /* | |
1639 | * If we're not supposed to execute a shell, don't. | 1639 | * If we're not supposed to execute a shell, don't. | |
1640 | */ | 1640 | */ | |
1641 | if (noExec) { | 1641 | if (noExec) { | |
1642 | if (!(job->flags & JOB_SPECIAL)) | 1642 | if (!(job->flags & JOB_SPECIAL)) | |
1643 | Job_TokenReturn(); | 1643 | Job_TokenReturn(); | |
1644 | /* | 1644 | /* | |
1645 | * Unlink and close the command file if we opened one | 1645 | * Unlink and close the command file if we opened one | |
1646 | */ | 1646 | */ | |
1647 | if (job->cmdFILE != stdout) { | 1647 | if (job->cmdFILE != stdout) { | |
1648 | if (job->cmdFILE != NULL) { | 1648 | if (job->cmdFILE != NULL) { | |
1649 | (void)fclose(job->cmdFILE); | 1649 | (void)fclose(job->cmdFILE); | |
1650 | job->cmdFILE = NULL; | 1650 | job->cmdFILE = NULL; | |
1651 | } | 1651 | } | |
1652 | } | 1652 | } | |
1653 | 1653 | |||
1654 | /* | 1654 | /* | |
1655 | * We only want to work our way up the graph if we aren't here because | 1655 | * We only want to work our way up the graph if we aren't here because | |
1656 | * the commands for the job were no good. | 1656 | * the commands for the job were no good. | |
1657 | */ | 1657 | */ | |
1658 | if (cmdsOK && aborting == ABORT_NONE) { | 1658 | if (cmdsOK && aborting == ABORT_NONE) { | |
1659 | JobSaveCommands(job); | 1659 | JobSaveCommands(job); | |
1660 | job->node->made = MADE; | 1660 | job->node->made = MADE; | |
1661 | Make_Update(job->node); | 1661 | Make_Update(job->node); | |
1662 | } | 1662 | } | |
1663 | job->job_state = JOB_ST_FREE; | 1663 | job->job_state = JOB_ST_FREE; | |
1664 | return cmdsOK ? JOB_FINISHED : JOB_ERROR; | 1664 | return cmdsOK ? JOB_FINISHED : JOB_ERROR; | |
1665 | } | 1665 | } | |
1666 | 1666 | |||
1667 | /* | 1667 | /* | |
1668 | * Set up the control arguments to the shell. This is based on the flags | 1668 | * Set up the control arguments to the shell. This is based on the flags | |
1669 | * set earlier for this job. | 1669 | * set earlier for this job. | |
1670 | */ | 1670 | */ | |
1671 | JobMakeArgv(job, argv); | 1671 | JobMakeArgv(job, argv); | |
1672 | 1672 | |||
1673 | /* Create the pipe by which we'll get the shell's output. */ | 1673 | /* Create the pipe by which we'll get the shell's output. */ | |
1674 | JobCreatePipe(job, 3); | 1674 | JobCreatePipe(job, 3); | |
1675 | 1675 | |||
1676 | JobExec(job, argv); | 1676 | JobExec(job, argv); | |
1677 | return JOB_RUNNING; | 1677 | return JOB_RUNNING; | |
1678 | } | 1678 | } | |
1679 | 1679 | |||
1680 | static char * | 1680 | static char * | |
1681 | JobOutput(Job *job, char *cp, char *endp) | 1681 | JobOutput(Job *job, char *cp, char *endp) | |
1682 | { | 1682 | { | |
1683 | char *ecp; | 1683 | char *ecp; | |
1684 | 1684 | |||
1685 | if (commandShell->noPrint && commandShell->noPrint[0] != '\0') { | 1685 | if (commandShell->noPrint && commandShell->noPrint[0] != '\0') { | |
1686 | while ((ecp = strstr(cp, commandShell->noPrint)) != NULL) { | 1686 | while ((ecp = strstr(cp, commandShell->noPrint)) != NULL) { | |
1687 | if (cp != ecp) { | 1687 | if (cp != ecp) { | |
1688 | *ecp = '\0'; | 1688 | *ecp = '\0'; | |
1689 | /* | 1689 | /* | |
1690 | * The only way there wouldn't be a newline after | 1690 | * The only way there wouldn't be a newline after | |
1691 | * this line is if it were the last in the buffer. | 1691 | * this line is if it were the last in the buffer. | |
1692 | * however, since the non-printable comes after it, | 1692 | * however, since the non-printable comes after it, | |
1693 | * there must be a newline, so we don't print one. | 1693 | * there must be a newline, so we don't print one. | |
1694 | */ | 1694 | */ | |
1695 | (void)fprintf(stdout, "%s", cp); | 1695 | (void)fprintf(stdout, "%s", cp); | |
1696 | (void)fflush(stdout); | 1696 | (void)fflush(stdout); | |
1697 | } | 1697 | } | |
1698 | cp = ecp + commandShell->noPrintLen; | 1698 | cp = ecp + commandShell->noPrintLen; | |
1699 | if (cp != endp) { | 1699 | if (cp != endp) { | |
1700 | /* | 1700 | /* | |
1701 | * Still more to print, look again after skipping | 1701 | * Still more to print, look again after skipping | |
1702 | * the whitespace following the non-printable | 1702 | * the whitespace following the non-printable | |
1703 | * command.... | 1703 | * command.... | |
1704 | */ | 1704 | */ | |
1705 | cp++; | 1705 | cp++; | |
1706 | while (*cp == ' ' || *cp == '\t' || *cp == '\n') { | 1706 | while (*cp == ' ' || *cp == '\t' || *cp == '\n') { | |
1707 | cp++; | 1707 | cp++; | |
1708 | } | 1708 | } | |
1709 | } else { | 1709 | } else { | |
1710 | return cp; | 1710 | return cp; | |
1711 | } | 1711 | } | |
1712 | } | 1712 | } | |
1713 | } | 1713 | } | |
1714 | return cp; | 1714 | return cp; | |
1715 | } | 1715 | } | |
1716 | 1716 | |||
1717 | /*- | 1717 | /*- | |
1718 | *----------------------------------------------------------------------- | 1718 | *----------------------------------------------------------------------- | |
1719 | * JobDoOutput -- | 1719 | * JobDoOutput -- | |
1720 | * This function is called at different times depending on | 1720 | * This function is called at different times depending on | |
1721 | * whether the user has specified that output is to be collected | 1721 | * whether the user has specified that output is to be collected | |
1722 | * via pipes or temporary files. In the former case, we are called | 1722 | * via pipes or temporary files. In the former case, we are called | |
1723 | * whenever there is something to read on the pipe. We collect more | 1723 | * whenever there is something to read on the pipe. We collect more | |
1724 | * output from the given job and store it in the job's outBuf. If | 1724 | * output from the given job and store it in the job's outBuf. If | |
1725 | * this makes up a line, we print it tagged by the job's identifier, | 1725 | * this makes up a line, we print it tagged by the job's identifier, | |
1726 | * as necessary. | 1726 | * as necessary. | |
1727 | * If output has been collected in a temporary file, we open the | 1727 | * If output has been collected in a temporary file, we open the | |
1728 | * file and read it line by line, transferring it to our own | 1728 | * file and read it line by line, transferring it to our own | |
1729 | * output channel until the file is empty. At which point we | 1729 | * output channel until the file is empty. At which point we | |
1730 | * remove the temporary file. | 1730 | * remove the temporary file. | |
1731 | * In both cases, however, we keep our figurative eye out for the | 1731 | * In both cases, however, we keep our figurative eye out for the | |
1732 | * 'noPrint' line for the shell from which the output came. If | 1732 | * 'noPrint' line for the shell from which the output came. If | |
1733 | * we recognize a line, we don't print it. If the command is not | 1733 | * we recognize a line, we don't print it. If the command is not | |
1734 | * alone on the line (the character after it is not \0 or \n), we | 1734 | * alone on the line (the character after it is not \0 or \n), we | |
1735 | * do print whatever follows it. | 1735 | * do print whatever follows it. | |
1736 | * | 1736 | * | |
1737 | * Input: | 1737 | * Input: | |
1738 | * job the job whose output needs printing | 1738 | * job the job whose output needs printing | |
1739 | * finish TRUE if this is the last time we'll be called | 1739 | * finish TRUE if this is the last time we'll be called | |
1740 | * for this job | 1740 | * for this job | |
1741 | * | 1741 | * | |
1742 | * Side Effects: | 1742 | * Side Effects: | |
1743 | * curPos may be shifted as may the contents of outBuf. | 1743 | * curPos may be shifted as may the contents of outBuf. | |
1744 | *----------------------------------------------------------------------- | 1744 | *----------------------------------------------------------------------- | |
1745 | */ | 1745 | */ | |
1746 | static void | 1746 | static void | |
1747 | JobDoOutput(Job *job, Boolean finish) | 1747 | JobDoOutput(Job *job, Boolean finish) | |
1748 | { | 1748 | { | |
1749 | Boolean gotNL = FALSE; /* true if got a newline */ | 1749 | Boolean gotNL = FALSE; /* true if got a newline */ | |
1750 | Boolean fbuf; /* true if our buffer filled up */ | 1750 | Boolean fbuf; /* true if our buffer filled up */ | |
1751 | size_t nr; /* number of bytes read */ | 1751 | size_t nr; /* number of bytes read */ | |
1752 | size_t i; /* auxiliary index into outBuf */ | 1752 | size_t i; /* auxiliary index into outBuf */ | |
1753 | size_t max; /* limit for i (end of current data) */ | 1753 | size_t max; /* limit for i (end of current data) */ | |
1754 | ssize_t nRead; /* (Temporary) number of bytes read */ | 1754 | ssize_t nRead; /* (Temporary) number of bytes read */ | |
1755 | 1755 | |||
1756 | /* | 1756 | /* | |
1757 | * Read as many bytes as will fit in the buffer. | 1757 | * Read as many bytes as will fit in the buffer. | |
1758 | */ | 1758 | */ | |
1759 | end_loop: | 1759 | end_loop: | |
1760 | gotNL = FALSE; | 1760 | gotNL = FALSE; | |
1761 | fbuf = FALSE; | 1761 | fbuf = FALSE; | |
1762 | 1762 | |||
1763 | nRead = read(job->inPipe, &job->outBuf[job->curPos], | 1763 | nRead = read(job->inPipe, &job->outBuf[job->curPos], | |
1764 | JOB_BUFSIZE - job->curPos); | 1764 | JOB_BUFSIZE - job->curPos); | |
1765 | if (nRead < 0) { | 1765 | if (nRead < 0) { | |
1766 | if (errno == EAGAIN) | 1766 | if (errno == EAGAIN) | |
1767 | return; | 1767 | return; | |
1768 | if (DEBUG(JOB)) { | 1768 | if (DEBUG(JOB)) { | |
1769 | perror("JobDoOutput(piperead)"); | 1769 | perror("JobDoOutput(piperead)"); | |
1770 | } | 1770 | } | |
1771 | nr = 0; | 1771 | nr = 0; | |
1772 | } else { | 1772 | } else { | |
1773 | nr = (size_t)nRead; | 1773 | nr = (size_t)nRead; | |
1774 | } | 1774 | } | |
1775 | 1775 | |||
1776 | /* | 1776 | /* | |
1777 | * If we hit the end-of-file (the job is dead), we must flush its | 1777 | * If we hit the end-of-file (the job is dead), we must flush its | |
1778 | * remaining output, so pretend we read a newline if there's any | 1778 | * remaining output, so pretend we read a newline if there's any | |
1779 | * output remaining in the buffer. | 1779 | * output remaining in the buffer. | |
1780 | * Also clear the 'finish' flag so we stop looping. | 1780 | * Also clear the 'finish' flag so we stop looping. | |
1781 | */ | 1781 | */ | |
1782 | if ((nr == 0) && (job->curPos != 0)) { | 1782 | if ((nr == 0) && (job->curPos != 0)) { | |
1783 | job->outBuf[job->curPos] = '\n'; | 1783 | job->outBuf[job->curPos] = '\n'; | |
1784 | nr = 1; | 1784 | nr = 1; | |
1785 | finish = FALSE; | 1785 | finish = FALSE; | |
1786 | } else if (nr == 0) { | 1786 | } else if (nr == 0) { | |
1787 | finish = FALSE; | 1787 | finish = FALSE; | |
1788 | } | 1788 | } | |
1789 | 1789 | |||
1790 | /* | 1790 | /* | |
1791 | * Look for the last newline in the bytes we just got. If there is | 1791 | * Look for the last newline in the bytes we just got. If there is | |
1792 | * one, break out of the loop with 'i' as its index and gotNL set | 1792 | * one, break out of the loop with 'i' as its index and gotNL set | |
1793 | * TRUE. | 1793 | * TRUE. | |
1794 | */ | 1794 | */ | |
1795 | max = job->curPos + nr; | 1795 | max = job->curPos + nr; | |
1796 | for (i = job->curPos + nr - 1; i >= job->curPos && i != (size_t)-1; i--) { | 1796 | for (i = job->curPos + nr - 1; i >= job->curPos && i != (size_t)-1; i--) { | |
1797 | if (job->outBuf[i] == '\n') { | 1797 | if (job->outBuf[i] == '\n') { | |
1798 | gotNL = TRUE; | 1798 | gotNL = TRUE; | |
1799 | break; | 1799 | break; | |
1800 | } else if (job->outBuf[i] == '\0') { | 1800 | } else if (job->outBuf[i] == '\0') { | |
1801 | /* | 1801 | /* | |
1802 | * Why? | 1802 | * Why? | |
1803 | */ | 1803 | */ | |
1804 | job->outBuf[i] = ' '; | 1804 | job->outBuf[i] = ' '; | |
1805 | } | 1805 | } | |
1806 | } | 1806 | } | |
1807 | 1807 | |||
1808 | if (!gotNL) { | 1808 | if (!gotNL) { | |
1809 | job->curPos += nr; | 1809 | job->curPos += nr; | |
1810 | if (job->curPos == JOB_BUFSIZE) { | 1810 | if (job->curPos == JOB_BUFSIZE) { | |
1811 | /* | 1811 | /* | |
1812 | * If we've run out of buffer space, we have no choice | 1812 | * If we've run out of buffer space, we have no choice | |
1813 | * but to print the stuff. sigh. | 1813 | * but to print the stuff. sigh. | |
1814 | */ | 1814 | */ | |
1815 | fbuf = TRUE; | 1815 | fbuf = TRUE; | |
1816 | i = job->curPos; | 1816 | i = job->curPos; | |
1817 | } | 1817 | } | |
1818 | } | 1818 | } | |
1819 | if (gotNL || fbuf) { | 1819 | if (gotNL || fbuf) { | |
1820 | /* | 1820 | /* | |
1821 | * Need to send the output to the screen. Null terminate it | 1821 | * Need to send the output to the screen. Null terminate it | |
1822 | * first, overwriting the newline character if there was one. | 1822 | * first, overwriting the newline character if there was one. | |
1823 | * So long as the line isn't one we should filter (according | 1823 | * So long as the line isn't one we should filter (according | |
1824 | * to the shell description), we print the line, preceded | 1824 | * to the shell description), we print the line, preceded | |
1825 | * by a target banner if this target isn't the same as the | 1825 | * by a target banner if this target isn't the same as the | |
1826 | * one for which we last printed something. | 1826 | * one for which we last printed something. | |
1827 | * The rest of the data in the buffer are then shifted down | 1827 | * The rest of the data in the buffer are then shifted down | |
1828 | * to the start of the buffer and curPos is set accordingly. | 1828 | * to the start of the buffer and curPos is set accordingly. | |
1829 | */ | 1829 | */ | |
1830 | job->outBuf[i] = '\0'; | 1830 | job->outBuf[i] = '\0'; | |
1831 | if (i >= job->curPos) { | 1831 | if (i >= job->curPos) { | |
1832 | char *cp; | 1832 | char *cp; | |
1833 | 1833 | |||
1834 | cp = JobOutput(job, job->outBuf, &job->outBuf[i]); | 1834 | cp = JobOutput(job, job->outBuf, &job->outBuf[i]); | |
1835 | 1835 | |||
1836 | /* | 1836 | /* | |
1837 | * There's still more in that thar buffer. This time, though, | 1837 | * There's still more in that thar buffer. This time, though, | |
1838 | * we know there's no newline at the end, so we add one of | 1838 | * we know there's no newline at the end, so we add one of | |
1839 | * our own free will. | 1839 | * our own free will. | |
1840 | */ | 1840 | */ | |
1841 | if (*cp != '\0') { | 1841 | if (*cp != '\0') { | |
1842 | if (!opts.beSilent && job->node != lastNode) { | 1842 | if (!opts.beSilent && job->node != lastNode) { | |
1843 | MESSAGE(stdout, job->node); | 1843 | MESSAGE(stdout, job->node); | |
1844 | lastNode = job->node; | 1844 | lastNode = job->node; | |
1845 | } | 1845 | } | |
1846 | #ifdef USE_META | 1846 | #ifdef USE_META | |
1847 | if (useMeta) { | 1847 | if (useMeta) { | |
1848 | meta_job_output(job, cp, gotNL ? "\n" : ""); | 1848 | meta_job_output(job, cp, gotNL ? "\n" : ""); | |
1849 | } | 1849 | } | |
1850 | #endif | 1850 | #endif | |
1851 | (void)fprintf(stdout, "%s%s", cp, gotNL ? "\n" : ""); | 1851 | (void)fprintf(stdout, "%s%s", cp, gotNL ? "\n" : ""); | |
1852 | (void)fflush(stdout); | 1852 | (void)fflush(stdout); | |
1853 | } | 1853 | } | |
1854 | } | 1854 | } | |
1855 | /* | 1855 | /* | |
1856 | * max is the last offset still in the buffer. Move any remaining | 1856 | * max is the last offset still in the buffer. Move any remaining | |
1857 | * characters to the start of the buffer and update the end marker | 1857 | * characters to the start of the buffer and update the end marker | |
1858 | * curPos. | 1858 | * curPos. | |
1859 | */ | 1859 | */ | |
1860 | if (i < max) { | 1860 | if (i < max) { | |
1861 | (void)memmove(job->outBuf, &job->outBuf[i + 1], max - (i + 1)); | 1861 | (void)memmove(job->outBuf, &job->outBuf[i + 1], max - (i + 1)); | |
1862 | job->curPos = max - (i + 1); | 1862 | job->curPos = max - (i + 1); | |
1863 | } else { | 1863 | } else { | |
1864 | assert(i == max); | 1864 | assert(i == max); | |
1865 | job->curPos = 0; | 1865 | job->curPos = 0; | |
1866 | } | 1866 | } | |
1867 | } | 1867 | } | |
1868 | if (finish) { | 1868 | if (finish) { | |
1869 | /* | 1869 | /* | |
1870 | * If the finish flag is true, we must loop until we hit | 1870 | * If the finish flag is true, we must loop until we hit | |
1871 | * end-of-file on the pipe. This is guaranteed to happen | 1871 | * end-of-file on the pipe. This is guaranteed to happen | |
1872 | * eventually since the other end of the pipe is now closed | 1872 | * eventually since the other end of the pipe is now closed | |
1873 | * (we closed it explicitly and the child has exited). When | 1873 | * (we closed it explicitly and the child has exited). When | |
1874 | * we do get an EOF, finish will be set FALSE and we'll fall | 1874 | * we do get an EOF, finish will be set FALSE and we'll fall | |
1875 | * through and out. | 1875 | * through and out. | |
1876 | */ | 1876 | */ | |
1877 | goto end_loop; | 1877 | goto end_loop; | |
1878 | } | 1878 | } | |
1879 | } | 1879 | } | |
1880 | 1880 | |||
1881 | static void | 1881 | static void | |
1882 | JobRun(GNode *targ) | 1882 | JobRun(GNode *targ) | |
1883 | { | 1883 | { | |
1884 | #if 0 | 1884 | #if 0 | |
1885 | /* | 1885 | /* | |
1886 | * Unfortunately it is too complicated to run .BEGIN, .END, and | 1886 | * Unfortunately it is too complicated to run .BEGIN, .END, and | |
1887 | * .INTERRUPT job in the parallel job module. As of 2020-09-25, | 1887 | * .INTERRUPT job in the parallel job module. As of 2020-09-25, | |
1888 | * unit-tests/deptgt-end-jobs.mk hangs in an endless loop. | 1888 | * unit-tests/deptgt-end-jobs.mk hangs in an endless loop. | |
1889 | * | 1889 | * | |
1890 | * Running these jobs in compat mode also guarantees that these | 1890 | * Running these jobs in compat mode also guarantees that these | |
1891 | * jobs do not overlap with other unrelated jobs. | 1891 | * jobs do not overlap with other unrelated jobs. | |
1892 | */ | 1892 | */ | |
1893 | List *lst = Lst_New(); | 1893 | List *lst = Lst_New(); | |
1894 | Lst_Append(lst, targ); | 1894 | Lst_Append(lst, targ); | |
1895 | (void)Make_Run(lst); | 1895 | (void)Make_Run(lst); | |
1896 | Lst_Destroy(lst, NULL); | 1896 | Lst_Destroy(lst, NULL); | |
1897 | JobStart(targ, JOB_SPECIAL); | 1897 | JobStart(targ, JOB_SPECIAL); | |
1898 | while (jobTokensRunning) { | 1898 | while (jobTokensRunning) { | |
1899 | Job_CatchOutput(); | 1899 | Job_CatchOutput(); | |
1900 | } | 1900 | } | |
1901 | #else | 1901 | #else | |
1902 | Compat_Make(targ, targ); | 1902 | Compat_Make(targ, targ); | |
1903 | if (targ->made == ERROR) { | 1903 | if (targ->made == ERROR) { | |
1904 | PrintOnError(targ, "\n\nStop."); | 1904 | PrintOnError(targ, "\n\nStop."); | |
1905 | exit(1); | 1905 | exit(1); | |
1906 | } | 1906 | } | |
1907 | #endif | 1907 | #endif | |
1908 | } | 1908 | } | |
1909 | 1909 | |||
1910 | /* Handle the exit of a child. Called from Make_Make. | 1910 | /* Handle the exit of a child. Called from Make_Make. | |
1911 | * | 1911 | * | |
1912 | * The job descriptor is removed from the list of children. | 1912 | * The job descriptor is removed from the list of children. | |
1913 | * | 1913 | * | |
1914 | * Notes: | 1914 | * Notes: | |
1915 | * We do waits, blocking or not, according to the wisdom of our | 1915 | * We do waits, blocking or not, according to the wisdom of our | |
1916 | * caller, until there are no more children to report. For each | 1916 | * caller, until there are no more children to report. For each | |
1917 | * job, call JobFinish to finish things off. | 1917 | * job, call JobFinish to finish things off. | |
1918 | */ | 1918 | */ | |
1919 | void | 1919 | void | |
1920 | Job_CatchChildren(void) | 1920 | Job_CatchChildren(void) | |
1921 | { | 1921 | { | |
1922 | int pid; /* pid of dead child */ | 1922 | int pid; /* pid of dead child */ | |
1923 | int status; /* Exit/termination status */ | 1923 | int status; /* Exit/termination status */ | |
1924 | 1924 | |||
1925 | /* | 1925 | /* | |
1926 | * Don't even bother if we know there's no one around. | 1926 | * Don't even bother if we know there's no one around. | |
1927 | */ | 1927 | */ | |
1928 | if (jobTokensRunning == 0) | 1928 | if (jobTokensRunning == 0) | |
1929 | return; | 1929 | return; | |
1930 | 1930 | |||
1931 | while ((pid = waitpid((pid_t) -1, &status, WNOHANG | WUNTRACED)) > 0) { | 1931 | while ((pid = waitpid((pid_t) -1, &status, WNOHANG | WUNTRACED)) > 0) { | |
1932 | DEBUG2(JOB, "Process %d exited/stopped status %x.\n", pid, status); | 1932 | DEBUG2(JOB, "Process %d exited/stopped status %x.\n", pid, status); | |
1933 | JobReapChild(pid, status, TRUE); | 1933 | JobReapChild(pid, status, TRUE); | |
1934 | } | 1934 | } | |
1935 | } | 1935 | } | |
1936 | 1936 | |||
1937 | /* | 1937 | /* | |
1938 | * It is possible that wait[pid]() was called from elsewhere, | 1938 | * It is possible that wait[pid]() was called from elsewhere, | |
1939 | * this lets us reap jobs regardless. | 1939 | * this lets us reap jobs regardless. | |
1940 | */ | 1940 | */ | |
1941 | void | 1941 | void | |
1942 | JobReapChild(pid_t pid, int status, Boolean isJobs) | 1942 | JobReapChild(pid_t pid, int status, Boolean isJobs) | |
1943 | { | 1943 | { | |
1944 | Job *job; /* job descriptor for dead child */ | 1944 | Job *job; /* job descriptor for dead child */ | |
1945 | 1945 | |||
1946 | /* | 1946 | /* | |
1947 | * Don't even bother if we know there's no one around. | 1947 | * Don't even bother if we know there's no one around. | |
1948 | */ | 1948 | */ | |
1949 | if (jobTokensRunning == 0) | 1949 | if (jobTokensRunning == 0) | |
1950 | return; | 1950 | return; | |
1951 | 1951 | |||
1952 | job = JobFindPid(pid, JOB_ST_RUNNING, isJobs); | 1952 | job = JobFindPid(pid, JOB_ST_RUNNING, isJobs); | |
1953 | if (job == NULL) { | 1953 | if (job == NULL) { | |
1954 | if (isJobs) { | 1954 | if (isJobs) { | |
1955 | if (!lurking_children) | 1955 | if (!lurking_children) | |
1956 | Error("Child (%d) status %x not in table?", pid, status); | 1956 | Error("Child (%d) status %x not in table?", pid, status); | |
1957 | } | 1957 | } | |
1958 | return; /* not ours */ | 1958 | return; /* not ours */ | |
1959 | } | 1959 | } | |
1960 | if (WIFSTOPPED(status)) { | 1960 | if (WIFSTOPPED(status)) { | |
1961 | DEBUG2(JOB, "Process %d (%s) stopped.\n", job->pid, job->node->name); | 1961 | DEBUG2(JOB, "Process %d (%s) stopped.\n", job->pid, job->node->name); | |
1962 | if (!make_suspended) { | 1962 | if (!make_suspended) { | |
1963 | switch (WSTOPSIG(status)) { | 1963 | switch (WSTOPSIG(status)) { | |
1964 | case SIGTSTP: | 1964 | case SIGTSTP: | |
1965 | (void)printf("*** [%s] Suspended\n", job->node->name); | 1965 | (void)printf("*** [%s] Suspended\n", job->node->name); | |
1966 | break; | 1966 | break; | |
1967 | case SIGSTOP: | 1967 | case SIGSTOP: | |
1968 | (void)printf("*** [%s] Stopped\n", job->node->name); | 1968 | (void)printf("*** [%s] Stopped\n", job->node->name); | |
1969 | break; | 1969 | break; | |
1970 | default: | 1970 | default: | |
1971 | (void)printf("*** [%s] Stopped -- signal %d\n", | 1971 | (void)printf("*** [%s] Stopped -- signal %d\n", | |
1972 | job->node->name, WSTOPSIG(status)); | 1972 | job->node->name, WSTOPSIG(status)); | |
1973 | } | 1973 | } | |
1974 | job->job_suspended = 1; | 1974 | job->job_suspended = 1; | |
1975 | } | 1975 | } | |
1976 | (void)fflush(stdout); | 1976 | (void)fflush(stdout); | |
1977 | return; | 1977 | return; | |
1978 | } | 1978 | } | |
1979 | 1979 | |||
1980 | job->job_state = JOB_ST_FINISHED; | 1980 | job->job_state = JOB_ST_FINISHED; | |
1981 | job->exit_status = status; | 1981 | job->exit_status = status; | |
1982 | 1982 | |||
1983 | JobFinish(job, status); | 1983 | JobFinish(job, status); | |
1984 | } | 1984 | } | |
1985 | 1985 | |||
1986 | /* Catch the output from our children, if we're using pipes do so. Otherwise | 1986 | /* Catch the output from our children, if we're using pipes do so. Otherwise | |
1987 | * just block time until we get a signal(most likely a SIGCHLD) since there's | 1987 | * just block time until we get a signal(most likely a SIGCHLD) since there's | |
1988 | * no point in just spinning when there's nothing to do and the reaping of a | 1988 | * no point in just spinning when there's nothing to do and the reaping of a | |
1989 | * child can wait for a while. */ | 1989 | * child can wait for a while. */ | |
1990 | void | 1990 | void | |
1991 | Job_CatchOutput(void) | 1991 | Job_CatchOutput(void) | |
1992 | { | 1992 | { | |
1993 | int nready; | 1993 | int nready; | |
1994 | Job *job; | 1994 | Job *job; | |
1995 | unsigned int i; | 1995 | unsigned int i; | |
1996 | 1996 | |||
1997 | (void)fflush(stdout); | 1997 | (void)fflush(stdout); | |
1998 | 1998 | |||
1999 | /* The first fd in the list is the job token pipe */ | 1999 | /* The first fd in the list is the job token pipe */ | |
2000 | do { | 2000 | do { | |
2001 | nready = poll(fds + 1 - wantToken, nfds - 1 + wantToken, POLL_MSEC); | 2001 | nready = poll(fds + 1 - wantToken, nfds - 1 + wantToken, POLL_MSEC); | |
2002 | } while (nready < 0 && errno == EINTR); | 2002 | } while (nready < 0 && errno == EINTR); | |
2003 | 2003 | |||
2004 | if (nready < 0) | 2004 | if (nready < 0) | |
2005 | Punt("poll: %s", strerror(errno)); | 2005 | Punt("poll: %s", strerror(errno)); | |
2006 | 2006 | |||
2007 | if (nready > 0 && readyfd(&childExitJob)) { | 2007 | if (nready > 0 && readyfd(&childExitJob)) { | |
2008 | char token = 0; | 2008 | char token = 0; | |
2009 | ssize_t count; | 2009 | ssize_t count; | |
2010 | count = read(childExitJob.inPipe, &token, 1); | 2010 | count = read(childExitJob.inPipe, &token, 1); | |
2011 | switch (count) { | 2011 | switch (count) { | |
2012 | case 0: | 2012 | case 0: | |
2013 | Punt("unexpected eof on token pipe"); | 2013 | Punt("unexpected eof on token pipe"); | |
2014 | case -1: | 2014 | case -1: | |
2015 | Punt("token pipe read: %s", strerror(errno)); | 2015 | Punt("token pipe read: %s", strerror(errno)); | |
2016 | case 1: | 2016 | case 1: | |
2017 | if (token == DO_JOB_RESUME[0]) | 2017 | if (token == DO_JOB_RESUME[0]) | |
2018 | /* Complete relay requested from our SIGCONT handler */ | 2018 | /* Complete relay requested from our SIGCONT handler */ | |
2019 | JobRestartJobs(); | 2019 | JobRestartJobs(); | |
2020 | break; | 2020 | break; | |
2021 | default: | 2021 | default: | |
2022 | abort(); | 2022 | abort(); | |
2023 | } | 2023 | } | |
2024 | --nready; | 2024 | --nready; | |
2025 | } | 2025 | } | |
2026 | 2026 | |||
2027 | Job_CatchChildren(); | 2027 | Job_CatchChildren(); | |
2028 | if (nready == 0) | 2028 | if (nready == 0) | |
2029 | return; | 2029 | return; | |
2030 | 2030 | |||
2031 | for (i = npseudojobs * nfds_per_job(); i < nfds; i++) { | 2031 | for (i = npseudojobs * nfds_per_job(); i < nfds; i++) { | |
2032 | if (!fds[i].revents) | 2032 | if (!fds[i].revents) | |
2033 | continue; | 2033 | continue; | |
2034 | job = jobfds[i]; | 2034 | job = jobfds[i]; | |
2035 | if (job->job_state == JOB_ST_RUNNING) | 2035 | if (job->job_state == JOB_ST_RUNNING) | |
2036 | JobDoOutput(job, FALSE); | 2036 | JobDoOutput(job, FALSE); | |
2037 | #if defined(USE_FILEMON) && !defined(USE_FILEMON_DEV) | 2037 | #if defined(USE_FILEMON) && !defined(USE_FILEMON_DEV) | |
2038 | /* | 2038 | /* | |
2039 | * With meta mode, we may have activity on the job's filemon | 2039 | * With meta mode, we may have activity on the job's filemon | |
2040 | * descriptor too, which at the moment is any pollfd other than | 2040 | * descriptor too, which at the moment is any pollfd other than | |
2041 | * job->inPollfd. | 2041 | * job->inPollfd. | |
2042 | */ | 2042 | */ | |
2043 | if (useMeta && job->inPollfd != &fds[i]) { | 2043 | if (useMeta && job->inPollfd != &fds[i]) { | |
2044 | if (meta_job_event(job) <= 0) { | 2044 | if (meta_job_event(job) <= 0) { | |
2045 | fds[i].events = 0; /* never mind */ | 2045 | fds[i].events = 0; /* never mind */ | |
2046 | } | 2046 | } | |
2047 | } | 2047 | } | |
2048 | #endif | 2048 | #endif | |
2049 | if (--nready == 0) | 2049 | if (--nready == 0) | |
2050 | return; | 2050 | return; | |
2051 | } | 2051 | } | |
2052 | } | 2052 | } | |
2053 | 2053 | |||
2054 | /* Start the creation of a target. Basically a front-end for JobStart used by | 2054 | /* Start the creation of a target. Basically a front-end for JobStart used by | |
2055 | * the Make module. */ | 2055 | * the Make module. */ | |
2056 | void | 2056 | void | |
2057 | Job_Make(GNode *gn) | 2057 | Job_Make(GNode *gn) | |
2058 | { | 2058 | { | |
2059 | (void)JobStart(gn, 0); | 2059 | (void)JobStart(gn, 0); | |
2060 | } | 2060 | } | |
2061 | 2061 | |||
2062 | void | 2062 | void | |
2063 | Shell_Init(void) | 2063 | Shell_Init(void) | |
2064 | { | 2064 | { | |
2065 | if (shellPath == NULL) { | 2065 | if (shellPath == NULL) { | |
2066 | /* | 2066 | /* | |
2067 | * We are using the default shell, which may be an absolute | 2067 | * We are using the default shell, which may be an absolute | |
2068 | * path if DEFSHELL_CUSTOM is defined. | 2068 | * path if DEFSHELL_CUSTOM is defined. | |
2069 | */ | 2069 | */ | |
2070 | shellName = commandShell->name; | 2070 | shellName = commandShell->name; | |
2071 | #ifdef DEFSHELL_CUSTOM | 2071 | #ifdef DEFSHELL_CUSTOM | |
2072 | if (*shellName == '/') { | 2072 | if (*shellName == '/') { | |
2073 | shellPath = shellName; | 2073 | shellPath = shellName; | |
2074 | shellName = strrchr(shellPath, '/'); | 2074 | shellName = strrchr(shellPath, '/'); | |
2075 | shellName++; | 2075 | shellName++; | |
2076 | } else | 2076 | } else | |
2077 | #endif | 2077 | #endif | |
2078 | shellPath = str_concat3(_PATH_DEFSHELLDIR, "/", shellName); | 2078 | shellPath = str_concat3(_PATH_DEFSHELLDIR, "/", shellName); | |
2079 | } | 2079 | } | |
2080 | Var_Set_with_flags(".SHELL", shellPath, VAR_CMDLINE, VAR_SET_READONLY); | 2080 | Var_Set_with_flags(".SHELL", shellPath, VAR_CMDLINE, VAR_SET_READONLY); | |
2081 | if (commandShell->exit == NULL) { | 2081 | if (commandShell->exit == NULL) { | |
2082 | commandShell->exit = ""; | 2082 | commandShell->exit = ""; | |
2083 | } | 2083 | } | |
2084 | if (commandShell->echo == NULL) { | 2084 | if (commandShell->echo == NULL) { | |
2085 | commandShell->echo = ""; | 2085 | commandShell->echo = ""; | |
2086 | } | 2086 | } | |
2087 | if (commandShell->hasErrCtl && commandShell->exit[0] != '\0') { | 2087 | if (commandShell->hasErrCtl && commandShell->exit[0] != '\0') { | |
2088 | if (shellErrFlag && | 2088 | if (shellErrFlag && | |
2089 | strcmp(commandShell->exit, &shellErrFlag[1]) != 0) { | 2089 | strcmp(commandShell->exit, &shellErrFlag[1]) != 0) { | |
2090 | free(shellErrFlag); | 2090 | free(shellErrFlag); | |
2091 | shellErrFlag = NULL; | 2091 | shellErrFlag = NULL; | |
2092 | } | 2092 | } | |
2093 | if (!shellErrFlag) { | 2093 | if (!shellErrFlag) { | |
2094 | size_t n = strlen(commandShell->exit) + 2; | 2094 | size_t n = strlen(commandShell->exit) + 2; | |
2095 | 2095 | |||
2096 | shellErrFlag = bmake_malloc(n); | 2096 | shellErrFlag = bmake_malloc(n); | |
2097 | if (shellErrFlag) { | 2097 | if (shellErrFlag) { | |
2098 | snprintf(shellErrFlag, n, "-%s", commandShell->exit); | 2098 | snprintf(shellErrFlag, n, "-%s", commandShell->exit); | |
2099 | } | 2099 | } | |
2100 | } | 2100 | } | |
2101 | } else if (shellErrFlag) { | 2101 | } else if (shellErrFlag) { | |
2102 | free(shellErrFlag); | 2102 | free(shellErrFlag); | |
2103 | shellErrFlag = NULL; | 2103 | shellErrFlag = NULL; | |
2104 | } | 2104 | } | |
2105 | } | 2105 | } | |
2106 | 2106 | |||
2107 | /* Return the string literal that is used in the current command shell | 2107 | /* Return the string literal that is used in the current command shell | |
2108 | * to produce a newline character. */ | 2108 | * to produce a newline character. */ | |
2109 | const char * | 2109 | const char * | |
2110 | Shell_GetNewline(void) | 2110 | Shell_GetNewline(void) | |
2111 | { | 2111 | { | |
2112 | return commandShell->newline; | 2112 | return commandShell->newline; | |
2113 | } | 2113 | } | |
2114 | 2114 | |||
2115 | void | 2115 | void | |
2116 | Job_SetPrefix(void) | 2116 | Job_SetPrefix(void) | |
2117 | { | 2117 | { | |
2118 | if (targPrefix) { | 2118 | if (targPrefix) { | |
2119 | free(targPrefix); | 2119 | free(targPrefix); | |
2120 | } else if (!Var_Exists(MAKE_JOB_PREFIX, VAR_GLOBAL)) { | 2120 | } else if (!Var_Exists(MAKE_JOB_PREFIX, VAR_GLOBAL)) { | |
2121 | Var_Set(MAKE_JOB_PREFIX, "---", VAR_GLOBAL); | 2121 | Var_Set(MAKE_JOB_PREFIX, "---", VAR_GLOBAL); | |
2122 | } | 2122 | } | |
2123 | 2123 | |||
2124 | (void)Var_Subst("${" MAKE_JOB_PREFIX "}", | 2124 | (void)Var_Subst("${" MAKE_JOB_PREFIX "}", | |
2125 | VAR_GLOBAL, VARE_WANTRES, &targPrefix); | 2125 | VAR_GLOBAL, VARE_WANTRES, &targPrefix); | |
2126 | /* TODO: handle errors */ | 2126 | /* TODO: handle errors */ | |
2127 | } | 2127 | } | |
2128 | 2128 | |||
2129 | /* Initialize the process module. */ | 2129 | /* Initialize the process module. */ | |
2130 | void | 2130 | void | |
2131 | Job_Init(void) | 2131 | Job_Init(void) | |
2132 | { | 2132 | { | |
2133 | Job_SetPrefix(); | 2133 | Job_SetPrefix(); | |
2134 | /* Allocate space for all the job info */ | 2134 | /* Allocate space for all the job info */ | |
2135 | job_table = bmake_malloc((size_t)opts.maxJobs * sizeof *job_table); | 2135 | job_table = bmake_malloc((size_t)opts.maxJobs * sizeof *job_table); | |
2136 | memset(job_table, 0, (size_t)opts.maxJobs * sizeof *job_table); | 2136 | memset(job_table, 0, (size_t)opts.maxJobs * sizeof *job_table); | |
2137 | job_table_end = job_table + opts.maxJobs; | 2137 | job_table_end = job_table + opts.maxJobs; | |
2138 | wantToken = 0; | 2138 | wantToken = 0; | |
2139 | 2139 | |||
2140 | aborting = ABORT_NONE; | 2140 | aborting = ABORT_NONE; | |
2141 | errors = 0; | 2141 | errors = 0; | |
2142 | 2142 | |||
2143 | lastNode = NULL; | 2143 | lastNode = NULL; | |
2144 | 2144 | |||
2145 | /* | 2145 | /* | |
2146 | * There is a non-zero chance that we already have children. | 2146 | * There is a non-zero chance that we already have children. | |
2147 | * eg after 'make -f- <<EOF' | 2147 | * eg after 'make -f- <<EOF' | |
2148 | * Since their termination causes a 'Child (pid) not in table' message, | 2148 | * Since their termination causes a 'Child (pid) not in table' message, | |
2149 | * Collect the status of any that are already dead, and suppress the | 2149 | * Collect the status of any that are already dead, and suppress the | |
2150 | * error message if there are any undead ones. | 2150 | * error message if there are any undead ones. | |
2151 | */ | 2151 | */ | |
2152 | for (;;) { | 2152 | for (;;) { | |
2153 | int rval, status; | 2153 | int rval, status; | |
2154 | rval = waitpid((pid_t) -1, &status, WNOHANG); | 2154 | rval = waitpid((pid_t) -1, &status, WNOHANG); | |
2155 | if (rval > 0) | 2155 | if (rval > 0) | |
2156 | continue; | 2156 | continue; | |
2157 | if (rval == 0) | 2157 | if (rval == 0) | |
2158 | lurking_children = 1; | 2158 | lurking_children = 1; | |
2159 | break; | 2159 | break; | |
2160 | } | 2160 | } | |
2161 | 2161 | |||
2162 | Shell_Init(); | 2162 | Shell_Init(); | |
2163 | 2163 | |||
2164 | JobCreatePipe(&childExitJob, 3); | 2164 | JobCreatePipe(&childExitJob, 3); | |
2165 | 2165 | |||
2166 | /* Preallocate enough for the maximum number of jobs. */ | 2166 | /* Preallocate enough for the maximum number of jobs. */ | |
2167 | fds = bmake_malloc(sizeof(*fds) * | 2167 | fds = bmake_malloc(sizeof(*fds) * | |
2168 | (npseudojobs + (size_t)opts.maxJobs) * nfds_per_job()); | 2168 | (npseudojobs + (size_t)opts.maxJobs) * nfds_per_job()); | |
2169 | jobfds = bmake_malloc(sizeof(*jobfds) * | 2169 | jobfds = bmake_malloc(sizeof(*jobfds) * | |
2170 | (npseudojobs + (size_t)opts.maxJobs) * nfds_per_job()); | 2170 | (npseudojobs + (size_t)opts.maxJobs) * nfds_per_job()); | |
2171 | 2171 | |||
2172 | /* These are permanent entries and take slots 0 and 1 */ | 2172 | /* These are permanent entries and take slots 0 and 1 */ | |
2173 | watchfd(&tokenWaitJob); | 2173 | watchfd(&tokenWaitJob); | |
2174 | watchfd(&childExitJob); | 2174 | watchfd(&childExitJob); | |
2175 | 2175 | |||
2176 | sigemptyset(&caught_signals); | 2176 | sigemptyset(&caught_signals); | |
2177 | /* | 2177 | /* | |
2178 | * Install a SIGCHLD handler. | 2178 | * Install a SIGCHLD handler. | |
2179 | */ | 2179 | */ | |
2180 | (void)bmake_signal(SIGCHLD, JobChildSig); | 2180 | (void)bmake_signal(SIGCHLD, JobChildSig); | |
2181 | sigaddset(&caught_signals, SIGCHLD); | 2181 | sigaddset(&caught_signals, SIGCHLD); | |
2182 | 2182 | |||
2183 | #define ADDSIG(s,h) \ | 2183 | #define ADDSIG(s,h) \ | |
2184 | if (bmake_signal(s, SIG_IGN) != SIG_IGN) { \ | 2184 | if (bmake_signal(s, SIG_IGN) != SIG_IGN) { \ | |
2185 | sigaddset(&caught_signals, s); \ | 2185 | sigaddset(&caught_signals, s); \ | |
2186 | (void)bmake_signal(s, h); \ | 2186 | (void)bmake_signal(s, h); \ | |
2187 | } | 2187 | } | |
2188 | 2188 | |||
2189 | /* | 2189 | /* | |
2190 | * Catch the four signals that POSIX specifies if they aren't ignored. | 2190 | * Catch the four signals that POSIX specifies if they aren't ignored. | |
2191 | * JobPassSig will take care of calling JobInterrupt if appropriate. | 2191 | * JobPassSig will take care of calling JobInterrupt if appropriate. | |
2192 | */ | 2192 | */ | |
2193 | ADDSIG(SIGINT, JobPassSig_int) | 2193 | ADDSIG(SIGINT, JobPassSig_int) | |
2194 | ADDSIG(SIGHUP, JobPassSig_term) | 2194 | ADDSIG(SIGHUP, JobPassSig_term) | |
2195 | ADDSIG(SIGTERM, JobPassSig_term) | 2195 | ADDSIG(SIGTERM, JobPassSig_term) | |
2196 | ADDSIG(SIGQUIT, JobPassSig_term) | 2196 | ADDSIG(SIGQUIT, JobPassSig_term) | |
2197 | 2197 | |||
2198 | /* | 2198 | /* | |
2199 | * There are additional signals that need to be caught and passed if | 2199 | * There are additional signals that need to be caught and passed if | |
2200 | * either the export system wants to be told directly of signals or if | 2200 | * either the export system wants to be told directly of signals or if | |
2201 | * we're giving each job its own process group (since then it won't get | 2201 | * we're giving each job its own process group (since then it won't get | |
2202 | * signals from the terminal driver as we own the terminal) | 2202 | * signals from the terminal driver as we own the terminal) | |
2203 | */ | 2203 | */ | |
2204 | ADDSIG(SIGTSTP, JobPassSig_suspend) | 2204 | ADDSIG(SIGTSTP, JobPassSig_suspend) | |
2205 | ADDSIG(SIGTTOU, JobPassSig_suspend) | 2205 | ADDSIG(SIGTTOU, JobPassSig_suspend) | |
2206 | ADDSIG(SIGTTIN, JobPassSig_suspend) | 2206 | ADDSIG(SIGTTIN, JobPassSig_suspend) | |
2207 | ADDSIG(SIGWINCH, JobCondPassSig) | 2207 | ADDSIG(SIGWINCH, JobCondPassSig) | |
2208 | ADDSIG(SIGCONT, JobContinueSig) | 2208 | ADDSIG(SIGCONT, JobContinueSig) | |
2209 | #undef ADDSIG | 2209 | #undef ADDSIG | |
2210 | 2210 | |||
2211 | (void)Job_RunTarget(".BEGIN", NULL); | 2211 | (void)Job_RunTarget(".BEGIN", NULL); | |
2212 | /* Create the .END node now, even though no code in the unit tests | 2212 | /* Create the .END node now, even though no code in the unit tests | |
2213 | * depends on it. See also Targ_GetEndNode in Compat_Run. */ | 2213 | * depends on it. See also Targ_GetEndNode in Compat_Run. */ | |
2214 | (void)Targ_GetEndNode(); | 2214 | (void)Targ_GetEndNode(); | |
2215 | } | 2215 | } | |
2216 | 2216 | |||
2217 | static void JobSigReset(void) | 2217 | static void JobSigReset(void) | |
2218 | { | 2218 | { | |
2219 | #define DELSIG(s) \ | 2219 | #define DELSIG(s) \ | |
2220 | if (sigismember(&caught_signals, s)) { \ | 2220 | if (sigismember(&caught_signals, s)) { \ | |
2221 | (void)bmake_signal(s, SIG_DFL); \ | 2221 | (void)bmake_signal(s, SIG_DFL); \ | |
2222 | } | 2222 | } | |
2223 | 2223 | |||
2224 | DELSIG(SIGINT) | 2224 | DELSIG(SIGINT) | |
2225 | DELSIG(SIGHUP) | 2225 | DELSIG(SIGHUP) | |
2226 | DELSIG(SIGQUIT) | 2226 | DELSIG(SIGQUIT) | |
2227 | DELSIG(SIGTERM) | 2227 | DELSIG(SIGTERM) | |
2228 | DELSIG(SIGTSTP) | 2228 | DELSIG(SIGTSTP) | |
2229 | DELSIG(SIGTTOU) | 2229 | DELSIG(SIGTTOU) | |
2230 | DELSIG(SIGTTIN) | 2230 | DELSIG(SIGTTIN) | |
2231 | DELSIG(SIGWINCH) | 2231 | DELSIG(SIGWINCH) | |
2232 | DELSIG(SIGCONT) | 2232 | DELSIG(SIGCONT) | |
2233 | #undef DELSIG | 2233 | #undef DELSIG | |
2234 | (void)bmake_signal(SIGCHLD, SIG_DFL); | 2234 | (void)bmake_signal(SIGCHLD, SIG_DFL); | |
2235 | } | 2235 | } | |
2236 | 2236 | |||
2237 | /* Find a shell in 'shells' given its name, or return NULL. */ | 2237 | /* Find a shell in 'shells' given its name, or return NULL. */ | |
2238 | static Shell * | 2238 | static Shell * | |
2239 | JobMatchShell(const char *name) | 2239 | JobMatchShell(const char *name) | |
2240 | { | 2240 | { | |
2241 | Shell *sh = shells; | 2241 | Shell *sh = shells; | |
2242 | const Shell *shellsEnd = sh + sizeof shells / sizeof shells[0]; | 2242 | const Shell *shellsEnd = sh + sizeof shells / sizeof shells[0]; | |
2243 | 2243 | |||
2244 | for (sh = shells; sh < shellsEnd; sh++) { | 2244 | for (sh = shells; sh < shellsEnd; sh++) { | |
2245 | if (strcmp(name, sh->name) == 0) | 2245 | if (strcmp(name, sh->name) == 0) | |
2246 | return sh; | 2246 | return sh; | |
2247 | } | 2247 | } | |
2248 | return NULL; | 2248 | return NULL; | |
2249 | } | 2249 | } | |
2250 | 2250 | |||
2251 | /*- | 2251 | /*- | |
2252 | *----------------------------------------------------------------------- | 2252 | *----------------------------------------------------------------------- | |
2253 | * Job_ParseShell -- | 2253 | * Job_ParseShell -- | |
2254 | * Parse a shell specification and set up commandShell, shellPath | 2254 | * Parse a shell specification and set up commandShell, shellPath | |
2255 | * and shellName appropriately. | 2255 | * and shellName appropriately. | |
2256 | * | 2256 | * | |
2257 | * Input: | 2257 | * Input: | |
2258 | * line The shell spec | 2258 | * line The shell spec | |
2259 | * | 2259 | * | |
2260 | * Results: | 2260 | * Results: | |
2261 | * FALSE if the specification was incorrect. | 2261 | * FALSE if the specification was incorrect. | |
2262 | * | 2262 | * | |
2263 | * Side Effects: | 2263 | * Side Effects: | |
2264 | * commandShell points to a Shell structure (either predefined or | 2264 | * commandShell points to a Shell structure (either predefined or | |
2265 | * created from the shell spec), shellPath is the full path of the | 2265 | * created from the shell spec), shellPath is the full path of the | |
2266 | * shell described by commandShell, while shellName is just the | 2266 | * shell described by commandShell, while shellName is just the | |
2267 | * final component of shellPath. | 2267 | * final component of shellPath. | |
2268 | * | 2268 | * | |
2269 | * Notes: | 2269 | * Notes: | |
2270 | * A shell specification consists of a .SHELL target, with dependency | 2270 | * A shell specification consists of a .SHELL target, with dependency | |
2271 | * operator, followed by a series of blank-separated words. Double | 2271 | * operator, followed by a series of blank-separated words. Double | |
2272 | * quotes can be used to use blanks in words. A backslash escapes | 2272 | * quotes can be used to use blanks in words. A backslash escapes | |
2273 | * anything (most notably a double-quote and a space) and | 2273 | * anything (most notably a double-quote and a space) and | |
2274 | * provides the functionality it does in C. Each word consists of | 2274 | * provides the functionality it does in C. Each word consists of | |
2275 | * keyword and value separated by an equal sign. There should be no | 2275 | * keyword and value separated by an equal sign. There should be no | |
2276 | * unnecessary spaces in the word. The keywords are as follows: | 2276 | * unnecessary spaces in the word. The keywords are as follows: | |
2277 | * name Name of shell. | 2277 | * name Name of shell. | |
2278 | * path Location of shell. | 2278 | * path Location of shell. | |
2279 | * quiet Command to turn off echoing. | 2279 | * quiet Command to turn off echoing. | |
2280 | * echo Command to turn echoing on | 2280 | * echo Command to turn echoing on | |
2281 | * filter Result of turning off echoing that shouldn't be | 2281 | * filter Result of turning off echoing that shouldn't be | |
2282 | * printed. | 2282 | * printed. | |
2283 | * echoFlag Flag to turn echoing on at the start | 2283 | * echoFlag Flag to turn echoing on at the start | |
2284 | * errFlag Flag to turn error checking on at the start | 2284 | * errFlag Flag to turn error checking on at the start | |
2285 | * hasErrCtl True if shell has error checking control | 2285 | * hasErrCtl True if shell has error checking control | |
2286 | * newline String literal to represent a newline char | 2286 | * newline String literal to represent a newline char | |
2287 | * check Command to turn on error checking if hasErrCtl | 2287 | * check Command to turn on error checking if hasErrCtl | |
2288 | * is TRUE or template of command to echo a command | 2288 | * is TRUE or template of command to echo a command | |
2289 | * for which error checking is off if hasErrCtl is | 2289 | * for which error checking is off if hasErrCtl is | |
2290 | * FALSE. | 2290 | * FALSE. | |
2291 | * ignore Command to turn off error checking if hasErrCtl | 2291 | * ignore Command to turn off error checking if hasErrCtl | |
2292 | * is TRUE or template of command to execute a | 2292 | * is TRUE or template of command to execute a | |
2293 | * command so as to ignore any errors it returns if | 2293 | * command so as to ignore any errors it returns if | |
2294 | * hasErrCtl is FALSE. | 2294 | * hasErrCtl is FALSE. | |
2295 | * | 2295 | * | |
2296 | *----------------------------------------------------------------------- | 2296 | *----------------------------------------------------------------------- | |
2297 | */ | 2297 | */ | |
2298 | Boolean | 2298 | Boolean | |
2299 | Job_ParseShell(char *line) | 2299 | Job_ParseShell(char *line) | |
2300 | { | 2300 | { | |
2301 | Words wordsList; | 2301 | Words wordsList; | |
2302 | char **words; | 2302 | char **words; | |
2303 | char **argv; | 2303 | char **argv; | |
2304 | size_t argc; | 2304 | size_t argc; | |
2305 | char *path; | 2305 | char *path; | |
2306 | Shell newShell; | 2306 | Shell newShell; | |
2307 | Boolean fullSpec = FALSE; | 2307 | Boolean fullSpec = FALSE; | |
2308 | Shell *sh; | 2308 | Shell *sh; | |
2309 | 2309 | |||
2310 | pp_skip_whitespace(&line); | 2310 | pp_skip_whitespace(&line); | |
2311 | 2311 | |||
2312 | free(shellArgv); | 2312 | free(shellArgv); | |
2313 | 2313 | |||
2314 | memset(&newShell, 0, sizeof(newShell)); | 2314 | memset(&newShell, 0, sizeof(newShell)); | |
2315 | 2315 | |||
2316 | /* | 2316 | /* | |
2317 | * Parse the specification by keyword | 2317 | * Parse the specification by keyword | |
2318 | */ | 2318 | */ | |
2319 | wordsList = Str_Words(line, TRUE); | 2319 | wordsList = Str_Words(line, TRUE); | |
2320 | words = wordsList.words; | 2320 | words = wordsList.words; | |
2321 | argc = wordsList.len; | 2321 | argc = wordsList.len; | |
2322 | path = wordsList.freeIt; | 2322 | path = wordsList.freeIt; | |
2323 | if (words == NULL) { | 2323 | if (words == NULL) { | |
2324 | Error("Unterminated quoted string [%s]", line); | 2324 | Error("Unterminated quoted string [%s]", line); | |
2325 | return FALSE; | 2325 | return FALSE; | |
2326 | } | 2326 | } | |
2327 | shellArgv = path; | 2327 | shellArgv = path; | |
2328 | 2328 | |||
2329 | for (path = NULL, argv = words; argc != 0; argc--, argv++) { | 2329 | for (path = NULL, argv = words; argc != 0; argc--, argv++) { | |
2330 | char *arg = *argv; | 2330 | char *arg = *argv; | |
2331 | if (strncmp(arg, "path=", 5) == 0) { | 2331 | if (strncmp(arg, "path=", 5) == 0) { | |
2332 | path = arg + 5; | 2332 | path = arg + 5; | |
2333 | } else if (strncmp(arg, "name=", 5) == 0) { | 2333 | } else if (strncmp(arg, "name=", 5) == 0) { | |
2334 | newShell.name = arg + 5; | 2334 | newShell.name = arg + 5; | |
2335 | } else { | 2335 | } else { | |
2336 | if (strncmp(arg, "quiet=", 6) == 0) { | 2336 | if (strncmp(arg, "quiet=", 6) == 0) { | |
2337 | newShell.echoOff = arg + 6; | 2337 | newShell.echoOff = arg + 6; | |
2338 | } else if (strncmp(arg, "echo=", 5) == 0) { | 2338 | } else if (strncmp(arg, "echo=", 5) == 0) { | |
2339 | newShell.echoOn = arg + 5; | 2339 | newShell.echoOn = arg + 5; | |
2340 | } else if (strncmp(arg, "filter=", 7) == 0) { | 2340 | } else if (strncmp(arg, "filter=", 7) == 0) { | |
2341 | newShell.noPrint = arg + 7; | 2341 | newShell.noPrint = arg + 7; | |
2342 | newShell.noPrintLen = strlen(newShell.noPrint); | 2342 | newShell.noPrintLen = strlen(newShell.noPrint); | |
2343 | } else if (strncmp(arg, "echoFlag=", 9) == 0) { | 2343 | } else if (strncmp(arg, "echoFlag=", 9) == 0) { | |
2344 | newShell.echo = arg + 9; | 2344 | newShell.echo = arg + 9; | |
2345 | } else if (strncmp(arg, "errFlag=", 8) == 0) { | 2345 | } else if (strncmp(arg, "errFlag=", 8) == 0) { | |
2346 | newShell.exit = arg + 8; | 2346 | newShell.exit = arg + 8; | |
2347 | } else if (strncmp(arg, "hasErrCtl=", 10) == 0) { | 2347 | } else if (strncmp(arg, "hasErrCtl=", 10) == 0) { | |
2348 | char c = arg[10]; | 2348 | char c = arg[10]; | |
2349 | newShell.hasErrCtl = c == 'Y' || c == 'y' || | 2349 | newShell.hasErrCtl = c == 'Y' || c == 'y' || | |
2350 | c == 'T' || c == 't'; | 2350 | c == 'T' || c == 't'; | |
2351 | } else if (strncmp(arg, "newline=", 8) == 0) { | 2351 | } else if (strncmp(arg, "newline=", 8) == 0) { | |
2352 | newShell.newline = arg + 8; | 2352 | newShell.newline = arg + 8; | |
2353 | } else if (strncmp(arg, "check=", 6) == 0) { | 2353 | } else if (strncmp(arg, "check=", 6) == 0) { | |
2354 | newShell.errOnOrEcho = arg + 6; | 2354 | newShell.errOnOrEcho = arg + 6; | |
2355 | } else if (strncmp(arg, "ignore=", 7) == 0) { | 2355 | } else if (strncmp(arg, "ignore=", 7) == 0) { | |
2356 | newShell.errOffOrExecIgnore = arg + 7; | 2356 | newShell.errOffOrExecIgnore = arg + 7; | |
2357 | } else if (strncmp(arg, "errout=", 7) == 0) { | 2357 | } else if (strncmp(arg, "errout=", 7) == 0) { | |
2358 | newShell.errExit = arg + 7; | 2358 | newShell.errExit = arg + 7; | |
2359 | } else if (strncmp(arg, "comment=", 8) == 0) { | 2359 | } else if (strncmp(arg, "comment=", 8) == 0) { | |
2360 | newShell.commentChar = arg[8]; | 2360 | newShell.commentChar = arg[8]; | |
2361 | } else { | 2361 | } else { | |
2362 | Parse_Error(PARSE_FATAL, "Unknown keyword \"%s\"", arg); | 2362 | Parse_Error(PARSE_FATAL, "Unknown keyword \"%s\"", arg); | |
2363 | free(words); | 2363 | free(words); | |
2364 | return FALSE; | 2364 | return FALSE; | |
2365 | } | 2365 | } | |
2366 | fullSpec = TRUE; | 2366 | fullSpec = TRUE; | |
2367 | } | 2367 | } | |
2368 | } | 2368 | } | |
2369 | 2369 | |||
2370 | if (path == NULL) { | 2370 | if (path == NULL) { | |
2371 | /* | 2371 | /* | |
2372 | * If no path was given, the user wants one of the pre-defined shells, | 2372 | * If no path was given, the user wants one of the pre-defined shells, | |
2373 | * yes? So we find the one s/he wants with the help of JobMatchShell | 2373 | * yes? So we find the one s/he wants with the help of JobMatchShell | |
2374 | * and set things up the right way. shellPath will be set up by | 2374 | * and set things up the right way. shellPath will be set up by | |
2375 | * Shell_Init. | 2375 | * Shell_Init. | |
2376 | */ | 2376 | */ | |
2377 | if (newShell.name == NULL) { | 2377 | if (newShell.name == NULL) { | |
2378 | Parse_Error(PARSE_FATAL, "Neither path nor name specified"); | 2378 | Parse_Error(PARSE_FATAL, "Neither path nor name specified"); | |
2379 | free(words); | 2379 | free(words); | |
2380 | return FALSE; | 2380 | return FALSE; | |
2381 | } else { | 2381 | } else { | |
2382 | if ((sh = JobMatchShell(newShell.name)) == NULL) { | 2382 | if ((sh = JobMatchShell(newShell.name)) == NULL) { | |
2383 | Parse_Error(PARSE_WARNING, "%s: No matching shell", | 2383 | Parse_Error(PARSE_WARNING, "%s: No matching shell", | |
2384 | newShell.name); | 2384 | newShell.name); | |
2385 | free(words); | 2385 | free(words); | |
2386 | return FALSE; | 2386 | return FALSE; | |
2387 | } | 2387 | } | |
2388 | commandShell = sh; | 2388 | commandShell = sh; | |
2389 | shellName = newShell.name; | 2389 | shellName = newShell.name; | |
2390 | if (shellPath) { | 2390 | if (shellPath) { | |
2391 | /* Shell_Init has already been called! Do it again. */ | 2391 | /* Shell_Init has already been called! Do it again. */ | |
2392 | free(UNCONST(shellPath)); | 2392 | free(UNCONST(shellPath)); | |
2393 | shellPath = NULL; | 2393 | shellPath = NULL; | |
2394 | Shell_Init(); | 2394 | Shell_Init(); | |
2395 | } | 2395 | } | |
2396 | } | 2396 | } | |
2397 | } else { | 2397 | } else { | |
2398 | /* | 2398 | /* | |
2399 | * The user provided a path. If s/he gave nothing else (fullSpec is | 2399 | * The user provided a path. If s/he gave nothing else (fullSpec is | |
2400 | * FALSE), try and find a matching shell in the ones we know of. | 2400 | * FALSE), try and find a matching shell in the ones we know of. | |
2401 | * Else we just take the specification at its word and copy it | 2401 | * Else we just take the specification at its word and copy it | |
2402 | * to a new location. In either case, we need to record the | 2402 | * to a new location. In either case, we need to record the | |
2403 | * path the user gave for the shell. | 2403 | * path the user gave for the shell. | |
2404 | */ | 2404 | */ | |
2405 | shellPath = path; | 2405 | shellPath = path; | |
2406 | path = strrchr(path, '/'); | 2406 | path = strrchr(path, '/'); | |
2407 | if (path == NULL) { | 2407 | if (path == NULL) { | |
2408 | path = UNCONST(shellPath); | 2408 | path = UNCONST(shellPath); | |
2409 | } else { | 2409 | } else { | |
2410 | path++; | 2410 | path++; | |
2411 | } | 2411 | } | |
2412 | if (newShell.name != NULL) { | 2412 | if (newShell.name != NULL) { | |
2413 | shellName = newShell.name; | 2413 | shellName = newShell.name; | |
2414 | } else { | 2414 | } else { | |
2415 | shellName = path; | 2415 | shellName = path; | |
2416 | } | 2416 | } | |
2417 | if (!fullSpec) { | 2417 | if (!fullSpec) { | |
2418 | if ((sh = JobMatchShell(shellName)) == NULL) { | 2418 | if ((sh = JobMatchShell(shellName)) == NULL) { | |
2419 | Parse_Error(PARSE_WARNING, "%s: No matching shell", | 2419 | Parse_Error(PARSE_WARNING, "%s: No matching shell", | |
2420 | shellName); | 2420 | shellName); | |
2421 | free(words); | 2421 | free(words); | |
2422 | return FALSE; | 2422 | return FALSE; | |
2423 | } | 2423 | } | |
2424 | commandShell = sh; | 2424 | commandShell = sh; | |
2425 | } else { | 2425 | } else { | |
2426 | commandShell = bmake_malloc(sizeof(Shell)); | 2426 | commandShell = bmake_malloc(sizeof(Shell)); | |
2427 | *commandShell = newShell; | 2427 | *commandShell = newShell; | |
2428 | } | 2428 | } | |
2429 | /* this will take care of shellErrFlag */ | 2429 | /* this will take care of shellErrFlag */ | |
2430 | Shell_Init(); | 2430 | Shell_Init(); | |
2431 | } | 2431 | } | |
2432 | 2432 | |||
2433 | if (commandShell->echoOn && commandShell->echoOff) { | 2433 | if (commandShell->echoOn && commandShell->echoOff) { | |
2434 | commandShell->hasEchoCtl = TRUE; | 2434 | commandShell->hasEchoCtl = TRUE; | |
2435 | } | 2435 | } | |
2436 | 2436 | |||
2437 | if (!commandShell->hasErrCtl) { | 2437 | if (!commandShell->hasErrCtl) { | |
2438 | if (commandShell->errOnOrEcho == NULL) { | 2438 | if (commandShell->errOnOrEcho == NULL) { | |
2439 | commandShell->errOnOrEcho = ""; | 2439 | commandShell->errOnOrEcho = ""; | |
2440 | } | 2440 | } | |
2441 | if (commandShell->errOffOrExecIgnore == NULL) { | 2441 | if (commandShell->errOffOrExecIgnore == NULL) { | |
2442 | commandShell->errOffOrExecIgnore = "%s\n"; | 2442 | commandShell->errOffOrExecIgnore = "%s\n"; | |
2443 | } | 2443 | } | |
2444 | } | 2444 | } | |
2445 | 2445 | |||
2446 | /* | 2446 | /* | |
2447 | * Do not free up the words themselves, since they might be in use by the | 2447 | * Do not free up the words themselves, since they might be in use by the | |
2448 | * shell specification. | 2448 | * shell specification. | |
2449 | */ | 2449 | */ | |
2450 | free(words); | 2450 | free(words); | |
2451 | return TRUE; | 2451 | return TRUE; | |
2452 | } | 2452 | } | |
2453 | 2453 | |||
2454 | /* Handle the receipt of an interrupt. | 2454 | /* Handle the receipt of an interrupt. | |
2455 | * | 2455 | * | |
2456 | * All children are killed. Another job will be started if the .INTERRUPT | 2456 | * All children are killed. Another job will be started if the .INTERRUPT | |
2457 | * target is defined. | 2457 | * target is defined. | |
2458 | * | 2458 | * | |
2459 | * Input: | 2459 | * Input: | |
2460 | * runINTERRUPT Non-zero if commands for the .INTERRUPT target | 2460 | * runINTERRUPT Non-zero if commands for the .INTERRUPT target | |
2461 | * should be executed | 2461 | * should be executed | |
2462 | * signo signal received | 2462 | * signo signal received | |
2463 | */ | 2463 | */ | |
2464 | static void | 2464 | static void | |
2465 | JobInterrupt(int runINTERRUPT, int signo) | 2465 | JobInterrupt(int runINTERRUPT, int signo) | |
2466 | { | 2466 | { | |
2467 | Job *job; /* job descriptor in that element */ | 2467 | Job *job; /* job descriptor in that element */ | |
2468 | GNode *interrupt; /* the node describing the .INTERRUPT target */ | 2468 | GNode *interrupt; /* the node describing the .INTERRUPT target */ | |
2469 | sigset_t mask; | 2469 | sigset_t mask; | |
2470 | GNode *gn; | 2470 | GNode *gn; | |
2471 | 2471 | |||
2472 | aborting = ABORT_INTERRUPT; | 2472 | aborting = ABORT_INTERRUPT; | |
2473 | 2473 | |||
2474 | JobSigLock(&mask); | 2474 | JobSigLock(&mask); | |
2475 | 2475 | |||
2476 | for (job = job_table; job < job_table_end; job++) { | 2476 | for (job = job_table; job < job_table_end; job++) { | |
2477 | if (job->job_state != JOB_ST_RUNNING) | 2477 | if (job->job_state != JOB_ST_RUNNING) | |
2478 | continue; | 2478 | continue; | |
2479 | 2479 | |||
2480 | gn = job->node; | 2480 | gn = job->node; | |
2481 | 2481 | |||
2482 | JobDeleteTarget(gn); | 2482 | JobDeleteTarget(gn); | |
2483 | if (job->pid) { | 2483 | if (job->pid) { | |
2484 | DEBUG2(JOB, "JobInterrupt passing signal %d to child %d.\n", | 2484 | DEBUG2(JOB, "JobInterrupt passing signal %d to child %d.\n", | |
2485 | signo, job->pid); | 2485 | signo, job->pid); | |
2486 | KILLPG(job->pid, signo); | 2486 | KILLPG(job->pid, signo); | |
2487 | } | 2487 | } | |
2488 | } | 2488 | } | |
2489 | 2489 | |||
2490 | JobSigUnlock(&mask); | 2490 | JobSigUnlock(&mask); | |
2491 | 2491 | |||
2492 | if (runINTERRUPT && !opts.touchFlag) { | 2492 | if (runINTERRUPT && !opts.touchFlag) { | |
2493 | interrupt = Targ_FindNode(".INTERRUPT"); | 2493 | interrupt = Targ_FindNode(".INTERRUPT"); | |
2494 | if (interrupt != NULL) { | 2494 | if (interrupt != NULL) { | |
2495 | opts.ignoreErrors = FALSE; | 2495 | opts.ignoreErrors = FALSE; | |
2496 | JobRun(interrupt); | 2496 | JobRun(interrupt); | |
2497 | } | 2497 | } | |
2498 | } | 2498 | } | |
2499 | Trace_Log(MAKEINTR, 0); | 2499 | Trace_Log(MAKEINTR, 0); | |
2500 | exit(signo); | 2500 | exit(signo); | |
2501 | } | 2501 | } | |
2502 | 2502 | |||
2503 | /* Do the final processing, i.e. run the commands attached to the .END target. | 2503 | /* Do the final processing, i.e. run the commands attached to the .END target. | |
2504 | * | 2504 | * | |
2505 | * Return the number of errors reported. */ | 2505 | * Return the number of errors reported. */ | |
2506 | int | 2506 | int | |
2507 | Job_Finish(void) | 2507 | Job_Finish(void) | |
2508 | { | 2508 | { | |
2509 | GNode *endNode = Targ_GetEndNode(); | 2509 | GNode *endNode = Targ_GetEndNode(); | |
2510 | if (!Lst_IsEmpty(endNode->commands) || !Lst_IsEmpty(endNode->children)) { | 2510 | if (!Lst_IsEmpty(endNode->commands) || !Lst_IsEmpty(endNode->children)) { | |
2511 | if (errors) { | 2511 | if (errors) { | |
2512 | Error("Errors reported so .END ignored"); | 2512 | Error("Errors reported so .END ignored"); | |
2513 | } else { | 2513 | } else { | |
2514 | JobRun(endNode); | 2514 | JobRun(endNode); | |
2515 | } | 2515 | } | |
2516 | } | 2516 | } | |
2517 | return errors; | 2517 | return errors; | |
2518 | } | 2518 | } | |
2519 | 2519 | |||
2520 | /* Clean up any memory used by the jobs module. */ | 2520 | /* Clean up any memory used by the jobs module. */ | |
2521 | void | 2521 | void | |
2522 | Job_End(void) | 2522 | Job_End(void) | |
2523 | { | 2523 | { | |
2524 | #ifdef CLEANUP | 2524 | #ifdef CLEANUP | |
2525 | free(shellArgv); | 2525 | free(shellArgv); | |
2526 | #endif | 2526 | #endif | |
2527 | } | 2527 | } | |
2528 | 2528 | |||
2529 | /* Waits for all running jobs to finish and returns. | 2529 | /* Waits for all running jobs to finish and returns. | |
2530 | * Sets 'aborting' to ABORT_WAIT to prevent other jobs from starting. */ | 2530 | * Sets 'aborting' to ABORT_WAIT to prevent other jobs from starting. */ | |
2531 | void | 2531 | void | |
2532 | Job_Wait(void) | 2532 | Job_Wait(void) | |
2533 | { | 2533 | { | |
2534 | aborting = ABORT_WAIT; | 2534 | aborting = ABORT_WAIT; | |
2535 | while (jobTokensRunning != 0) { | 2535 | while (jobTokensRunning != 0) { | |
2536 | Job_CatchOutput(); | 2536 | Job_CatchOutput(); | |
2537 | } | 2537 | } | |
2538 | aborting = ABORT_NONE; | 2538 | aborting = ABORT_NONE; | |
2539 | } | 2539 | } | |
2540 | 2540 | |||
2541 | /* Abort all currently running jobs without handling output or anything. | 2541 | /* Abort all currently running jobs without handling output or anything. | |
2542 | * This function is to be called only in the event of a major error. | 2542 | * This function is to be called only in the event of a major error. | |
2543 | * Most definitely NOT to be called from JobInterrupt. | 2543 | * Most definitely NOT to be called from JobInterrupt. | |
2544 | * | 2544 | * | |
2545 | * All children are killed, not just the firstborn. */ | 2545 | * All children are killed, not just the firstborn. */ | |
2546 | void | 2546 | void | |
2547 | Job_AbortAll(void) | 2547 | Job_AbortAll(void) | |
2548 | { | 2548 | { | |
2549 | Job *job; /* the job descriptor in that element */ | 2549 | Job *job; /* the job descriptor in that element */ | |
2550 | int foo; | 2550 | int foo; | |
2551 | 2551 | |||
2552 | aborting = ABORT_ERROR; | 2552 | aborting = ABORT_ERROR; | |
2553 | 2553 | |||
2554 | if (jobTokensRunning) { | 2554 | if (jobTokensRunning) { | |
2555 | for (job = job_table; job < job_table_end; job++) { | 2555 | for (job = job_table; job < job_table_end; job++) { | |
2556 | if (job->job_state != JOB_ST_RUNNING) | 2556 | if (job->job_state != JOB_ST_RUNNING) | |
2557 | continue; | 2557 | continue; | |
2558 | /* | 2558 | /* | |
2559 | * kill the child process with increasingly drastic signals to make | 2559 | * kill the child process with increasingly drastic signals to make | |
2560 | * darn sure it's dead. | 2560 | * darn sure it's dead. | |
2561 | */ | 2561 | */ | |
2562 | KILLPG(job->pid, SIGINT); | 2562 | KILLPG(job->pid, SIGINT); | |
2563 | KILLPG(job->pid, SIGKILL); | 2563 | KILLPG(job->pid, SIGKILL); | |
2564 | } | 2564 | } | |
2565 | } | 2565 | } | |
2566 | 2566 | |||
2567 | /* | 2567 | /* | |
2568 | * Catch as many children as want to report in at first, then give up | 2568 | * Catch as many children as want to report in at first, then give up | |
2569 | */ | 2569 | */ | |
2570 | while (waitpid((pid_t) -1, &foo, WNOHANG) > 0) | 2570 | while (waitpid((pid_t) -1, &foo, WNOHANG) > 0) | |
2571 | continue; | 2571 | continue; | |
2572 | } | 2572 | } | |
2573 | 2573 | |||
2574 | /* Tries to restart stopped jobs if there are slots available. | 2574 | /* Tries to restart stopped jobs if there are slots available. | |
2575 | * Called in process context in response to a SIGCONT. */ | 2575 | * Called in process context in response to a SIGCONT. */ | |
2576 | static void | 2576 | static void | |
2577 | JobRestartJobs(void) | 2577 | JobRestartJobs(void) | |
2578 | { | 2578 | { | |
2579 | Job *job; | 2579 | Job *job; | |
2580 | 2580 | |||
2581 | for (job = job_table; job < job_table_end; job++) { | 2581 | for (job = job_table; job < job_table_end; job++) { | |
2582 | if (job->job_state == JOB_ST_RUNNING && | 2582 | if (job->job_state == JOB_ST_RUNNING && | |
2583 | (make_suspended || job->job_suspended)) { | 2583 | (make_suspended || job->job_suspended)) { | |
2584 | DEBUG1(JOB, "Restarting stopped job pid %d.\n", job->pid); | 2584 | DEBUG1(JOB, "Restarting stopped job pid %d.\n", job->pid); | |
2585 | if (job->job_suspended) { | 2585 | if (job->job_suspended) { | |
2586 | (void)printf("*** [%s] Continued\n", job->node->name); | 2586 | (void)printf("*** [%s] Continued\n", job->node->name); | |
2587 | (void)fflush(stdout); | 2587 | (void)fflush(stdout); | |
2588 | } | 2588 | } | |
2589 | job->job_suspended = 0; | 2589 | job->job_suspended = 0; | |
2590 | if (KILLPG(job->pid, SIGCONT) != 0 && DEBUG(JOB)) { | 2590 | if (KILLPG(job->pid, SIGCONT) != 0 && DEBUG(JOB)) { | |
2591 | debug_printf("Failed to send SIGCONT to %d\n", job->pid); | 2591 | debug_printf("Failed to send SIGCONT to %d\n", job->pid); | |
2592 | } | 2592 | } | |
2593 | } | 2593 | } | |
2594 | if (job->job_state == JOB_ST_FINISHED) | 2594 | if (job->job_state == JOB_ST_FINISHED) | |
2595 | /* Job exit deferred after calling waitpid() in a signal handler */ | 2595 | /* Job exit deferred after calling waitpid() in a signal handler */ | |
2596 | JobFinish(job, job->exit_status); | 2596 | JobFinish(job, job->exit_status); | |
2597 | } | 2597 | } | |
2598 | make_suspended = 0; | 2598 | make_suspended = 0; | |
2599 | } | 2599 | } | |
2600 | 2600 | |||
2601 | static void | 2601 | static void | |
2602 | watchfd(Job *job) | 2602 | watchfd(Job *job) |
--- src/usr.bin/make/make.c 2020/10/31 18:41:07 1.185
+++ src/usr.bin/make/make.c 2020/11/01 17:47:26 1.186
@@ -1,1361 +1,1361 @@ | @@ -1,1361 +1,1361 @@ | |||
1 | /* $NetBSD: make.c,v 1.185 2020/10/31 18:41:07 rillig Exp $ */ | 1 | /* $NetBSD: make.c,v 1.186 2020/11/01 17:47:26 rillig Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 1988, 1989, 1990, 1993 | 4 | * Copyright (c) 1988, 1989, 1990, 1993 | |
5 | * The Regents of the University of California. All rights reserved. | 5 | * The Regents of the University of California. All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to Berkeley by | 7 | * This code is derived from software contributed to Berkeley by | |
8 | * Adam de Boor. | 8 | * Adam de Boor. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | 15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | 16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | 17 | * documentation and/or other materials provided with the distribution. | |
18 | * 3. Neither the name of the University nor the names of its contributors | 18 | * 3. Neither the name of the University nor the names of its contributors | |
19 | * may be used to endorse or promote products derived from this software | 19 | * may be used to endorse or promote products derived from this software | |
20 | * without specific prior written permission. | 20 | * without specific prior written permission. | |
21 | * | 21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
32 | * SUCH DAMAGE. | 32 | * SUCH DAMAGE. | |
33 | */ | 33 | */ | |
34 | 34 | |||
35 | /* | 35 | /* | |
36 | * Copyright (c) 1989 by Berkeley Softworks | 36 | * Copyright (c) 1989 by Berkeley Softworks | |
37 | * All rights reserved. | 37 | * All rights reserved. | |
38 | * | 38 | * | |
39 | * This code is derived from software contributed to Berkeley by | 39 | * This code is derived from software contributed to Berkeley by | |
40 | * Adam de Boor. | 40 | * Adam de Boor. | |
41 | * | 41 | * | |
42 | * Redistribution and use in source and binary forms, with or without | 42 | * Redistribution and use in source and binary forms, with or without | |
43 | * modification, are permitted provided that the following conditions | 43 | * modification, are permitted provided that the following conditions | |
44 | * are met: | 44 | * are met: | |
45 | * 1. Redistributions of source code must retain the above copyright | 45 | * 1. Redistributions of source code must retain the above copyright | |
46 | * notice, this list of conditions and the following disclaimer. | 46 | * notice, this list of conditions and the following disclaimer. | |
47 | * 2. Redistributions in binary form must reproduce the above copyright | 47 | * 2. Redistributions in binary form must reproduce the above copyright | |
48 | * notice, this list of conditions and the following disclaimer in the | 48 | * notice, this list of conditions and the following disclaimer in the | |
49 | * documentation and/or other materials provided with the distribution. | 49 | * documentation and/or other materials provided with the distribution. | |
50 | * 3. All advertising materials mentioning features or use of this software | 50 | * 3. All advertising materials mentioning features or use of this software | |
51 | * must display the following acknowledgement: | 51 | * must display the following acknowledgement: | |
52 | * This product includes software developed by the University of | 52 | * This product includes software developed by the University of | |
53 | * California, Berkeley and its contributors. | 53 | * California, Berkeley and its contributors. | |
54 | * 4. Neither the name of the University nor the names of its contributors | 54 | * 4. Neither the name of the University nor the names of its contributors | |
55 | * may be used to endorse or promote products derived from this software | 55 | * may be used to endorse or promote products derived from this software | |
56 | * without specific prior written permission. | 56 | * without specific prior written permission. | |
57 | * | 57 | * | |
58 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 58 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
59 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 59 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
60 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 60 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
61 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 61 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
62 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 62 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
63 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 63 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
64 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 64 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
65 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 65 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
66 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 66 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
67 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 67 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
68 | * SUCH DAMAGE. | 68 | * SUCH DAMAGE. | |
69 | */ | 69 | */ | |
70 | 70 | |||
71 | /*- | 71 | /*- | |
72 | * make.c -- | 72 | * make.c -- | |
73 | * The functions which perform the examination of targets and | 73 | * The functions which perform the examination of targets and | |
74 | * their suitability for creation | 74 | * their suitability for creation | |
75 | * | 75 | * | |
76 | * Interface: | 76 | * Interface: | |
77 | * Make_Run Initialize things for the module and recreate | 77 | * Make_Run Initialize things for the module and recreate | |
78 | * whatever needs recreating. Returns TRUE if | 78 | * whatever needs recreating. Returns TRUE if | |
79 | * work was (or would have been) done and FALSE | 79 | * work was (or would have been) done and FALSE | |
80 | * otherwise. | 80 | * otherwise. | |
81 | * | 81 | * | |
82 | * Make_Update Update all parents of a given child. Performs | 82 | * Make_Update Update all parents of a given child. Performs | |
83 | * various bookkeeping chores like the updating | 83 | * various bookkeeping chores like the updating | |
84 | * of the youngestChild field of the parent, filling | 84 | * of the youngestChild field of the parent, filling | |
85 | * of the IMPSRC context variable, etc. It will | 85 | * of the IMPSRC context variable, etc. It will | |
86 | * place the parent on the toBeMade queue if it | 86 | * place the parent on the toBeMade queue if it | |
87 | * should be. | 87 | * should be. | |
88 | * | 88 | * | |
89 | * Make_TimeStamp Function to set the parent's youngestChild field | 89 | * Make_TimeStamp Function to set the parent's youngestChild field | |
90 | * based on a child's modification time. | 90 | * based on a child's modification time. | |
91 | * | 91 | * | |
92 | * Make_DoAllVar Set up the various local variables for a | 92 | * Make_DoAllVar Set up the various local variables for a | |
93 | * target, including the .ALLSRC variable, making | 93 | * target, including the .ALLSRC variable, making | |
94 | * sure that any variable that needs to exist | 94 | * sure that any variable that needs to exist | |
95 | * at the very least has the empty value. | 95 | * at the very least has the empty value. | |
96 | * | 96 | * | |
97 | * Make_OODate Determine if a target is out-of-date. | 97 | * Make_OODate Determine if a target is out-of-date. | |
98 | * | 98 | * | |
99 | * Make_HandleUse See if a child is a .USE node for a parent | 99 | * Make_HandleUse See if a child is a .USE node for a parent | |
100 | * and perform the .USE actions if so. | 100 | * and perform the .USE actions if so. | |
101 | * | 101 | * | |
102 | * Make_ExpandUse Expand .USE nodes | 102 | * Make_ExpandUse Expand .USE nodes | |
103 | */ | 103 | */ | |
104 | 104 | |||
105 | #include "make.h" | 105 | #include "make.h" | |
106 | #include "dir.h" | 106 | #include "dir.h" | |
107 | #include "job.h" | 107 | #include "job.h" | |
108 | 108 | |||
109 | /* "@(#)make.c 8.1 (Berkeley) 6/6/93" */ | 109 | /* "@(#)make.c 8.1 (Berkeley) 6/6/93" */ | |
110 | MAKE_RCSID("$NetBSD: make.c,v 1.185 2020/10/31 18:41:07 rillig Exp $"); | 110 | MAKE_RCSID("$NetBSD: make.c,v 1.186 2020/11/01 17:47:26 rillig Exp $"); | |
111 | 111 | |||
112 | /* Sequence # to detect recursion. */ | 112 | /* Sequence # to detect recursion. */ | |
113 | static unsigned int checked = 1; | 113 | static unsigned int checked = 1; | |
114 | 114 | |||
115 | /* The current fringe of the graph. | 115 | /* The current fringe of the graph. | |
116 | * These are nodes which await examination by MakeOODate. | 116 | * These are nodes which await examination by MakeOODate. | |
117 | * It is added to by Make_Update and subtracted from by MakeStartJobs */ | 117 | * It is added to by Make_Update and subtracted from by MakeStartJobs */ | |
118 | static GNodeList *toBeMade; | 118 | static GNodeList *toBeMade; | |
119 | 119 | |||
120 | static int MakeCheckOrder(void *, void *); | 120 | static int MakeCheckOrder(void *, void *); | |
121 | static int MakeBuildParent(void *, void *); | 121 | static int MakeBuildParent(void *, void *); | |
122 | 122 | |||
123 | void | 123 | void | |
124 | debug_printf(const char *fmt, ...) | 124 | debug_printf(const char *fmt, ...) | |
125 | { | 125 | { | |
126 | va_list args; | 126 | va_list args; | |
127 | 127 | |||
128 | va_start(args, fmt); | 128 | va_start(args, fmt); | |
129 | vfprintf(opts.debug_file, fmt, args); | 129 | vfprintf(opts.debug_file, fmt, args); | |
130 | va_end(args); | 130 | va_end(args); | |
131 | } | 131 | } | |
132 | 132 | |||
133 | MAKE_ATTR_DEAD static void | 133 | MAKE_ATTR_DEAD static void | |
134 | make_abort(GNode *gn, int line) | 134 | make_abort(GNode *gn, int line) | |
135 | { | 135 | { | |
136 | debug_printf("make_abort from line %d\n", line); | 136 | debug_printf("make_abort from line %d\n", line); | |
137 | Targ_PrintNode(gn, 2); | 137 | Targ_PrintNode(gn, 2); | |
138 | Targ_PrintNodes(toBeMade, 2); | 138 | Targ_PrintNodes(toBeMade, 2); | |
139 | Targ_PrintGraph(3); | 139 | Targ_PrintGraph(3); | |
140 | abort(); | 140 | abort(); | |
141 | } | 141 | } | |
142 | 142 | |||
143 | ENUM_VALUE_RTTI_8(GNodeMade, | 143 | ENUM_VALUE_RTTI_8(GNodeMade, | |
144 | UNMADE, DEFERRED, REQUESTED, BEINGMADE, | 144 | UNMADE, DEFERRED, REQUESTED, BEINGMADE, | |
145 | MADE, UPTODATE, ERROR, ABORTED); | 145 | MADE, UPTODATE, ERROR, ABORTED); | |
146 | 146 | |||
147 | ENUM_FLAGS_RTTI_31(GNodeType, | 147 | ENUM_FLAGS_RTTI_31(GNodeType, | |
148 | OP_DEPENDS, OP_FORCE, OP_DOUBLEDEP, | 148 | OP_DEPENDS, OP_FORCE, OP_DOUBLEDEP, | |
149 | /* OP_OPMASK is omitted since it combines other flags */ | 149 | /* OP_OPMASK is omitted since it combines other flags */ | |
150 | OP_OPTIONAL, OP_USE, OP_EXEC, OP_IGNORE, | 150 | OP_OPTIONAL, OP_USE, OP_EXEC, OP_IGNORE, | |
151 | OP_PRECIOUS, OP_SILENT, OP_MAKE, OP_JOIN, | 151 | OP_PRECIOUS, OP_SILENT, OP_MAKE, OP_JOIN, | |
152 | OP_MADE, OP_SPECIAL, OP_USEBEFORE, OP_INVISIBLE, | 152 | OP_MADE, OP_SPECIAL, OP_USEBEFORE, OP_INVISIBLE, | |
153 | OP_NOTMAIN, OP_PHONY, OP_NOPATH, OP_WAIT, | 153 | OP_NOTMAIN, OP_PHONY, OP_NOPATH, OP_WAIT, | |
154 | OP_NOMETA, OP_META, OP_NOMETA_CMP, OP_SUBMAKE, | 154 | OP_NOMETA, OP_META, OP_NOMETA_CMP, OP_SUBMAKE, | |
155 | OP_TRANSFORM, OP_MEMBER, OP_LIB, OP_ARCHV, | 155 | OP_TRANSFORM, OP_MEMBER, OP_LIB, OP_ARCHV, | |
156 | OP_HAS_COMMANDS, OP_SAVE_CMDS, OP_DEPS_FOUND, OP_MARK); | 156 | OP_HAS_COMMANDS, OP_SAVE_CMDS, OP_DEPS_FOUND, OP_MARK); | |
157 | 157 | |||
158 | ENUM_FLAGS_RTTI_10(GNodeFlags, | 158 | ENUM_FLAGS_RTTI_10(GNodeFlags, | |
159 | REMAKE, CHILDMADE, FORCE, DONE_WAIT, | 159 | REMAKE, CHILDMADE, FORCE, DONE_WAIT, | |
160 | DONE_ORDER, FROM_DEPEND, DONE_ALLSRC, CYCLE, | 160 | DONE_ORDER, FROM_DEPEND, DONE_ALLSRC, CYCLE, | |
161 | DONECYCLE, INTERNAL); | 161 | DONECYCLE, INTERNAL); | |
162 | 162 | |||
163 | void | 163 | void | |
164 | GNode_FprintDetails(FILE *f, const char *prefix, const GNode *gn, | 164 | GNode_FprintDetails(FILE *f, const char *prefix, const GNode *gn, | |
165 | const char *suffix) | 165 | const char *suffix) | |
166 | { | 166 | { | |
167 | char type_buf[GNodeType_ToStringSize]; | 167 | char type_buf[GNodeType_ToStringSize]; | |
168 | char flags_buf[GNodeFlags_ToStringSize]; | 168 | char flags_buf[GNodeFlags_ToStringSize]; | |
169 | 169 | |||
170 | fprintf(f, "%smade %s, type %s, flags %s%s", | 170 | fprintf(f, "%smade %s, type %s, flags %s%s", | |
171 | prefix, | 171 | prefix, | |
172 | Enum_ValueToString(gn->made, GNodeMade_ToStringSpecs), | 172 | Enum_ValueToString(gn->made, GNodeMade_ToStringSpecs), | |
173 | Enum_FlagsToString(type_buf, sizeof type_buf, | 173 | Enum_FlagsToString(type_buf, sizeof type_buf, | |
174 | gn->type, GNodeType_ToStringSpecs), | 174 | gn->type, GNodeType_ToStringSpecs), | |
175 | Enum_FlagsToString(flags_buf, sizeof flags_buf, | 175 | Enum_FlagsToString(flags_buf, sizeof flags_buf, | |
176 | gn->flags, GNodeFlags_ToStringSpecs), | 176 | gn->flags, GNodeFlags_ToStringSpecs), | |
177 | suffix); | 177 | suffix); | |
178 | } | 178 | } | |
179 | 179 | |||
180 | Boolean | 180 | Boolean | |
181 | NoExecute(GNode *gn) | 181 | GNode_ShouldExecute(GNode *gn) | |
182 | { | 182 | { | |
183 | return (gn->type & OP_MAKE) ? opts.noRecursiveExecute : opts.noExecute; | 183 | return !((gn->type & OP_MAKE) ? opts.noRecursiveExecute : opts.noExecute); | |
184 | } | 184 | } | |
185 | 185 | |||
186 | /* Update the youngest child of the node, according to the given child. */ | 186 | /* Update the youngest child of the node, according to the given child. */ | |
187 | void | 187 | void | |
188 | Make_TimeStamp(GNode *pgn, GNode *cgn) | 188 | Make_TimeStamp(GNode *pgn, GNode *cgn) | |
189 | { | 189 | { | |
190 | if (pgn->youngestChild == NULL || cgn->mtime > pgn->youngestChild->mtime) { | 190 | if (pgn->youngestChild == NULL || cgn->mtime > pgn->youngestChild->mtime) { | |
191 | pgn->youngestChild = cgn; | 191 | pgn->youngestChild = cgn; | |
192 | } | 192 | } | |
193 | } | 193 | } | |
194 | 194 | |||
195 | /* See if the node is out of date with respect to its sources. | 195 | /* See if the node is out of date with respect to its sources. | |
196 | * | 196 | * | |
197 | * Used by Make_Run when deciding which nodes to place on the | 197 | * Used by Make_Run when deciding which nodes to place on the | |
198 | * toBeMade queue initially and by Make_Update to screen out .USE and | 198 | * toBeMade queue initially and by Make_Update to screen out .USE and | |
199 | * .EXEC nodes. In the latter case, however, any other sort of node | 199 | * .EXEC nodes. In the latter case, however, any other sort of node | |
200 | * must be considered out-of-date since at least one of its children | 200 | * must be considered out-of-date since at least one of its children | |
201 | * will have been recreated. | 201 | * will have been recreated. | |
202 | * | 202 | * | |
203 | * The mtime field of the node and the youngestChild field of its parents | 203 | * The mtime field of the node and the youngestChild field of its parents | |
204 | * may be changed. | 204 | * may be changed. | |
205 | */ | 205 | */ | |
206 | Boolean | 206 | Boolean | |
207 | Make_OODate(GNode *gn) | 207 | Make_OODate(GNode *gn) | |
208 | { | 208 | { | |
209 | Boolean oodate; | 209 | Boolean oodate; | |
210 | 210 | |||
211 | /* | 211 | /* | |
212 | * Certain types of targets needn't even be sought as their datedness | 212 | * Certain types of targets needn't even be sought as their datedness | |
213 | * doesn't depend on their modification time... | 213 | * doesn't depend on their modification time... | |
214 | */ | 214 | */ | |
215 | if ((gn->type & (OP_JOIN|OP_USE|OP_USEBEFORE|OP_EXEC)) == 0) { | 215 | if ((gn->type & (OP_JOIN|OP_USE|OP_USEBEFORE|OP_EXEC)) == 0) { | |
216 | (void)Dir_MTime(gn, 1); | 216 | (void)Dir_MTime(gn, 1); | |
217 | if (DEBUG(MAKE)) { | 217 | if (DEBUG(MAKE)) { | |
218 | if (gn->mtime != 0) { | 218 | if (gn->mtime != 0) { | |
219 | debug_printf("modified %s...", Targ_FmtTime(gn->mtime)); | 219 | debug_printf("modified %s...", Targ_FmtTime(gn->mtime)); | |
220 | } else { | 220 | } else { | |
221 | debug_printf("non-existent..."); | 221 | debug_printf("non-existent..."); | |
222 | } | 222 | } | |
223 | } | 223 | } | |
224 | } | 224 | } | |
225 | 225 | |||
226 | /* | 226 | /* | |
227 | * A target is remade in one of the following circumstances: | 227 | * A target is remade in one of the following circumstances: | |
228 | * its modification time is smaller than that of its youngest child and | 228 | * its modification time is smaller than that of its youngest child and | |
229 | * it would actually be run (has commands or is not GNode_IsTarget) | 229 | * it would actually be run (has commands or is not GNode_IsTarget) | |
230 | * it's the object of a force operator | 230 | * it's the object of a force operator | |
231 | * it has no children, was on the lhs of an operator and doesn't exist | 231 | * it has no children, was on the lhs of an operator and doesn't exist | |
232 | * already. | 232 | * already. | |
233 | * | 233 | * | |
234 | * Libraries are only considered out-of-date if the archive module says | 234 | * Libraries are only considered out-of-date if the archive module says | |
235 | * they are. | 235 | * they are. | |
236 | * | 236 | * | |
237 | * These weird rules are brought to you by Backward-Compatibility and | 237 | * These weird rules are brought to you by Backward-Compatibility and | |
238 | * the strange people who wrote 'Make'. | 238 | * the strange people who wrote 'Make'. | |
239 | */ | 239 | */ | |
240 | if (gn->type & (OP_USE|OP_USEBEFORE)) { | 240 | if (gn->type & (OP_USE|OP_USEBEFORE)) { | |
241 | /* | 241 | /* | |
242 | * If the node is a USE node it is *never* out of date | 242 | * If the node is a USE node it is *never* out of date | |
243 | * no matter *what*. | 243 | * no matter *what*. | |
244 | */ | 244 | */ | |
245 | DEBUG0(MAKE, ".USE node..."); | 245 | DEBUG0(MAKE, ".USE node..."); | |
246 | oodate = FALSE; | 246 | oodate = FALSE; | |
247 | } else if ((gn->type & OP_LIB) && | 247 | } else if ((gn->type & OP_LIB) && | |
248 | ((gn->mtime==0) || Arch_IsLib(gn))) { | 248 | ((gn->mtime==0) || Arch_IsLib(gn))) { | |
249 | DEBUG0(MAKE, "library..."); | 249 | DEBUG0(MAKE, "library..."); | |
250 | 250 | |||
251 | /* | 251 | /* | |
252 | * always out of date if no children and :: target | 252 | * always out of date if no children and :: target | |
253 | * or non-existent. | 253 | * or non-existent. | |
254 | */ | 254 | */ | |
255 | oodate = (gn->mtime == 0 || Arch_LibOODate(gn) || | 255 | oodate = (gn->mtime == 0 || Arch_LibOODate(gn) || | |
256 | (gn->youngestChild == NULL && (gn->type & OP_DOUBLEDEP))); | 256 | (gn->youngestChild == NULL && (gn->type & OP_DOUBLEDEP))); | |
257 | } else if (gn->type & OP_JOIN) { | 257 | } else if (gn->type & OP_JOIN) { | |
258 | /* | 258 | /* | |
259 | * A target with the .JOIN attribute is only considered | 259 | * A target with the .JOIN attribute is only considered | |
260 | * out-of-date if any of its children was out-of-date. | 260 | * out-of-date if any of its children was out-of-date. | |
261 | */ | 261 | */ | |
262 | DEBUG0(MAKE, ".JOIN node..."); | 262 | DEBUG0(MAKE, ".JOIN node..."); | |
263 | DEBUG1(MAKE, "source %smade...", gn->flags & CHILDMADE ? "" : "not "); | 263 | DEBUG1(MAKE, "source %smade...", gn->flags & CHILDMADE ? "" : "not "); | |
264 | oodate = (gn->flags & CHILDMADE) ? TRUE : FALSE; | 264 | oodate = (gn->flags & CHILDMADE) ? TRUE : FALSE; | |
265 | } else if (gn->type & (OP_FORCE|OP_EXEC|OP_PHONY)) { | 265 | } else if (gn->type & (OP_FORCE|OP_EXEC|OP_PHONY)) { | |
266 | /* | 266 | /* | |
267 | * A node which is the object of the force (!) operator or which has | 267 | * A node which is the object of the force (!) operator or which has | |
268 | * the .EXEC attribute is always considered out-of-date. | 268 | * the .EXEC attribute is always considered out-of-date. | |
269 | */ | 269 | */ | |
270 | if (DEBUG(MAKE)) { | 270 | if (DEBUG(MAKE)) { | |
271 | if (gn->type & OP_FORCE) { | 271 | if (gn->type & OP_FORCE) { | |
272 | debug_printf("! operator..."); | 272 | debug_printf("! operator..."); | |
273 | } else if (gn->type & OP_PHONY) { | 273 | } else if (gn->type & OP_PHONY) { | |
274 | debug_printf(".PHONY node..."); | 274 | debug_printf(".PHONY node..."); | |
275 | } else { | 275 | } else { | |
276 | debug_printf(".EXEC node..."); | 276 | debug_printf(".EXEC node..."); | |
277 | } | 277 | } | |
278 | } | 278 | } | |
279 | oodate = TRUE; | 279 | oodate = TRUE; | |
280 | } else if ((gn->youngestChild != NULL && | 280 | } else if ((gn->youngestChild != NULL && | |
281 | gn->mtime < gn->youngestChild->mtime) || | 281 | gn->mtime < gn->youngestChild->mtime) || | |
282 | (gn->youngestChild == NULL && | 282 | (gn->youngestChild == NULL && | |
283 | ((gn->mtime == 0 && !(gn->type & OP_OPTIONAL)) | 283 | ((gn->mtime == 0 && !(gn->type & OP_OPTIONAL)) | |
284 | || gn->type & OP_DOUBLEDEP))) | 284 | || gn->type & OP_DOUBLEDEP))) | |
285 | { | 285 | { | |
286 | /* | 286 | /* | |
287 | * A node whose modification time is less than that of its | 287 | * A node whose modification time is less than that of its | |
288 | * youngest child or that has no children (youngestChild == NULL) and | 288 | * youngest child or that has no children (youngestChild == NULL) and | |
289 | * either doesn't exist (mtime == 0) and it isn't optional | 289 | * either doesn't exist (mtime == 0) and it isn't optional | |
290 | * or was the object of a * :: operator is out-of-date. | 290 | * or was the object of a * :: operator is out-of-date. | |
291 | * Why? Because that's the way Make does it. | 291 | * Why? Because that's the way Make does it. | |
292 | */ | 292 | */ | |
293 | if (DEBUG(MAKE)) { | 293 | if (DEBUG(MAKE)) { | |
294 | if (gn->youngestChild != NULL && | 294 | if (gn->youngestChild != NULL && | |
295 | gn->mtime < gn->youngestChild->mtime) { | 295 | gn->mtime < gn->youngestChild->mtime) { | |
296 | debug_printf("modified before source %s...", | 296 | debug_printf("modified before source %s...", | |
297 | GNode_Path(gn->youngestChild)); | 297 | GNode_Path(gn->youngestChild)); | |
298 | } else if (gn->mtime == 0) { | 298 | } else if (gn->mtime == 0) { | |
299 | debug_printf("non-existent and no sources..."); | 299 | debug_printf("non-existent and no sources..."); | |
300 | } else { | 300 | } else { | |
301 | debug_printf(":: operator and no sources..."); | 301 | debug_printf(":: operator and no sources..."); | |
302 | } | 302 | } | |
303 | } | 303 | } | |
304 | oodate = TRUE; | 304 | oodate = TRUE; | |
305 | } else { | 305 | } else { | |
306 | /* | 306 | /* | |
307 | * When a non-existing child with no sources | 307 | * When a non-existing child with no sources | |
308 | * (such as a typically used FORCE source) has been made and | 308 | * (such as a typically used FORCE source) has been made and | |
309 | * the target of the child (usually a directory) has the same | 309 | * the target of the child (usually a directory) has the same | |
310 | * timestamp as the timestamp just given to the non-existing child | 310 | * timestamp as the timestamp just given to the non-existing child | |
311 | * after it was considered made. | 311 | * after it was considered made. | |
312 | */ | 312 | */ | |
313 | if (DEBUG(MAKE)) { | 313 | if (DEBUG(MAKE)) { | |
314 | if (gn->flags & FORCE) | 314 | if (gn->flags & FORCE) | |
315 | debug_printf("non existing child..."); | 315 | debug_printf("non existing child..."); | |
316 | } | 316 | } | |
317 | oodate = (gn->flags & FORCE) ? TRUE : FALSE; | 317 | oodate = (gn->flags & FORCE) ? TRUE : FALSE; | |
318 | } | 318 | } | |
319 | 319 | |||
320 | #ifdef USE_META | 320 | #ifdef USE_META | |
321 | if (useMeta) { | 321 | if (useMeta) { | |
322 | oodate = meta_oodate(gn, oodate); | 322 | oodate = meta_oodate(gn, oodate); | |
323 | } | 323 | } | |
324 | #endif | 324 | #endif | |
325 | 325 | |||
326 | /* | 326 | /* | |
327 | * If the target isn't out-of-date, the parents need to know its | 327 | * If the target isn't out-of-date, the parents need to know its | |
328 | * modification time. Note that targets that appear to be out-of-date | 328 | * modification time. Note that targets that appear to be out-of-date | |
329 | * but aren't, because they have no commands and are GNode_IsTarget, | 329 | * but aren't, because they have no commands and are GNode_IsTarget, | |
330 | * have their mtime stay below their children's mtime to keep parents from | 330 | * have their mtime stay below their children's mtime to keep parents from | |
331 | * thinking they're out-of-date. | 331 | * thinking they're out-of-date. | |
332 | */ | 332 | */ | |
333 | if (!oodate) { | 333 | if (!oodate) { | |
334 | GNodeListNode *ln; | 334 | GNodeListNode *ln; | |
335 | for (ln = gn->parents->first; ln != NULL; ln = ln->next) | 335 | for (ln = gn->parents->first; ln != NULL; ln = ln->next) | |
336 | Make_TimeStamp(ln->datum, gn); | 336 | Make_TimeStamp(ln->datum, gn); | |
337 | } | 337 | } | |
338 | 338 | |||
339 | return oodate; | 339 | return oodate; | |
340 | } | 340 | } | |
341 | 341 | |||
342 | /* Add the node to the list if it needs to be examined. */ | 342 | /* Add the node to the list if it needs to be examined. */ | |
343 | static int | 343 | static int | |
344 | MakeAddChild(void *gnp, void *lp) | 344 | MakeAddChild(void *gnp, void *lp) | |
345 | { | 345 | { | |
346 | GNode *gn = gnp; | 346 | GNode *gn = gnp; | |
347 | GNodeList *l = lp; | 347 | GNodeList *l = lp; | |
348 | 348 | |||
349 | if ((gn->flags & REMAKE) == 0 && !(gn->type & (OP_USE|OP_USEBEFORE))) { | 349 | if ((gn->flags & REMAKE) == 0 && !(gn->type & (OP_USE|OP_USEBEFORE))) { | |
350 | DEBUG2(MAKE, "MakeAddChild: need to examine %s%s\n", | 350 | DEBUG2(MAKE, "MakeAddChild: need to examine %s%s\n", | |
351 | gn->name, gn->cohort_num); | 351 | gn->name, gn->cohort_num); | |
352 | Lst_Enqueue(l, gn); | 352 | Lst_Enqueue(l, gn); | |
353 | } | 353 | } | |
354 | return 0; | 354 | return 0; | |
355 | } | 355 | } | |
356 | 356 | |||
357 | /* Find the pathname of a child that was already made. | 357 | /* Find the pathname of a child that was already made. | |
358 | * | 358 | * | |
359 | * The path and mtime of the node and the youngestChild of the parent are | 359 | * The path and mtime of the node and the youngestChild of the parent are | |
360 | * updated; the unmade children count of the parent is decremented. | 360 | * updated; the unmade children count of the parent is decremented. | |
361 | * | 361 | * | |
362 | * Input: | 362 | * Input: | |
363 | * gnp the node to find | 363 | * gnp the node to find | |
364 | */ | 364 | */ | |
365 | static int | 365 | static int | |
366 | MakeFindChild(void *gnp, void *pgnp) | 366 | MakeFindChild(void *gnp, void *pgnp) | |
367 | { | 367 | { | |
368 | GNode *gn = gnp; | 368 | GNode *gn = gnp; | |
369 | GNode *pgn = pgnp; | 369 | GNode *pgn = pgnp; | |
370 | 370 | |||
371 | (void)Dir_MTime(gn, 0); | 371 | (void)Dir_MTime(gn, 0); | |
372 | Make_TimeStamp(pgn, gn); | 372 | Make_TimeStamp(pgn, gn); | |
373 | pgn->unmade--; | 373 | pgn->unmade--; | |
374 | 374 | |||
375 | return 0; | 375 | return 0; | |
376 | } | 376 | } | |
377 | 377 | |||
378 | /* Called by Make_Run and SuffApplyTransform on the downward pass to handle | 378 | /* Called by Make_Run and SuffApplyTransform on the downward pass to handle | |
379 | * .USE and transformation nodes, by copying the child node's commands, type | 379 | * .USE and transformation nodes, by copying the child node's commands, type | |
380 | * flags and children to the parent node. | 380 | * flags and children to the parent node. | |
381 | * | 381 | * | |
382 | * A .USE node is much like an explicit transformation rule, except its | 382 | * A .USE node is much like an explicit transformation rule, except its | |
383 | * commands are always added to the target node, even if the target already | 383 | * commands are always added to the target node, even if the target already | |
384 | * has commands. | 384 | * has commands. | |
385 | * | 385 | * | |
386 | * Input: | 386 | * Input: | |
387 | * cgn The source node, which is either a .USE/.USEBEFORE | 387 | * cgn The source node, which is either a .USE/.USEBEFORE | |
388 | * node or a transformation node (OP_TRANSFORM). | 388 | * node or a transformation node (OP_TRANSFORM). | |
389 | * pgn The target node | 389 | * pgn The target node | |
390 | */ | 390 | */ | |
391 | void | 391 | void | |
392 | Make_HandleUse(GNode *cgn, GNode *pgn) | 392 | Make_HandleUse(GNode *cgn, GNode *pgn) | |
393 | { | 393 | { | |
394 | GNodeListNode *ln; /* An element in the children list */ | 394 | GNodeListNode *ln; /* An element in the children list */ | |
395 | 395 | |||
396 | #ifdef DEBUG_SRC | 396 | #ifdef DEBUG_SRC | |
397 | if ((cgn->type & (OP_USE|OP_USEBEFORE|OP_TRANSFORM)) == 0) { | 397 | if ((cgn->type & (OP_USE|OP_USEBEFORE|OP_TRANSFORM)) == 0) { | |
398 | debug_printf("Make_HandleUse: called for plain node %s\n", cgn->name); | 398 | debug_printf("Make_HandleUse: called for plain node %s\n", cgn->name); | |
399 | return; | 399 | return; | |
400 | } | 400 | } | |
401 | #endif | 401 | #endif | |
402 | 402 | |||
403 | if ((cgn->type & (OP_USE|OP_USEBEFORE)) || Lst_IsEmpty(pgn->commands)) { | 403 | if ((cgn->type & (OP_USE|OP_USEBEFORE)) || Lst_IsEmpty(pgn->commands)) { | |
404 | if (cgn->type & OP_USEBEFORE) { | 404 | if (cgn->type & OP_USEBEFORE) { | |
405 | /* .USEBEFORE */ | 405 | /* .USEBEFORE */ | |
406 | Lst_PrependAll(pgn->commands, cgn->commands); | 406 | Lst_PrependAll(pgn->commands, cgn->commands); | |
407 | } else { | 407 | } else { | |
408 | /* .USE, or target has no commands */ | 408 | /* .USE, or target has no commands */ | |
409 | Lst_AppendAll(pgn->commands, cgn->commands); | 409 | Lst_AppendAll(pgn->commands, cgn->commands); | |
410 | } | 410 | } | |
411 | } | 411 | } | |
412 | 412 | |||
413 | for (ln = cgn->children->first; ln != NULL; ln = ln->next) { | 413 | for (ln = cgn->children->first; ln != NULL; ln = ln->next) { | |
414 | GNode *gn = ln->datum; | 414 | GNode *gn = ln->datum; | |
415 | 415 | |||
416 | /* | 416 | /* | |
417 | * Expand variables in the .USE node's name | 417 | * Expand variables in the .USE node's name | |
418 | * and save the unexpanded form. | 418 | * and save the unexpanded form. | |
419 | * We don't need to do this for commands. | 419 | * We don't need to do this for commands. | |
420 | * They get expanded properly when we execute. | 420 | * They get expanded properly when we execute. | |
421 | */ | 421 | */ | |
422 | if (gn->uname == NULL) { | 422 | if (gn->uname == NULL) { | |
423 | gn->uname = gn->name; | 423 | gn->uname = gn->name; | |
424 | } else { | 424 | } else { | |
425 | free(gn->name); | 425 | free(gn->name); | |
426 | } | 426 | } | |
427 | (void)Var_Subst(gn->uname, pgn, VARE_WANTRES, &gn->name); | 427 | (void)Var_Subst(gn->uname, pgn, VARE_WANTRES, &gn->name); | |
428 | /* TODO: handle errors */ | 428 | /* TODO: handle errors */ | |
429 | if (gn->uname && strcmp(gn->name, gn->uname) != 0) { | 429 | if (gn->uname && strcmp(gn->name, gn->uname) != 0) { | |
430 | /* See if we have a target for this node. */ | 430 | /* See if we have a target for this node. */ | |
431 | GNode *tgn = Targ_FindNode(gn->name); | 431 | GNode *tgn = Targ_FindNode(gn->name); | |
432 | if (tgn != NULL) | 432 | if (tgn != NULL) | |
433 | gn = tgn; | 433 | gn = tgn; | |
434 | } | 434 | } | |
435 | 435 | |||
436 | Lst_Append(pgn->children, gn); | 436 | Lst_Append(pgn->children, gn); | |
437 | Lst_Append(gn->parents, pgn); | 437 | Lst_Append(gn->parents, pgn); | |
438 | pgn->unmade++; | 438 | pgn->unmade++; | |
439 | } | 439 | } | |
440 | 440 | |||
441 | pgn->type |= cgn->type & ~(OP_OPMASK|OP_USE|OP_USEBEFORE|OP_TRANSFORM); | 441 | pgn->type |= cgn->type & ~(OP_OPMASK|OP_USE|OP_USEBEFORE|OP_TRANSFORM); | |
442 | } | 442 | } | |
443 | 443 | |||
444 | /* Used by Make_Run on the downward pass to handle .USE nodes. Should be | 444 | /* Used by Make_Run on the downward pass to handle .USE nodes. Should be | |
445 | * called before the children are enqueued to be looked at by MakeAddChild. | 445 | * called before the children are enqueued to be looked at by MakeAddChild. | |
446 | * | 446 | * | |
447 | * For a .USE child, the commands, type flags and children are copied to the | 447 | * For a .USE child, the commands, type flags and children are copied to the | |
448 | * parent node, and since the relation to the .USE node is then no longer | 448 | * parent node, and since the relation to the .USE node is then no longer | |
449 | * needed, that relation is removed. | 449 | * needed, that relation is removed. | |
450 | * | 450 | * | |
451 | * Input: | 451 | * Input: | |
452 | * cgn the child, which may be a .USE node | 452 | * cgn the child, which may be a .USE node | |
453 | * pgn the current parent | 453 | * pgn the current parent | |
454 | */ | 454 | */ | |
455 | static void | 455 | static void | |
456 | MakeHandleUse(GNode *cgn, GNode *pgn, GNodeListNode *ln) | 456 | MakeHandleUse(GNode *cgn, GNode *pgn, GNodeListNode *ln) | |
457 | { | 457 | { | |
458 | Boolean unmarked; | 458 | Boolean unmarked; | |
459 | 459 | |||
460 | unmarked = ((cgn->type & OP_MARK) == 0); | 460 | unmarked = ((cgn->type & OP_MARK) == 0); | |
461 | cgn->type |= OP_MARK; | 461 | cgn->type |= OP_MARK; | |
462 | 462 | |||
463 | if ((cgn->type & (OP_USE|OP_USEBEFORE)) == 0) | 463 | if ((cgn->type & (OP_USE|OP_USEBEFORE)) == 0) | |
464 | return; | 464 | return; | |
465 | 465 | |||
466 | if (unmarked) | 466 | if (unmarked) | |
467 | Make_HandleUse(cgn, pgn); | 467 | Make_HandleUse(cgn, pgn); | |
468 | 468 | |||
469 | /* | 469 | /* | |
470 | * This child node is now "made", so we decrement the count of | 470 | * This child node is now "made", so we decrement the count of | |
471 | * unmade children in the parent... We also remove the child | 471 | * unmade children in the parent... We also remove the child | |
472 | * from the parent's list to accurately reflect the number of decent | 472 | * from the parent's list to accurately reflect the number of decent | |
473 | * children the parent has. This is used by Make_Run to decide | 473 | * children the parent has. This is used by Make_Run to decide | |
474 | * whether to queue the parent or examine its children... | 474 | * whether to queue the parent or examine its children... | |
475 | */ | 475 | */ | |
476 | Lst_Remove(pgn->children, ln); | 476 | Lst_Remove(pgn->children, ln); | |
477 | pgn->unmade--; | 477 | pgn->unmade--; | |
478 | } | 478 | } | |
479 | 479 | |||
480 | static void | 480 | static void | |
481 | HandleUseNodes(GNode *gn) | 481 | HandleUseNodes(GNode *gn) | |
482 | { | 482 | { | |
483 | GNodeListNode *ln, *nln; | 483 | GNodeListNode *ln, *nln; | |
484 | for (ln = gn->children->first; ln != NULL; ln = nln) { | 484 | for (ln = gn->children->first; ln != NULL; ln = nln) { | |
485 | nln = ln->next; | 485 | nln = ln->next; | |
486 | MakeHandleUse(ln->datum, gn, ln); | 486 | MakeHandleUse(ln->datum, gn, ln); | |
487 | } | 487 | } | |
488 | } | 488 | } | |
489 | 489 | |||
490 | 490 | |||
491 | /* Check the modification time of a gnode, and update it if necessary. | 491 | /* Check the modification time of a gnode, and update it if necessary. | |
492 | * Return 0 if the gnode does not exist, or its filesystem time if it does. */ | 492 | * Return 0 if the gnode does not exist, or its filesystem time if it does. */ | |
493 | time_t | 493 | time_t | |
494 | Make_Recheck(GNode *gn) | 494 | Make_Recheck(GNode *gn) | |
495 | { | 495 | { | |
496 | time_t mtime = Dir_MTime(gn, 1); | 496 | time_t mtime = Dir_MTime(gn, 1); | |
497 | 497 | |||
498 | #ifndef RECHECK | 498 | #ifndef RECHECK | |
499 | /* | 499 | /* | |
500 | * We can't re-stat the thing, but we can at least take care of rules | 500 | * We can't re-stat the thing, but we can at least take care of rules | |
501 | * where a target depends on a source that actually creates the | 501 | * where a target depends on a source that actually creates the | |
502 | * target, but only if it has changed, e.g. | 502 | * target, but only if it has changed, e.g. | |
503 | * | 503 | * | |
504 | * parse.h : parse.o | 504 | * parse.h : parse.o | |
505 | * | 505 | * | |
506 | * parse.o : parse.y | 506 | * parse.o : parse.y | |
507 | * yacc -d parse.y | 507 | * yacc -d parse.y | |
508 | * cc -c y.tab.c | 508 | * cc -c y.tab.c | |
509 | * mv y.tab.o parse.o | 509 | * mv y.tab.o parse.o | |
510 | * cmp -s y.tab.h parse.h || mv y.tab.h parse.h | 510 | * cmp -s y.tab.h parse.h || mv y.tab.h parse.h | |
511 | * | 511 | * | |
512 | * In this case, if the definitions produced by yacc haven't changed | 512 | * In this case, if the definitions produced by yacc haven't changed | |
513 | * from before, parse.h won't have been updated and gn->mtime will | 513 | * from before, parse.h won't have been updated and gn->mtime will | |
514 | * reflect the current modification time for parse.h. This is | 514 | * reflect the current modification time for parse.h. This is | |
515 | * something of a kludge, I admit, but it's a useful one.. | 515 | * something of a kludge, I admit, but it's a useful one.. | |
516 | * XXX: People like to use a rule like | 516 | * XXX: People like to use a rule like | |
517 | * | 517 | * | |
518 | * FRC: | 518 | * FRC: | |
519 | * | 519 | * | |
520 | * To force things that depend on FRC to be made, so we have to | 520 | * To force things that depend on FRC to be made, so we have to | |
521 | * check for gn->children being empty as well... | 521 | * check for gn->children being empty as well... | |
522 | */ | 522 | */ | |
523 | if (!Lst_IsEmpty(gn->commands) || Lst_IsEmpty(gn->children)) { | 523 | if (!Lst_IsEmpty(gn->commands) || Lst_IsEmpty(gn->children)) { | |
524 | gn->mtime = now; | 524 | gn->mtime = now; | |
525 | } | 525 | } | |
526 | #else | 526 | #else | |
527 | /* | 527 | /* | |
528 | * This is what Make does and it's actually a good thing, as it | 528 | * This is what Make does and it's actually a good thing, as it | |
529 | * allows rules like | 529 | * allows rules like | |
530 | * | 530 | * | |
531 | * cmp -s y.tab.h parse.h || cp y.tab.h parse.h | 531 | * cmp -s y.tab.h parse.h || cp y.tab.h parse.h | |
532 | * | 532 | * | |
533 | * to function as intended. Unfortunately, thanks to the stateless | 533 | * to function as intended. Unfortunately, thanks to the stateless | |
534 | * nature of NFS (by which I mean the loose coupling of two clients | 534 | * nature of NFS (by which I mean the loose coupling of two clients | |
535 | * using the same file from a common server), there are times | 535 | * using the same file from a common server), there are times | |
536 | * when the modification time of a file created on a remote | 536 | * when the modification time of a file created on a remote | |
537 | * machine will not be modified before the local stat() implied by | 537 | * machine will not be modified before the local stat() implied by | |
538 | * the Dir_MTime occurs, thus leading us to believe that the file | 538 | * the Dir_MTime occurs, thus leading us to believe that the file | |
539 | * is unchanged, wreaking havoc with files that depend on this one. | 539 | * is unchanged, wreaking havoc with files that depend on this one. | |
540 | * | 540 | * | |
541 | * I have decided it is better to make too much than to make too | 541 | * I have decided it is better to make too much than to make too | |
542 | * little, so this stuff is commented out unless you're sure it's ok. | 542 | * little, so this stuff is commented out unless you're sure it's ok. | |
543 | * -- ardeb 1/12/88 | 543 | * -- ardeb 1/12/88 | |
544 | */ | 544 | */ | |
545 | /* | 545 | /* | |
546 | * Christos, 4/9/92: If we are saving commands pretend that | 546 | * Christos, 4/9/92: If we are saving commands pretend that | |
547 | * the target is made now. Otherwise archives with ... rules | 547 | * the target is made now. Otherwise archives with ... rules | |
548 | * don't work! | 548 | * don't work! | |
549 | */ | 549 | */ | |
550 | if (NoExecute(gn) || (gn->type & OP_SAVE_CMDS) || | 550 | if (!GNode_ShouldExecute(gn) || (gn->type & OP_SAVE_CMDS) || | |
551 | (mtime == 0 && !(gn->type & OP_WAIT))) { | 551 | (mtime == 0 && !(gn->type & OP_WAIT))) { | |
552 | DEBUG2(MAKE, " recheck(%s): update time from %s to now\n", | 552 | DEBUG2(MAKE, " recheck(%s): update time from %s to now\n", | |
553 | gn->name, Targ_FmtTime(gn->mtime)); | 553 | gn->name, Targ_FmtTime(gn->mtime)); | |
554 | gn->mtime = now; | 554 | gn->mtime = now; | |
555 | } | 555 | } | |
556 | else { | 556 | else { | |
557 | DEBUG2(MAKE, " recheck(%s): current update time: %s\n", | 557 | DEBUG2(MAKE, " recheck(%s): current update time: %s\n", | |
558 | gn->name, Targ_FmtTime(gn->mtime)); | 558 | gn->name, Targ_FmtTime(gn->mtime)); | |
559 | } | 559 | } | |
560 | #endif | 560 | #endif | |
561 | return mtime; | 561 | return mtime; | |
562 | } | 562 | } | |
563 | 563 | |||
564 | /* | 564 | /* | |
565 | * Set the .PREFIX and .IMPSRC variables for all the implied parents | 565 | * Set the .PREFIX and .IMPSRC variables for all the implied parents | |
566 | * of this node. | 566 | * of this node. | |
567 | */ | 567 | */ | |
568 | static void | 568 | static void | |
569 | UpdateImplicitParentsVars(GNode *cgn, const char *cname) | 569 | UpdateImplicitParentsVars(GNode *cgn, const char *cname) | |
570 | { | 570 | { | |
571 | GNodeListNode *ln; | 571 | GNodeListNode *ln; | |
572 | const char *cpref = GNode_VarPrefix(cgn); | 572 | const char *cpref = GNode_VarPrefix(cgn); | |
573 | 573 | |||
574 | for (ln = cgn->implicitParents->first; ln != NULL; ln = ln->next) { | 574 | for (ln = cgn->implicitParents->first; ln != NULL; ln = ln->next) { | |
575 | GNode *pgn = ln->datum; | 575 | GNode *pgn = ln->datum; | |
576 | if (pgn->flags & REMAKE) { | 576 | if (pgn->flags & REMAKE) { | |
577 | Var_Set(IMPSRC, cname, pgn); | 577 | Var_Set(IMPSRC, cname, pgn); | |
578 | if (cpref != NULL) | 578 | if (cpref != NULL) | |
579 | Var_Set(PREFIX, cpref, pgn); | 579 | Var_Set(PREFIX, cpref, pgn); | |
580 | } | 580 | } | |
581 | } | 581 | } | |
582 | } | 582 | } | |
583 | 583 | |||
584 | /* Perform update on the parents of a node. Used by JobFinish once | 584 | /* Perform update on the parents of a node. Used by JobFinish once | |
585 | * a node has been dealt with and by MakeStartJobs if it finds an | 585 | * a node has been dealt with and by MakeStartJobs if it finds an | |
586 | * up-to-date node. | 586 | * up-to-date node. | |
587 | * | 587 | * | |
588 | * The unmade field of pgn is decremented and pgn may be placed on | 588 | * The unmade field of pgn is decremented and pgn may be placed on | |
589 | * the toBeMade queue if this field becomes 0. | 589 | * the toBeMade queue if this field becomes 0. | |
590 | * | 590 | * | |
591 | * If the child was made, the parent's flag CHILDMADE field will be | 591 | * If the child was made, the parent's flag CHILDMADE field will be | |
592 | * set true. | 592 | * set true. | |
593 | * | 593 | * | |
594 | * If the child is not up-to-date and still does not exist, | 594 | * If the child is not up-to-date and still does not exist, | |
595 | * set the FORCE flag on the parents. | 595 | * set the FORCE flag on the parents. | |
596 | * | 596 | * | |
597 | * If the child wasn't made, the youngestChild field of the parent will be | 597 | * If the child wasn't made, the youngestChild field of the parent will be | |
598 | * altered if the child's mtime is big enough. | 598 | * altered if the child's mtime is big enough. | |
599 | * | 599 | * | |
600 | * Finally, if the child is the implied source for the parent, the | 600 | * Finally, if the child is the implied source for the parent, the | |
601 | * parent's IMPSRC variable is set appropriately. | 601 | * parent's IMPSRC variable is set appropriately. | |
602 | */ | 602 | */ | |
603 | void | 603 | void | |
604 | Make_Update(GNode *cgn) | 604 | Make_Update(GNode *cgn) | |
605 | { | 605 | { | |
606 | const char *cname; /* the child's name */ | 606 | const char *cname; /* the child's name */ | |
607 | time_t mtime = -1; | 607 | time_t mtime = -1; | |
608 | GNodeList *parents; | 608 | GNodeList *parents; | |
609 | GNodeListNode *ln; | 609 | GNodeListNode *ln; | |
610 | GNode *centurion; | 610 | GNode *centurion; | |
611 | 611 | |||
612 | /* It is save to re-examine any nodes again */ | 612 | /* It is save to re-examine any nodes again */ | |
613 | checked++; | 613 | checked++; | |
614 | 614 | |||
615 | cname = GNode_VarTarget(cgn); | 615 | cname = GNode_VarTarget(cgn); | |
616 | 616 | |||
617 | DEBUG2(MAKE, "Make_Update: %s%s\n", cgn->name, cgn->cohort_num); | 617 | DEBUG2(MAKE, "Make_Update: %s%s\n", cgn->name, cgn->cohort_num); | |
618 | 618 | |||
619 | /* | 619 | /* | |
620 | * If the child was actually made, see what its modification time is | 620 | * If the child was actually made, see what its modification time is | |
621 | * now -- some rules won't actually update the file. If the file still | 621 | * now -- some rules won't actually update the file. If the file still | |
622 | * doesn't exist, make its mtime now. | 622 | * doesn't exist, make its mtime now. | |
623 | */ | 623 | */ | |
624 | if (cgn->made != UPTODATE) { | 624 | if (cgn->made != UPTODATE) { | |
625 | mtime = Make_Recheck(cgn); | 625 | mtime = Make_Recheck(cgn); | |
626 | } | 626 | } | |
627 | 627 | |||
628 | /* | 628 | /* | |
629 | * If this is a `::' node, we must consult its first instance | 629 | * If this is a `::' node, we must consult its first instance | |
630 | * which is where all parents are linked. | 630 | * which is where all parents are linked. | |
631 | */ | 631 | */ | |
632 | if ((centurion = cgn->centurion) != NULL) { | 632 | if ((centurion = cgn->centurion) != NULL) { | |
633 | if (!Lst_IsEmpty(cgn->parents)) | 633 | if (!Lst_IsEmpty(cgn->parents)) | |
634 | Punt("%s%s: cohort has parents", cgn->name, cgn->cohort_num); | 634 | Punt("%s%s: cohort has parents", cgn->name, cgn->cohort_num); | |
635 | centurion->unmade_cohorts--; | 635 | centurion->unmade_cohorts--; | |
636 | if (centurion->unmade_cohorts < 0) | 636 | if (centurion->unmade_cohorts < 0) | |
637 | Error("Graph cycles through centurion %s", centurion->name); | 637 | Error("Graph cycles through centurion %s", centurion->name); | |
638 | } else { | 638 | } else { | |
639 | centurion = cgn; | 639 | centurion = cgn; | |
640 | } | 640 | } | |
641 | parents = centurion->parents; | 641 | parents = centurion->parents; | |
642 | 642 | |||
643 | /* If this was a .ORDER node, schedule the RHS */ | 643 | /* If this was a .ORDER node, schedule the RHS */ | |
644 | Lst_ForEachUntil(centurion->order_succ, MakeBuildParent, toBeMade->first); | 644 | Lst_ForEachUntil(centurion->order_succ, MakeBuildParent, toBeMade->first); | |
645 | 645 | |||
646 | /* Now mark all the parents as having one less unmade child */ | 646 | /* Now mark all the parents as having one less unmade child */ | |
647 | for (ln = parents->first; ln != NULL; ln = ln->next) { | 647 | for (ln = parents->first; ln != NULL; ln = ln->next) { | |
648 | GNode *pgn = ln->datum; | 648 | GNode *pgn = ln->datum; | |
649 | 649 | |||
650 | if (DEBUG(MAKE)) | 650 | if (DEBUG(MAKE)) | |
651 | debug_printf("inspect parent %s%s: flags %x, " | 651 | debug_printf("inspect parent %s%s: flags %x, " | |
652 | "type %x, made %d, unmade %d ", | 652 | "type %x, made %d, unmade %d ", | |
653 | pgn->name, pgn->cohort_num, pgn->flags, | 653 | pgn->name, pgn->cohort_num, pgn->flags, | |
654 | pgn->type, pgn->made, pgn->unmade - 1); | 654 | pgn->type, pgn->made, pgn->unmade - 1); | |
655 | 655 | |||
656 | if (!(pgn->flags & REMAKE)) { | 656 | if (!(pgn->flags & REMAKE)) { | |
657 | /* This parent isn't needed */ | 657 | /* This parent isn't needed */ | |
658 | DEBUG0(MAKE, "- not needed\n"); | 658 | DEBUG0(MAKE, "- not needed\n"); | |
659 | continue; | 659 | continue; | |
660 | } | 660 | } | |
661 | if (mtime == 0 && !(cgn->type & OP_WAIT)) | 661 | if (mtime == 0 && !(cgn->type & OP_WAIT)) | |
662 | pgn->flags |= FORCE; | 662 | pgn->flags |= FORCE; | |
663 | 663 | |||
664 | /* | 664 | /* | |
665 | * If the parent has the .MADE attribute, its timestamp got | 665 | * If the parent has the .MADE attribute, its timestamp got | |
666 | * updated to that of its newest child, and its unmade | 666 | * updated to that of its newest child, and its unmade | |
667 | * child count got set to zero in Make_ExpandUse(). | 667 | * child count got set to zero in Make_ExpandUse(). | |
668 | * However other things might cause us to build one of its | 668 | * However other things might cause us to build one of its | |
669 | * children - and so we mustn't do any processing here when | 669 | * children - and so we mustn't do any processing here when | |
670 | * the child build finishes. | 670 | * the child build finishes. | |
671 | */ | 671 | */ | |
672 | if (pgn->type & OP_MADE) { | 672 | if (pgn->type & OP_MADE) { | |
673 | DEBUG0(MAKE, "- .MADE\n"); | 673 | DEBUG0(MAKE, "- .MADE\n"); | |
674 | continue; | 674 | continue; | |
675 | } | 675 | } | |
676 | 676 | |||
677 | if ( ! (cgn->type & (OP_EXEC|OP_USE|OP_USEBEFORE))) { | 677 | if ( ! (cgn->type & (OP_EXEC|OP_USE|OP_USEBEFORE))) { | |
678 | if (cgn->made == MADE) | 678 | if (cgn->made == MADE) | |
679 | pgn->flags |= CHILDMADE; | 679 | pgn->flags |= CHILDMADE; | |
680 | (void)Make_TimeStamp(pgn, cgn); | 680 | (void)Make_TimeStamp(pgn, cgn); | |
681 | } | 681 | } | |
682 | 682 | |||
683 | /* | 683 | /* | |
684 | * A parent must wait for the completion of all instances | 684 | * A parent must wait for the completion of all instances | |
685 | * of a `::' dependency. | 685 | * of a `::' dependency. | |
686 | */ | 686 | */ | |
687 | if (centurion->unmade_cohorts != 0 || centurion->made < MADE) { | 687 | if (centurion->unmade_cohorts != 0 || centurion->made < MADE) { | |
688 | DEBUG2(MAKE, "- centurion made %d, %d unmade cohorts\n", | 688 | DEBUG2(MAKE, "- centurion made %d, %d unmade cohorts\n", | |
689 | centurion->made, centurion->unmade_cohorts); | 689 | centurion->made, centurion->unmade_cohorts); | |
690 | continue; | 690 | continue; | |
691 | } | 691 | } | |
692 | 692 | |||
693 | /* One more child of this parent is now made */ | 693 | /* One more child of this parent is now made */ | |
694 | pgn->unmade--; | 694 | pgn->unmade--; | |
695 | if (pgn->unmade < 0) { | 695 | if (pgn->unmade < 0) { | |
696 | if (DEBUG(MAKE)) { | 696 | if (DEBUG(MAKE)) { | |
697 | debug_printf("Graph cycles through %s%s\n", | 697 | debug_printf("Graph cycles through %s%s\n", | |
698 | pgn->name, pgn->cohort_num); | 698 | pgn->name, pgn->cohort_num); | |
699 | Targ_PrintGraph(2); | 699 | Targ_PrintGraph(2); | |
700 | } | 700 | } | |
701 | Error("Graph cycles through %s%s", pgn->name, pgn->cohort_num); | 701 | Error("Graph cycles through %s%s", pgn->name, pgn->cohort_num); | |
702 | } | 702 | } | |
703 | 703 | |||
704 | /* We must always rescan the parents of .WAIT and .ORDER nodes. */ | 704 | /* We must always rescan the parents of .WAIT and .ORDER nodes. */ | |
705 | if (pgn->unmade != 0 && !(centurion->type & OP_WAIT) | 705 | if (pgn->unmade != 0 && !(centurion->type & OP_WAIT) | |
706 | && !(centurion->flags & DONE_ORDER)) { | 706 | && !(centurion->flags & DONE_ORDER)) { | |
707 | DEBUG0(MAKE, "- unmade children\n"); | 707 | DEBUG0(MAKE, "- unmade children\n"); | |
708 | continue; | 708 | continue; | |
709 | } | 709 | } | |
710 | if (pgn->made != DEFERRED) { | 710 | if (pgn->made != DEFERRED) { | |
711 | /* | 711 | /* | |
712 | * Either this parent is on a different branch of the tree, | 712 | * Either this parent is on a different branch of the tree, | |
713 | * or it on the RHS of a .WAIT directive | 713 | * or it on the RHS of a .WAIT directive | |
714 | * or it is already on the toBeMade list. | 714 | * or it is already on the toBeMade list. | |
715 | */ | 715 | */ | |
716 | DEBUG0(MAKE, "- not deferred\n"); | 716 | DEBUG0(MAKE, "- not deferred\n"); | |
717 | continue; | 717 | continue; | |
718 | } | 718 | } | |
719 | assert(pgn->order_pred != NULL); | 719 | assert(pgn->order_pred != NULL); | |
720 | if (Lst_ForEachUntil(pgn->order_pred, MakeCheckOrder, 0)) { | 720 | if (Lst_ForEachUntil(pgn->order_pred, MakeCheckOrder, 0)) { | |
721 | /* A .ORDER rule stops us building this */ | 721 | /* A .ORDER rule stops us building this */ | |
722 | continue; | 722 | continue; | |
723 | } | 723 | } | |
724 | if (DEBUG(MAKE)) { | 724 | if (DEBUG(MAKE)) { | |
725 | debug_printf("- %s%s made, schedule %s%s (made %d)\n", | 725 | debug_printf("- %s%s made, schedule %s%s (made %d)\n", | |
726 | cgn->name, cgn->cohort_num, | 726 | cgn->name, cgn->cohort_num, | |
727 | pgn->name, pgn->cohort_num, pgn->made); | 727 | pgn->name, pgn->cohort_num, pgn->made); | |
728 | Targ_PrintNode(pgn, 2); | 728 | Targ_PrintNode(pgn, 2); | |
729 | } | 729 | } | |
730 | /* Ok, we can schedule the parent again */ | 730 | /* Ok, we can schedule the parent again */ | |
731 | pgn->made = REQUESTED; | 731 | pgn->made = REQUESTED; | |
732 | Lst_Enqueue(toBeMade, pgn); | 732 | Lst_Enqueue(toBeMade, pgn); | |
733 | } | 733 | } | |
734 | 734 | |||
735 | UpdateImplicitParentsVars(cgn, cname); | 735 | UpdateImplicitParentsVars(cgn, cname); | |
736 | } | 736 | } | |
737 | 737 | |||
738 | static void | 738 | static void | |
739 | UnmarkChildren(GNode *gn) | 739 | UnmarkChildren(GNode *gn) | |
740 | { | 740 | { | |
741 | GNodeListNode *ln; | 741 | GNodeListNode *ln; | |
742 | 742 | |||
743 | for (ln = gn->children->first; ln != NULL; ln = ln->next) { | 743 | for (ln = gn->children->first; ln != NULL; ln = ln->next) { | |
744 | GNode *child = ln->datum; | 744 | GNode *child = ln->datum; | |
745 | child->type &= ~OP_MARK; | 745 | child->type &= ~OP_MARK; | |
746 | } | 746 | } | |
747 | } | 747 | } | |
748 | 748 | |||
749 | /* Add a child's name to the ALLSRC and OODATE variables of the given | 749 | /* Add a child's name to the ALLSRC and OODATE variables of the given | |
750 | * node, but only if it has not been given the .EXEC, .USE or .INVISIBLE | 750 | * node, but only if it has not been given the .EXEC, .USE or .INVISIBLE | |
751 | * attributes. .EXEC and .USE children are very rarely going to be files, | 751 | * attributes. .EXEC and .USE children are very rarely going to be files, | |
752 | * so... | 752 | * so... | |
753 | * | 753 | * | |
754 | * If the child is a .JOIN node, its ALLSRC is propagated to the parent. | 754 | * If the child is a .JOIN node, its ALLSRC is propagated to the parent. | |
755 | * | 755 | * | |
756 | * A child is added to the OODATE variable if its modification time is | 756 | * A child is added to the OODATE variable if its modification time is | |
757 | * later than that of its parent, as defined by Make, except if the | 757 | * later than that of its parent, as defined by Make, except if the | |
758 | * parent is a .JOIN node. In that case, it is only added to the OODATE | 758 | * parent is a .JOIN node. In that case, it is only added to the OODATE | |
759 | * variable if it was actually made (since .JOIN nodes don't have | 759 | * variable if it was actually made (since .JOIN nodes don't have | |
760 | * modification times, the comparison is rather unfair...).. | 760 | * modification times, the comparison is rather unfair...).. | |
761 | * | 761 | * | |
762 | * Input: | 762 | * Input: | |
763 | * cgn The child to add | 763 | * cgn The child to add | |
764 | * pgn The parent to whose ALLSRC variable it should | 764 | * pgn The parent to whose ALLSRC variable it should | |
765 | * be added | 765 | * be added | |
766 | */ | 766 | */ | |
767 | static void | 767 | static void | |
768 | MakeAddAllSrc(GNode *cgn, GNode *pgn) | 768 | MakeAddAllSrc(GNode *cgn, GNode *pgn) | |
769 | { | 769 | { | |
770 | if (cgn->type & OP_MARK) | 770 | if (cgn->type & OP_MARK) | |
771 | return; | 771 | return; | |
772 | cgn->type |= OP_MARK; | 772 | cgn->type |= OP_MARK; | |
773 | 773 | |||
774 | if ((cgn->type & (OP_EXEC|OP_USE|OP_USEBEFORE|OP_INVISIBLE)) == 0) { | 774 | if ((cgn->type & (OP_EXEC|OP_USE|OP_USEBEFORE|OP_INVISIBLE)) == 0) { | |
775 | const char *child, *allsrc; | 775 | const char *child, *allsrc; | |
776 | 776 | |||
777 | if (cgn->type & OP_ARCHV) | 777 | if (cgn->type & OP_ARCHV) | |
778 | child = GNode_VarMember(cgn); | 778 | child = GNode_VarMember(cgn); | |
779 | else | 779 | else | |
780 | child = GNode_Path(cgn); | 780 | child = GNode_Path(cgn); | |
781 | if (cgn->type & OP_JOIN) { | 781 | if (cgn->type & OP_JOIN) { | |
782 | allsrc = GNode_VarAllsrc(cgn); | 782 | allsrc = GNode_VarAllsrc(cgn); | |
783 | } else { | 783 | } else { | |
784 | allsrc = child; | 784 | allsrc = child; | |
785 | } | 785 | } | |
786 | if (allsrc != NULL) | 786 | if (allsrc != NULL) | |
787 | Var_Append(ALLSRC, allsrc, pgn); | 787 | Var_Append(ALLSRC, allsrc, pgn); | |
788 | if (pgn->type & OP_JOIN) { | 788 | if (pgn->type & OP_JOIN) { | |
789 | if (cgn->made == MADE) { | 789 | if (cgn->made == MADE) { | |
790 | Var_Append(OODATE, child, pgn); | 790 | Var_Append(OODATE, child, pgn); | |
791 | } | 791 | } | |
792 | } else if ((pgn->mtime < cgn->mtime) || | 792 | } else if ((pgn->mtime < cgn->mtime) || | |
793 | (cgn->mtime >= now && cgn->made == MADE)) | 793 | (cgn->mtime >= now && cgn->made == MADE)) | |
794 | { | 794 | { | |
795 | /* | 795 | /* | |
796 | * It goes in the OODATE variable if the parent is younger than the | 796 | * It goes in the OODATE variable if the parent is younger than the | |
797 | * child or if the child has been modified more recently than | 797 | * child or if the child has been modified more recently than | |
798 | * the start of the make. This is to keep pmake from getting | 798 | * the start of the make. This is to keep pmake from getting | |
799 | * confused if something else updates the parent after the | 799 | * confused if something else updates the parent after the | |
800 | * make starts (shouldn't happen, I know, but sometimes it | 800 | * make starts (shouldn't happen, I know, but sometimes it | |
801 | * does). In such a case, if we've updated the kid, the parent | 801 | * does). In such a case, if we've updated the kid, the parent | |
802 | * is likely to have a modification time later than that of | 802 | * is likely to have a modification time later than that of | |
803 | * the kid and anything that relies on the OODATE variable will | 803 | * the kid and anything that relies on the OODATE variable will | |
804 | * be hosed. | 804 | * be hosed. | |
805 | * | 805 | * | |
806 | * XXX: This will cause all made children to go in the OODATE | 806 | * XXX: This will cause all made children to go in the OODATE | |
807 | * variable, even if they're not touched, if RECHECK isn't defined, | 807 | * variable, even if they're not touched, if RECHECK isn't defined, | |
808 | * since cgn->mtime is set to now in Make_Update. According to | 808 | * since cgn->mtime is set to now in Make_Update. According to | |
809 | * some people, this is good... | 809 | * some people, this is good... | |
810 | */ | 810 | */ | |
811 | Var_Append(OODATE, child, pgn); | 811 | Var_Append(OODATE, child, pgn); | |
812 | } | 812 | } | |
813 | } | 813 | } | |
814 | } | 814 | } | |
815 | 815 | |||
816 | /* Set up the ALLSRC and OODATE variables. Sad to say, it must be | 816 | /* Set up the ALLSRC and OODATE variables. Sad to say, it must be | |
817 | * done separately, rather than while traversing the graph. This is | 817 | * done separately, rather than while traversing the graph. This is | |
818 | * because Make defined OODATE to contain all sources whose modification | 818 | * because Make defined OODATE to contain all sources whose modification | |
819 | * times were later than that of the target, *not* those sources that | 819 | * times were later than that of the target, *not* those sources that | |
820 | * were out-of-date. Since in both compatibility and native modes, | 820 | * were out-of-date. Since in both compatibility and native modes, | |
821 | * the modification time of the parent isn't found until the child | 821 | * the modification time of the parent isn't found until the child | |
822 | * has been dealt with, we have to wait until now to fill in the | 822 | * has been dealt with, we have to wait until now to fill in the | |
823 | * variable. As for ALLSRC, the ordering is important and not | 823 | * variable. As for ALLSRC, the ordering is important and not | |
824 | * guaranteed when in native mode, so it must be set here, too. | 824 | * guaranteed when in native mode, so it must be set here, too. | |
825 | * | 825 | * | |
826 | * If the node is a .JOIN node, its TARGET variable will be set to | 826 | * If the node is a .JOIN node, its TARGET variable will be set to | |
827 | * match its ALLSRC variable. | 827 | * match its ALLSRC variable. | |
828 | */ | 828 | */ | |
829 | void | 829 | void | |
830 | Make_DoAllVar(GNode *gn) | 830 | Make_DoAllVar(GNode *gn) | |
831 | { | 831 | { | |
832 | GNodeListNode *ln; | 832 | GNodeListNode *ln; | |
833 | 833 | |||
834 | if (gn->flags & DONE_ALLSRC) | 834 | if (gn->flags & DONE_ALLSRC) | |
835 | return; | 835 | return; | |
836 | 836 | |||
837 | UnmarkChildren(gn); | 837 | UnmarkChildren(gn); | |
838 | for (ln = gn->children->first; ln != NULL; ln = ln->next) | 838 | for (ln = gn->children->first; ln != NULL; ln = ln->next) | |
839 | MakeAddAllSrc(ln->datum, gn); | 839 | MakeAddAllSrc(ln->datum, gn); | |
840 | 840 | |||
841 | if (!Var_Exists(OODATE, gn)) { | 841 | if (!Var_Exists(OODATE, gn)) { | |
842 | Var_Set(OODATE, "", gn); | 842 | Var_Set(OODATE, "", gn); | |
843 | } | 843 | } | |
844 | if (!Var_Exists(ALLSRC, gn)) { | 844 | if (!Var_Exists(ALLSRC, gn)) { | |
845 | Var_Set(ALLSRC, "", gn); | 845 | Var_Set(ALLSRC, "", gn); | |
846 | } | 846 | } | |
847 | 847 | |||
848 | if (gn->type & OP_JOIN) | 848 | if (gn->type & OP_JOIN) | |
849 | Var_Set(TARGET, GNode_VarAllsrc(gn), gn); | 849 | Var_Set(TARGET, GNode_VarAllsrc(gn), gn); | |
850 | gn->flags |= DONE_ALLSRC; | 850 | gn->flags |= DONE_ALLSRC; | |
851 | } | 851 | } | |
852 | 852 | |||
853 | static int | 853 | static int | |
854 | MakeCheckOrder(void *v_bn, void *ignore MAKE_ATTR_UNUSED) | 854 | MakeCheckOrder(void *v_bn, void *ignore MAKE_ATTR_UNUSED) | |
855 | { | 855 | { | |
856 | GNode *bn = v_bn; | 856 | GNode *bn = v_bn; | |
857 | 857 | |||
858 | if (bn->made >= MADE || !(bn->flags & REMAKE)) | 858 | if (bn->made >= MADE || !(bn->flags & REMAKE)) | |
859 | return 0; | 859 | return 0; | |
860 | 860 | |||
861 | DEBUG2(MAKE, "MakeCheckOrder: Waiting for .ORDER node %s%s\n", | 861 | DEBUG2(MAKE, "MakeCheckOrder: Waiting for .ORDER node %s%s\n", | |
862 | bn->name, bn->cohort_num); | 862 | bn->name, bn->cohort_num); | |
863 | return 1; | 863 | return 1; | |
864 | } | 864 | } | |
865 | 865 | |||
866 | static int | 866 | static int | |
867 | MakeBuildChild(void *v_cn, void *toBeMade_next) | 867 | MakeBuildChild(void *v_cn, void *toBeMade_next) | |
868 | { | 868 | { | |
869 | GNode *cn = v_cn; | 869 | GNode *cn = v_cn; | |
870 | 870 | |||
871 | DEBUG4(MAKE, "MakeBuildChild: inspect %s%s, made %d, type %x\n", | 871 | DEBUG4(MAKE, "MakeBuildChild: inspect %s%s, made %d, type %x\n", | |
872 | cn->name, cn->cohort_num, cn->made, cn->type); | 872 | cn->name, cn->cohort_num, cn->made, cn->type); | |
873 | if (cn->made > DEFERRED) | 873 | if (cn->made > DEFERRED) | |
874 | return 0; | 874 | return 0; | |
875 | 875 | |||
876 | /* If this node is on the RHS of a .ORDER, check LHSs. */ | 876 | /* If this node is on the RHS of a .ORDER, check LHSs. */ | |
877 | assert(cn->order_pred); | 877 | assert(cn->order_pred); | |
878 | if (Lst_ForEachUntil(cn->order_pred, MakeCheckOrder, 0)) { | 878 | if (Lst_ForEachUntil(cn->order_pred, MakeCheckOrder, 0)) { | |
879 | /* Can't build this (or anything else in this child list) yet */ | 879 | /* Can't build this (or anything else in this child list) yet */ | |
880 | cn->made = DEFERRED; | 880 | cn->made = DEFERRED; | |
881 | return 0; /* but keep looking */ | 881 | return 0; /* but keep looking */ | |
882 | } | 882 | } | |
883 | 883 | |||
884 | DEBUG2(MAKE, "MakeBuildChild: schedule %s%s\n", cn->name, cn->cohort_num); | 884 | DEBUG2(MAKE, "MakeBuildChild: schedule %s%s\n", cn->name, cn->cohort_num); | |
885 | 885 | |||
886 | cn->made = REQUESTED; | 886 | cn->made = REQUESTED; | |
887 | if (toBeMade_next == NULL) | 887 | if (toBeMade_next == NULL) | |
888 | Lst_Append(toBeMade, cn); | 888 | Lst_Append(toBeMade, cn); | |
889 | else | 889 | else | |
890 | Lst_InsertBefore(toBeMade, toBeMade_next, cn); | 890 | Lst_InsertBefore(toBeMade, toBeMade_next, cn); | |
891 | 891 | |||
892 | if (cn->unmade_cohorts != 0) | 892 | if (cn->unmade_cohorts != 0) | |
893 | Lst_ForEachUntil(cn->cohorts, MakeBuildChild, toBeMade_next); | 893 | Lst_ForEachUntil(cn->cohorts, MakeBuildChild, toBeMade_next); | |
894 | 894 | |||
895 | /* | 895 | /* | |
896 | * If this node is a .WAIT node with unmade children | 896 | * If this node is a .WAIT node with unmade children | |
897 | * then don't add the next sibling. | 897 | * then don't add the next sibling. | |
898 | */ | 898 | */ | |
899 | return cn->type & OP_WAIT && cn->unmade > 0; | 899 | return cn->type & OP_WAIT && cn->unmade > 0; | |
900 | } | 900 | } | |
901 | 901 | |||
902 | /* When a .ORDER LHS node completes we do this on each RHS */ | 902 | /* When a .ORDER LHS node completes we do this on each RHS */ | |
903 | static int | 903 | static int | |
904 | MakeBuildParent(void *v_pn, void *toBeMade_next) | 904 | MakeBuildParent(void *v_pn, void *toBeMade_next) | |
905 | { | 905 | { | |
906 | GNode *pn = v_pn; | 906 | GNode *pn = v_pn; | |
907 | 907 | |||
908 | if (pn->made != DEFERRED) | 908 | if (pn->made != DEFERRED) | |
909 | return 0; | 909 | return 0; | |
910 | 910 | |||
911 | if (MakeBuildChild(pn, toBeMade_next) == 0) { | 911 | if (MakeBuildChild(pn, toBeMade_next) == 0) { | |
912 | /* Mark so that when this node is built we reschedule its parents */ | 912 | /* Mark so that when this node is built we reschedule its parents */ | |
913 | pn->flags |= DONE_ORDER; | 913 | pn->flags |= DONE_ORDER; | |
914 | } | 914 | } | |
915 | 915 | |||
916 | return 0; | 916 | return 0; | |
917 | } | 917 | } | |
918 | 918 | |||
919 | /* Start as many jobs as possible, taking them from the toBeMade queue. | 919 | /* Start as many jobs as possible, taking them from the toBeMade queue. | |
920 | * | 920 | * | |
921 | * If the query flag was given to pmake, no job will be started, | 921 | * If the query flag was given to pmake, no job will be started, | |
922 | * but as soon as an out-of-date target is found, this function | 922 | * but as soon as an out-of-date target is found, this function | |
923 | * returns TRUE. At all other times, this function returns FALSE. | 923 | * returns TRUE. At all other times, this function returns FALSE. | |
924 | */ | 924 | */ | |
925 | static Boolean | 925 | static Boolean | |
926 | MakeStartJobs(void) | 926 | MakeStartJobs(void) | |
927 | { | 927 | { | |
928 | GNode *gn; | 928 | GNode *gn; | |
929 | int have_token = 0; | 929 | int have_token = 0; | |
930 | 930 | |||
931 | while (!Lst_IsEmpty(toBeMade)) { | 931 | while (!Lst_IsEmpty(toBeMade)) { | |
932 | /* Get token now to avoid cycling job-list when we only have 1 token */ | 932 | /* Get token now to avoid cycling job-list when we only have 1 token */ | |
933 | if (!have_token && !Job_TokenWithdraw()) | 933 | if (!have_token && !Job_TokenWithdraw()) | |
934 | break; | 934 | break; | |
935 | have_token = 1; | 935 | have_token = 1; | |
936 | 936 | |||
937 | gn = Lst_Dequeue(toBeMade); | 937 | gn = Lst_Dequeue(toBeMade); | |
938 | DEBUG2(MAKE, "Examining %s%s...\n", gn->name, gn->cohort_num); | 938 | DEBUG2(MAKE, "Examining %s%s...\n", gn->name, gn->cohort_num); | |
939 | 939 | |||
940 | if (gn->made != REQUESTED) { | 940 | if (gn->made != REQUESTED) { | |
941 | DEBUG1(MAKE, "state %d\n", gn->made); | 941 | DEBUG1(MAKE, "state %d\n", gn->made); | |
942 | 942 | |||
943 | make_abort(gn, __LINE__); | 943 | make_abort(gn, __LINE__); | |
944 | } | 944 | } | |
945 | 945 | |||
946 | if (gn->checked_seqno == checked) { | 946 | if (gn->checked_seqno == checked) { | |
947 | /* We've already looked at this node since a job finished... */ | 947 | /* We've already looked at this node since a job finished... */ | |
948 | DEBUG2(MAKE, "already checked %s%s\n", gn->name, gn->cohort_num); | 948 | DEBUG2(MAKE, "already checked %s%s\n", gn->name, gn->cohort_num); | |
949 | gn->made = DEFERRED; | 949 | gn->made = DEFERRED; | |
950 | continue; | 950 | continue; | |
951 | } | 951 | } | |
952 | gn->checked_seqno = checked; | 952 | gn->checked_seqno = checked; | |
953 | 953 | |||
954 | if (gn->unmade != 0) { | 954 | if (gn->unmade != 0) { | |
955 | /* | 955 | /* | |
956 | * We can't build this yet, add all unmade children to toBeMade, | 956 | * We can't build this yet, add all unmade children to toBeMade, | |
957 | * just before the current first element. | 957 | * just before the current first element. | |
958 | */ | 958 | */ | |
959 | gn->made = DEFERRED; | 959 | gn->made = DEFERRED; | |
960 | Lst_ForEachUntil(gn->children, MakeBuildChild, toBeMade->first); | 960 | Lst_ForEachUntil(gn->children, MakeBuildChild, toBeMade->first); | |
961 | /* and drop this node on the floor */ | 961 | /* and drop this node on the floor */ | |
962 | DEBUG2(MAKE, "dropped %s%s\n", gn->name, gn->cohort_num); | 962 | DEBUG2(MAKE, "dropped %s%s\n", gn->name, gn->cohort_num); | |
963 | continue; | 963 | continue; | |
964 | } | 964 | } | |
965 | 965 | |||
966 | gn->made = BEINGMADE; | 966 | gn->made = BEINGMADE; | |
967 | if (Make_OODate(gn)) { | 967 | if (Make_OODate(gn)) { | |
968 | DEBUG0(MAKE, "out-of-date\n"); | 968 | DEBUG0(MAKE, "out-of-date\n"); | |
969 | if (opts.queryFlag) { | 969 | if (opts.queryFlag) { | |
970 | return TRUE; | 970 | return TRUE; | |
971 | } | 971 | } | |
972 | Make_DoAllVar(gn); | 972 | Make_DoAllVar(gn); | |
973 | Job_Make(gn); | 973 | Job_Make(gn); | |
974 | have_token = 0; | 974 | have_token = 0; | |
975 | } else { | 975 | } else { | |
976 | DEBUG0(MAKE, "up-to-date\n"); | 976 | DEBUG0(MAKE, "up-to-date\n"); | |
977 | gn->made = UPTODATE; | 977 | gn->made = UPTODATE; | |
978 | if (gn->type & OP_JOIN) { | 978 | if (gn->type & OP_JOIN) { | |
979 | /* | 979 | /* | |
980 | * Even for an up-to-date .JOIN node, we need it to have its | 980 | * Even for an up-to-date .JOIN node, we need it to have its | |
981 | * context variables so references to it get the correct | 981 | * context variables so references to it get the correct | |
982 | * value for .TARGET when building up the context variables | 982 | * value for .TARGET when building up the context variables | |
983 | * of its parent(s)... | 983 | * of its parent(s)... | |
984 | */ | 984 | */ | |
985 | Make_DoAllVar(gn); | 985 | Make_DoAllVar(gn); | |
986 | } | 986 | } | |
987 | Make_Update(gn); | 987 | Make_Update(gn); | |
988 | } | 988 | } | |
989 | } | 989 | } | |
990 | 990 | |||
991 | if (have_token) | 991 | if (have_token) | |
992 | Job_TokenReturn(); | 992 | Job_TokenReturn(); | |
993 | 993 | |||
994 | return FALSE; | 994 | return FALSE; | |
995 | } | 995 | } | |
996 | 996 | |||
997 | static void | 997 | static void | |
998 | MakePrintStatusOrderNode(GNode *ogn, GNode *gn) | 998 | MakePrintStatusOrderNode(GNode *ogn, GNode *gn) | |
999 | { | 999 | { | |
1000 | if (!(ogn->flags & REMAKE) || ogn->made > REQUESTED) | 1000 | if (!(ogn->flags & REMAKE) || ogn->made > REQUESTED) | |
1001 | /* not waiting for this one */ | 1001 | /* not waiting for this one */ | |
1002 | return; | 1002 | return; | |
1003 | 1003 | |||
1004 | printf(" `%s%s' has .ORDER dependency against %s%s ", | 1004 | printf(" `%s%s' has .ORDER dependency against %s%s ", | |
1005 | gn->name, gn->cohort_num, ogn->name, ogn->cohort_num); | 1005 | gn->name, gn->cohort_num, ogn->name, ogn->cohort_num); | |
1006 | GNode_FprintDetails(stdout, "(", ogn, ")\n"); | 1006 | GNode_FprintDetails(stdout, "(", ogn, ")\n"); | |
1007 | 1007 | |||
1008 | if (DEBUG(MAKE) && opts.debug_file != stdout) { | 1008 | if (DEBUG(MAKE) && opts.debug_file != stdout) { | |
1009 | debug_printf(" `%s%s' has .ORDER dependency against %s%s ", | 1009 | debug_printf(" `%s%s' has .ORDER dependency against %s%s ", | |
1010 | gn->name, gn->cohort_num, ogn->name, ogn->cohort_num); | 1010 | gn->name, gn->cohort_num, ogn->name, ogn->cohort_num); | |
1011 | GNode_FprintDetails(opts.debug_file, "(", ogn, ")\n"); | 1011 | GNode_FprintDetails(opts.debug_file, "(", ogn, ")\n"); | |
1012 | } | 1012 | } | |
1013 | } | 1013 | } | |
1014 | 1014 | |||
1015 | static void | 1015 | static void | |
1016 | MakePrintStatusOrder(GNode *gn) | 1016 | MakePrintStatusOrder(GNode *gn) | |
1017 | { | 1017 | { | |
1018 | GNodeListNode *ln; | 1018 | GNodeListNode *ln; | |
1019 | for (ln = gn->order_pred->first; ln != NULL; ln = ln->next) | 1019 | for (ln = gn->order_pred->first; ln != NULL; ln = ln->next) | |
1020 | MakePrintStatusOrderNode(ln->datum, gn); | 1020 | MakePrintStatusOrderNode(ln->datum, gn); | |
1021 | } | 1021 | } | |
1022 | 1022 | |||
1023 | static void MakePrintStatusList(GNodeList *, int *); | 1023 | static void MakePrintStatusList(GNodeList *, int *); | |
1024 | 1024 | |||
1025 | /* Print the status of a top-level node, viz. it being up-to-date already | 1025 | /* Print the status of a top-level node, viz. it being up-to-date already | |
1026 | * or not created due to an error in a lower level. | 1026 | * or not created due to an error in a lower level. | |
1027 | * Callback function for Make_Run via Lst_ForEachUntil. | 1027 | * Callback function for Make_Run via Lst_ForEachUntil. | |
1028 | */ | 1028 | */ | |
1029 | static Boolean | 1029 | static Boolean | |
1030 | MakePrintStatus(GNode *gn, int *errors) | 1030 | MakePrintStatus(GNode *gn, int *errors) | |
1031 | { | 1031 | { | |
1032 | if (gn->flags & DONECYCLE) | 1032 | if (gn->flags & DONECYCLE) | |
1033 | /* We've completely processed this node before, don't do it again. */ | 1033 | /* We've completely processed this node before, don't do it again. */ | |
1034 | return FALSE; | 1034 | return FALSE; | |
1035 | 1035 | |||
1036 | if (gn->unmade == 0) { | 1036 | if (gn->unmade == 0) { | |
1037 | gn->flags |= DONECYCLE; | 1037 | gn->flags |= DONECYCLE; | |
1038 | switch (gn->made) { | 1038 | switch (gn->made) { | |
1039 | case UPTODATE: | 1039 | case UPTODATE: | |
1040 | printf("`%s%s' is up to date.\n", gn->name, gn->cohort_num); | 1040 | printf("`%s%s' is up to date.\n", gn->name, gn->cohort_num); | |
1041 | break; | 1041 | break; | |
1042 | case MADE: | 1042 | case MADE: | |
1043 | break; | 1043 | break; | |
1044 | case UNMADE: | 1044 | case UNMADE: | |
1045 | case DEFERRED: | 1045 | case DEFERRED: | |
1046 | case REQUESTED: | 1046 | case REQUESTED: | |
1047 | case BEINGMADE: | 1047 | case BEINGMADE: | |
1048 | (*errors)++; | 1048 | (*errors)++; | |
1049 | printf("`%s%s' was not built", gn->name, gn->cohort_num); | 1049 | printf("`%s%s' was not built", gn->name, gn->cohort_num); | |
1050 | GNode_FprintDetails(stdout, " (", gn, ")!\n"); | 1050 | GNode_FprintDetails(stdout, " (", gn, ")!\n"); | |
1051 | if (DEBUG(MAKE) && opts.debug_file != stdout) { | 1051 | if (DEBUG(MAKE) && opts.debug_file != stdout) { | |
1052 | debug_printf("`%s%s' was not built", gn->name, gn->cohort_num); | 1052 | debug_printf("`%s%s' was not built", gn->name, gn->cohort_num); | |
1053 | GNode_FprintDetails(opts.debug_file, " (", gn, ")!\n"); | 1053 | GNode_FprintDetails(opts.debug_file, " (", gn, ")!\n"); | |
1054 | } | 1054 | } | |
1055 | /* Most likely problem is actually caused by .ORDER */ | 1055 | /* Most likely problem is actually caused by .ORDER */ | |
1056 | MakePrintStatusOrder(gn); | 1056 | MakePrintStatusOrder(gn); | |
1057 | break; | 1057 | break; | |
1058 | default: | 1058 | default: | |
1059 | /* Errors - already counted */ | 1059 | /* Errors - already counted */ | |
1060 | printf("`%s%s' not remade because of errors.\n", | 1060 | printf("`%s%s' not remade because of errors.\n", | |
1061 | gn->name, gn->cohort_num); | 1061 | gn->name, gn->cohort_num); | |
1062 | if (DEBUG(MAKE) && opts.debug_file != stdout) | 1062 | if (DEBUG(MAKE) && opts.debug_file != stdout) | |
1063 | debug_printf("`%s%s' not remade because of errors.\n", | 1063 | debug_printf("`%s%s' not remade because of errors.\n", | |
1064 | gn->name, gn->cohort_num); | 1064 | gn->name, gn->cohort_num); | |
1065 | break; | 1065 | break; | |
1066 | } | 1066 | } | |
1067 | return FALSE; | 1067 | return FALSE; | |
1068 | } | 1068 | } | |
1069 | 1069 | |||
1070 | DEBUG3(MAKE, "MakePrintStatus: %s%s has %d unmade children\n", | 1070 | DEBUG3(MAKE, "MakePrintStatus: %s%s has %d unmade children\n", | |
1071 | gn->name, gn->cohort_num, gn->unmade); | 1071 | gn->name, gn->cohort_num, gn->unmade); | |
1072 | /* | 1072 | /* | |
1073 | * If printing cycles and came to one that has unmade children, | 1073 | * If printing cycles and came to one that has unmade children, | |
1074 | * print out the cycle by recursing on its children. | 1074 | * print out the cycle by recursing on its children. | |
1075 | */ | 1075 | */ | |
1076 | if (!(gn->flags & CYCLE)) { | 1076 | if (!(gn->flags & CYCLE)) { | |
1077 | /* Fist time we've seen this node, check all children */ | 1077 | /* Fist time we've seen this node, check all children */ | |
1078 | gn->flags |= CYCLE; | 1078 | gn->flags |= CYCLE; | |
1079 | MakePrintStatusList(gn->children, errors); | 1079 | MakePrintStatusList(gn->children, errors); | |
1080 | /* Mark that this node needn't be processed again */ | 1080 | /* Mark that this node needn't be processed again */ | |
1081 | gn->flags |= DONECYCLE; | 1081 | gn->flags |= DONECYCLE; | |
1082 | return FALSE; | 1082 | return FALSE; | |
1083 | } | 1083 | } | |
1084 | 1084 | |||
1085 | /* Only output the error once per node */ | 1085 | /* Only output the error once per node */ | |
1086 | gn->flags |= DONECYCLE; | 1086 | gn->flags |= DONECYCLE; | |
1087 | Error("Graph cycles through `%s%s'", gn->name, gn->cohort_num); | 1087 | Error("Graph cycles through `%s%s'", gn->name, gn->cohort_num); | |
1088 | if ((*errors)++ > 100) | 1088 | if ((*errors)++ > 100) | |
1089 | /* Abandon the whole error report */ | 1089 | /* Abandon the whole error report */ | |
1090 | return TRUE; | 1090 | return TRUE; | |
1091 | 1091 | |||
1092 | /* Reporting for our children will give the rest of the loop */ | 1092 | /* Reporting for our children will give the rest of the loop */ | |
1093 | MakePrintStatusList(gn->children, errors); | 1093 | MakePrintStatusList(gn->children, errors); | |
1094 | return FALSE; | 1094 | return FALSE; | |
1095 | } | 1095 | } | |
1096 | 1096 | |||
1097 | static void | 1097 | static void | |
1098 | MakePrintStatusList(GNodeList *gnodes, int *errors) | 1098 | MakePrintStatusList(GNodeList *gnodes, int *errors) | |
1099 | { | 1099 | { | |
1100 | GNodeListNode *ln; | 1100 | GNodeListNode *ln; | |
1101 | for (ln = gnodes->first; ln != NULL; ln = ln->next) | 1101 | for (ln = gnodes->first; ln != NULL; ln = ln->next) | |
1102 | if (MakePrintStatus(ln->datum, errors)) | 1102 | if (MakePrintStatus(ln->datum, errors)) | |
1103 | break; | 1103 | break; | |
1104 | } | 1104 | } | |
1105 | 1105 | |||
1106 | /* Expand .USE nodes and create a new targets list. | 1106 | /* Expand .USE nodes and create a new targets list. | |
1107 | * | 1107 | * | |
1108 | * Input: | 1108 | * Input: | |
1109 | * targs the initial list of targets | 1109 | * targs the initial list of targets | |
1110 | */ | 1110 | */ | |
1111 | void | 1111 | void | |
1112 | Make_ExpandUse(GNodeList *targs) | 1112 | Make_ExpandUse(GNodeList *targs) | |
1113 | { | 1113 | { | |
1114 | GNodeList *examine; /* List of targets to examine */ | 1114 | GNodeList *examine; /* List of targets to examine */ | |
1115 | 1115 | |||
1116 | { | 1116 | { | |
1117 | /* XXX: Why is it necessary to copy the list? There shouldn't be | 1117 | /* XXX: Why is it necessary to copy the list? There shouldn't be | |
1118 | * any modifications to the list, at least the function name | 1118 | * any modifications to the list, at least the function name | |
1119 | * ExpandUse doesn't suggest that. */ | 1119 | * ExpandUse doesn't suggest that. */ | |
1120 | GNodeListNode *ln; | 1120 | GNodeListNode *ln; | |
1121 | examine = Lst_New(); | 1121 | examine = Lst_New(); | |
1122 | for (ln = targs->first; ln != NULL; ln = ln->next) | 1122 | for (ln = targs->first; ln != NULL; ln = ln->next) | |
1123 | Lst_Append(examine, ln->datum); | 1123 | Lst_Append(examine, ln->datum); | |
1124 | } | 1124 | } | |
1125 | 1125 | |||
1126 | /* | 1126 | /* | |
1127 | * Make an initial downward pass over the graph, marking nodes to be made | 1127 | * Make an initial downward pass over the graph, marking nodes to be made | |
1128 | * as we go down. We call Suff_FindDeps to find where a node is and | 1128 | * as we go down. We call Suff_FindDeps to find where a node is and | |
1129 | * to get some children for it if it has none and also has no commands. | 1129 | * to get some children for it if it has none and also has no commands. | |
1130 | * If the node is a leaf, we stick it on the toBeMade queue to | 1130 | * If the node is a leaf, we stick it on the toBeMade queue to | |
1131 | * be looked at in a minute, otherwise we add its children to our queue | 1131 | * be looked at in a minute, otherwise we add its children to our queue | |
1132 | * and go on about our business. | 1132 | * and go on about our business. | |
1133 | */ | 1133 | */ | |
1134 | while (!Lst_IsEmpty(examine)) { | 1134 | while (!Lst_IsEmpty(examine)) { | |
1135 | GNode *gn = Lst_Dequeue(examine); | 1135 | GNode *gn = Lst_Dequeue(examine); | |
1136 | 1136 | |||
1137 | if (gn->flags & REMAKE) | 1137 | if (gn->flags & REMAKE) | |
1138 | /* We've looked at this one already */ | 1138 | /* We've looked at this one already */ | |
1139 | continue; | 1139 | continue; | |
1140 | gn->flags |= REMAKE; | 1140 | gn->flags |= REMAKE; | |
1141 | DEBUG2(MAKE, "Make_ExpandUse: examine %s%s\n", | 1141 | DEBUG2(MAKE, "Make_ExpandUse: examine %s%s\n", | |
1142 | gn->name, gn->cohort_num); | 1142 | gn->name, gn->cohort_num); | |
1143 | 1143 | |||
1144 | if (gn->type & OP_DOUBLEDEP) | 1144 | if (gn->type & OP_DOUBLEDEP) | |
1145 | Lst_PrependAll(examine, gn->cohorts); | 1145 | Lst_PrependAll(examine, gn->cohorts); | |
1146 | 1146 | |||
1147 | /* | 1147 | /* | |
1148 | * Apply any .USE rules before looking for implicit dependencies | 1148 | * Apply any .USE rules before looking for implicit dependencies | |
1149 | * to make sure everything has commands that should... | 1149 | * to make sure everything has commands that should... | |
1150 | * Make sure that the TARGET is set, so that we can make | 1150 | * Make sure that the TARGET is set, so that we can make | |
1151 | * expansions. | 1151 | * expansions. | |
1152 | */ | 1152 | */ | |
1153 | if (gn->type & OP_ARCHV) { | 1153 | if (gn->type & OP_ARCHV) { | |
1154 | char *eoa, *eon; | 1154 | char *eoa, *eon; | |
1155 | eoa = strchr(gn->name, '('); | 1155 | eoa = strchr(gn->name, '('); | |
1156 | eon = strchr(gn->name, ')'); | 1156 | eon = strchr(gn->name, ')'); | |
1157 | if (eoa == NULL || eon == NULL) | 1157 | if (eoa == NULL || eon == NULL) | |
1158 | continue; | 1158 | continue; | |
1159 | *eoa = '\0'; | 1159 | *eoa = '\0'; | |
1160 | *eon = '\0'; | 1160 | *eon = '\0'; | |
1161 | Var_Set(MEMBER, eoa + 1, gn); | 1161 | Var_Set(MEMBER, eoa + 1, gn); | |
1162 | Var_Set(ARCHIVE, gn->name, gn); | 1162 | Var_Set(ARCHIVE, gn->name, gn); | |
1163 | *eoa = '('; | 1163 | *eoa = '('; | |
1164 | *eon = ')'; | 1164 | *eon = ')'; | |
1165 | } | 1165 | } | |
1166 | 1166 | |||
1167 | (void)Dir_MTime(gn, 0); | 1167 | (void)Dir_MTime(gn, 0); | |
1168 | Var_Set(TARGET, GNode_Path(gn), gn); | 1168 | Var_Set(TARGET, GNode_Path(gn), gn); | |
1169 | UnmarkChildren(gn); | 1169 | UnmarkChildren(gn); | |
1170 | HandleUseNodes(gn); | 1170 | HandleUseNodes(gn); | |
1171 | 1171 | |||
1172 | if ((gn->type & OP_MADE) == 0) | 1172 | if ((gn->type & OP_MADE) == 0) | |
1173 | Suff_FindDeps(gn); | 1173 | Suff_FindDeps(gn); | |
1174 | else { | 1174 | else { | |
1175 | /* Pretend we made all this node's children */ | 1175 | /* Pretend we made all this node's children */ | |
1176 | Lst_ForEachUntil(gn->children, MakeFindChild, gn); | 1176 | Lst_ForEachUntil(gn->children, MakeFindChild, gn); | |
1177 | if (gn->unmade != 0) | 1177 | if (gn->unmade != 0) | |
1178 | printf("Warning: %s%s still has %d unmade children\n", | 1178 | printf("Warning: %s%s still has %d unmade children\n", | |
1179 | gn->name, gn->cohort_num, gn->unmade); | 1179 | gn->name, gn->cohort_num, gn->unmade); | |
1180 | } | 1180 | } | |
1181 | 1181 | |||
1182 | if (gn->unmade != 0) | 1182 | if (gn->unmade != 0) | |
1183 | Lst_ForEachUntil(gn->children, MakeAddChild, examine); | 1183 | Lst_ForEachUntil(gn->children, MakeAddChild, examine); | |
1184 | } | 1184 | } | |
1185 | 1185 | |||
1186 | Lst_Free(examine); | 1186 | Lst_Free(examine); | |
1187 | } | 1187 | } | |
1188 | 1188 | |||
1189 | /* Make the .WAIT node depend on the previous children */ | 1189 | /* Make the .WAIT node depend on the previous children */ | |
1190 | static void | 1190 | static void | |
1191 | add_wait_dependency(GNodeListNode *owln, GNode *wn) | 1191 | add_wait_dependency(GNodeListNode *owln, GNode *wn) | |
1192 | { | 1192 | { | |
1193 | GNodeListNode *cln; | 1193 | GNodeListNode *cln; | |
1194 | GNode *cn; | 1194 | GNode *cn; | |
1195 | 1195 | |||
1196 | for (cln = owln; (cn = cln->datum) != wn; cln = cln->next) { | 1196 | for (cln = owln; (cn = cln->datum) != wn; cln = cln->next) { | |
1197 | DEBUG3(MAKE, ".WAIT: add dependency %s%s -> %s\n", | 1197 | DEBUG3(MAKE, ".WAIT: add dependency %s%s -> %s\n", | |
1198 | cn->name, cn->cohort_num, wn->name); | 1198 | cn->name, cn->cohort_num, wn->name); | |
1199 | 1199 | |||
1200 | /* XXX: This pattern should be factored out, it repeats often */ | 1200 | /* XXX: This pattern should be factored out, it repeats often */ | |
1201 | Lst_Append(wn->children, cn); | 1201 | Lst_Append(wn->children, cn); | |
1202 | wn->unmade++; | 1202 | wn->unmade++; | |
1203 | Lst_Append(cn->parents, wn); | 1203 | Lst_Append(cn->parents, wn); | |
1204 | } | 1204 | } | |
1205 | } | 1205 | } | |
1206 | 1206 | |||
1207 | /* Convert .WAIT nodes into dependencies. */ | 1207 | /* Convert .WAIT nodes into dependencies. */ | |
1208 | static void | 1208 | static void | |
1209 | Make_ProcessWait(GNodeList *targs) | 1209 | Make_ProcessWait(GNodeList *targs) | |
1210 | { | 1210 | { | |
1211 | GNode *pgn; /* 'parent' node we are examining */ | 1211 | GNode *pgn; /* 'parent' node we are examining */ | |
1212 | GNodeListNode *owln; /* Previous .WAIT node */ | 1212 | GNodeListNode *owln; /* Previous .WAIT node */ | |
1213 | GNodeList *examine; /* List of targets to examine */ | 1213 | GNodeList *examine; /* List of targets to examine */ | |
1214 | 1214 | |||
1215 | /* | 1215 | /* | |
1216 | * We need all the nodes to have a common parent in order for the | 1216 | * We need all the nodes to have a common parent in order for the | |
1217 | * .WAIT and .ORDER scheduling to work. | 1217 | * .WAIT and .ORDER scheduling to work. | |
1218 | * Perhaps this should be done earlier... | 1218 | * Perhaps this should be done earlier... | |
1219 | */ | 1219 | */ | |
1220 | 1220 | |||
1221 | pgn = Targ_NewGN(".MAIN"); | 1221 | pgn = Targ_NewGN(".MAIN"); | |
1222 | pgn->flags = REMAKE; | 1222 | pgn->flags = REMAKE; | |
1223 | pgn->type = OP_PHONY | OP_DEPENDS; | 1223 | pgn->type = OP_PHONY | OP_DEPENDS; | |
1224 | /* Get it displayed in the diag dumps */ | 1224 | /* Get it displayed in the diag dumps */ | |
1225 | Lst_Prepend(Targ_List(), pgn); | 1225 | Lst_Prepend(Targ_List(), pgn); | |
1226 | 1226 | |||
1227 | { | 1227 | { | |
1228 | GNodeListNode *ln; | 1228 | GNodeListNode *ln; | |
1229 | for (ln = targs->first; ln != NULL; ln = ln->next) { | 1229 | for (ln = targs->first; ln != NULL; ln = ln->next) { | |
1230 | GNode *cgn = ln->datum; | 1230 | GNode *cgn = ln->datum; | |
1231 | 1231 | |||
1232 | Lst_Append(pgn->children, cgn); | 1232 | Lst_Append(pgn->children, cgn); | |
1233 | Lst_Append(cgn->parents, pgn); | 1233 | Lst_Append(cgn->parents, pgn); | |
1234 | pgn->unmade++; | 1234 | pgn->unmade++; | |
1235 | } | 1235 | } | |
1236 | } | 1236 | } | |
1237 | 1237 | |||
1238 | /* Start building with the 'dummy' .MAIN' node */ | 1238 | /* Start building with the 'dummy' .MAIN' node */ | |
1239 | MakeBuildChild(pgn, NULL); | 1239 | MakeBuildChild(pgn, NULL); | |
1240 | 1240 | |||
1241 | examine = Lst_New(); | 1241 | examine = Lst_New(); | |
1242 | Lst_Append(examine, pgn); | 1242 | Lst_Append(examine, pgn); | |
1243 | 1243 | |||
1244 | while (!Lst_IsEmpty(examine)) { | 1244 | while (!Lst_IsEmpty(examine)) { | |
1245 | GNodeListNode *ln; | 1245 | GNodeListNode *ln; | |
1246 | 1246 | |||
1247 | pgn = Lst_Dequeue(examine); | 1247 | pgn = Lst_Dequeue(examine); | |
1248 | 1248 | |||
1249 | /* We only want to process each child-list once */ | 1249 | /* We only want to process each child-list once */ | |
1250 | if (pgn->flags & DONE_WAIT) | 1250 | if (pgn->flags & DONE_WAIT) | |
1251 | continue; | 1251 | continue; | |
1252 | pgn->flags |= DONE_WAIT; | 1252 | pgn->flags |= DONE_WAIT; | |
1253 | DEBUG1(MAKE, "Make_ProcessWait: examine %s\n", pgn->name); | 1253 | DEBUG1(MAKE, "Make_ProcessWait: examine %s\n", pgn->name); | |
1254 | 1254 | |||
1255 | if (pgn->type & OP_DOUBLEDEP) | 1255 | if (pgn->type & OP_DOUBLEDEP) | |
1256 | Lst_PrependAll(examine, pgn->cohorts); | 1256 | Lst_PrependAll(examine, pgn->cohorts); | |
1257 | 1257 | |||
1258 | owln = pgn->children->first; | 1258 | owln = pgn->children->first; | |
1259 | for (ln = pgn->children->first; ln != NULL; ln = ln->next) { | 1259 | for (ln = pgn->children->first; ln != NULL; ln = ln->next) { | |
1260 | GNode *cgn = ln->datum; | 1260 | GNode *cgn = ln->datum; | |
1261 | if (cgn->type & OP_WAIT) { | 1261 | if (cgn->type & OP_WAIT) { | |
1262 | add_wait_dependency(owln, cgn); | 1262 | add_wait_dependency(owln, cgn); | |
1263 | owln = ln; | 1263 | owln = ln; | |
1264 | } else { | 1264 | } else { | |
1265 | Lst_Append(examine, cgn); | 1265 | Lst_Append(examine, cgn); | |
1266 | } | 1266 | } | |
1267 | } | 1267 | } | |
1268 | } | 1268 | } | |
1269 | 1269 | |||
1270 | Lst_Free(examine); | 1270 | Lst_Free(examine); | |
1271 | } | 1271 | } | |
1272 | 1272 | |||
1273 | /*- | 1273 | /*- | |
1274 | *----------------------------------------------------------------------- | 1274 | *----------------------------------------------------------------------- | |
1275 | * Make_Run -- | 1275 | * Make_Run -- | |
1276 | * Initialize the nodes to remake and the list of nodes which are | 1276 | * Initialize the nodes to remake and the list of nodes which are | |
1277 | * ready to be made by doing a breadth-first traversal of the graph | 1277 | * ready to be made by doing a breadth-first traversal of the graph | |
1278 | * starting from the nodes in the given list. Once this traversal | 1278 | * starting from the nodes in the given list. Once this traversal | |
1279 | * is finished, all the 'leaves' of the graph are in the toBeMade | 1279 | * is finished, all the 'leaves' of the graph are in the toBeMade | |
1280 | * queue. | 1280 | * queue. | |
1281 | * Using this queue and the Job module, work back up the graph, | 1281 | * Using this queue and the Job module, work back up the graph, | |
1282 | * calling on MakeStartJobs to keep the job table as full as | 1282 | * calling on MakeStartJobs to keep the job table as full as | |
1283 | * possible. | 1283 | * possible. | |
1284 | * | 1284 | * | |
1285 | * Input: | 1285 | * Input: | |
1286 | * targs the initial list of targets | 1286 | * targs the initial list of targets | |
1287 | * | 1287 | * | |
1288 | * Results: | 1288 | * Results: | |
1289 | * TRUE if work was done. FALSE otherwise. | 1289 | * TRUE if work was done. FALSE otherwise. | |
1290 | * | 1290 | * | |
1291 | * Side Effects: | 1291 | * Side Effects: | |
1292 | * The make field of all nodes involved in the creation of the given | 1292 | * The make field of all nodes involved in the creation of the given | |
1293 | * targets is set to 1. The toBeMade list is set to contain all the | 1293 | * targets is set to 1. The toBeMade list is set to contain all the | |
1294 | * 'leaves' of these subgraphs. | 1294 | * 'leaves' of these subgraphs. | |
1295 | *----------------------------------------------------------------------- | 1295 | *----------------------------------------------------------------------- | |
1296 | */ | 1296 | */ | |
1297 | Boolean | 1297 | Boolean | |
1298 | Make_Run(GNodeList *targs) | 1298 | Make_Run(GNodeList *targs) | |
1299 | { | 1299 | { | |
1300 | int errors; /* Number of errors the Job module reports */ | 1300 | int errors; /* Number of errors the Job module reports */ | |
1301 | 1301 | |||
1302 | /* Start trying to make the current targets... */ | 1302 | /* Start trying to make the current targets... */ | |
1303 | toBeMade = Lst_New(); | 1303 | toBeMade = Lst_New(); | |
1304 | 1304 | |||
1305 | Make_ExpandUse(targs); | 1305 | Make_ExpandUse(targs); | |
1306 | Make_ProcessWait(targs); | 1306 | Make_ProcessWait(targs); | |
1307 | 1307 | |||
1308 | if (DEBUG(MAKE)) { | 1308 | if (DEBUG(MAKE)) { | |
1309 | debug_printf("#***# full graph\n"); | 1309 | debug_printf("#***# full graph\n"); | |
1310 | Targ_PrintGraph(1); | 1310 | Targ_PrintGraph(1); | |
1311 | } | 1311 | } | |
1312 | 1312 | |||
1313 | if (opts.queryFlag) { | 1313 | if (opts.queryFlag) { | |
1314 | /* | 1314 | /* | |
1315 | * We wouldn't do any work unless we could start some jobs in the | 1315 | * We wouldn't do any work unless we could start some jobs in the | |
1316 | * next loop... (we won't actually start any, of course, this is just | 1316 | * next loop... (we won't actually start any, of course, this is just | |
1317 | * to see if any of the targets was out of date) | 1317 | * to see if any of the targets was out of date) | |
1318 | */ | 1318 | */ | |
1319 | return MakeStartJobs(); | 1319 | return MakeStartJobs(); | |
1320 | } | 1320 | } | |
1321 | /* | 1321 | /* | |
1322 | * Initialization. At the moment, no jobs are running and until some | 1322 | * Initialization. At the moment, no jobs are running and until some | |
1323 | * get started, nothing will happen since the remaining upward | 1323 | * get started, nothing will happen since the remaining upward | |
1324 | * traversal of the graph is performed by the routines in job.c upon | 1324 | * traversal of the graph is performed by the routines in job.c upon | |
1325 | * the finishing of a job. So we fill the Job table as much as we can | 1325 | * the finishing of a job. So we fill the Job table as much as we can | |
1326 | * before going into our loop. | 1326 | * before going into our loop. | |
1327 | */ | 1327 | */ | |
1328 | (void)MakeStartJobs(); | 1328 | (void)MakeStartJobs(); | |
1329 | 1329 | |||
1330 | /* | 1330 | /* | |
1331 | * Main Loop: The idea here is that the ending of jobs will take | 1331 | * Main Loop: The idea here is that the ending of jobs will take | |
1332 | * care of the maintenance of data structures and the waiting for output | 1332 | * care of the maintenance of data structures and the waiting for output | |
1333 | * will cause us to be idle most of the time while our children run as | 1333 | * will cause us to be idle most of the time while our children run as | |
1334 | * much as possible. Because the job table is kept as full as possible, | 1334 | * much as possible. Because the job table is kept as full as possible, | |
1335 | * the only time when it will be empty is when all the jobs which need | 1335 | * the only time when it will be empty is when all the jobs which need | |
1336 | * running have been run, so that is the end condition of this loop. | 1336 | * running have been run, so that is the end condition of this loop. | |
1337 | * Note that the Job module will exit if there were any errors unless the | 1337 | * Note that the Job module will exit if there were any errors unless the | |
1338 | * keepgoing flag was given. | 1338 | * keepgoing flag was given. | |
1339 | */ | 1339 | */ | |
1340 | while (!Lst_IsEmpty(toBeMade) || jobTokensRunning > 0) { | 1340 | while (!Lst_IsEmpty(toBeMade) || jobTokensRunning > 0) { | |
1341 | Job_CatchOutput(); | 1341 | Job_CatchOutput(); | |
1342 | (void)MakeStartJobs(); | 1342 | (void)MakeStartJobs(); | |
1343 | } | 1343 | } | |
1344 | 1344 | |||
1345 | errors = Job_Finish(); | 1345 | errors = Job_Finish(); | |
1346 | 1346 | |||
1347 | /* | 1347 | /* | |
1348 | * Print the final status of each target. E.g. if it wasn't made | 1348 | * Print the final status of each target. E.g. if it wasn't made | |
1349 | * because some inferior reported an error. | 1349 | * because some inferior reported an error. | |
1350 | */ | 1350 | */ | |
1351 | DEBUG1(MAKE, "done: errors %d\n", errors); | 1351 | DEBUG1(MAKE, "done: errors %d\n", errors); | |
1352 | if (errors == 0) { | 1352 | if (errors == 0) { | |
1353 | MakePrintStatusList(targs, &errors); | 1353 | MakePrintStatusList(targs, &errors); | |
1354 | if (DEBUG(MAKE)) { | 1354 | if (DEBUG(MAKE)) { | |
1355 | debug_printf("done: errors %d\n", errors); | 1355 | debug_printf("done: errors %d\n", errors); | |
1356 | if (errors) | 1356 | if (errors) | |
1357 | Targ_PrintGraph(4); | 1357 | Targ_PrintGraph(4); | |
1358 | } | 1358 | } | |
1359 | } | 1359 | } | |
1360 | return errors != 0; | 1360 | return errors != 0; | |
1361 | } | 1361 | } |
--- src/usr.bin/make/make.h 2020/10/31 11:54:33 1.178
+++ src/usr.bin/make/make.h 2020/11/01 17:47:26 1.179
@@ -1,726 +1,726 @@ | @@ -1,726 +1,726 @@ | |||
1 | /* $NetBSD: make.h,v 1.178 2020/10/31 11:54:33 rillig Exp $ */ | 1 | /* $NetBSD: make.h,v 1.179 2020/11/01 17:47:26 rillig Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 1988, 1989, 1990, 1993 | 4 | * Copyright (c) 1988, 1989, 1990, 1993 | |
5 | * The Regents of the University of California. All rights reserved. | 5 | * The Regents of the University of California. All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to Berkeley by | 7 | * This code is derived from software contributed to Berkeley by | |
8 | * Adam de Boor. | 8 | * Adam de Boor. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | 15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | 16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | 17 | * documentation and/or other materials provided with the distribution. | |
18 | * 3. Neither the name of the University nor the names of its contributors | 18 | * 3. Neither the name of the University nor the names of its contributors | |
19 | * may be used to endorse or promote products derived from this software | 19 | * may be used to endorse or promote products derived from this software | |
20 | * without specific prior written permission. | 20 | * without specific prior written permission. | |
21 | * | 21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
32 | * SUCH DAMAGE. | 32 | * SUCH DAMAGE. | |
33 | * | 33 | * | |
34 | * from: @(#)make.h 8.3 (Berkeley) 6/13/95 | 34 | * from: @(#)make.h 8.3 (Berkeley) 6/13/95 | |
35 | */ | 35 | */ | |
36 | 36 | |||
37 | /* | 37 | /* | |
38 | * Copyright (c) 1989 by Berkeley Softworks | 38 | * Copyright (c) 1989 by Berkeley Softworks | |
39 | * All rights reserved. | 39 | * All rights reserved. | |
40 | * | 40 | * | |
41 | * This code is derived from software contributed to Berkeley by | 41 | * This code is derived from software contributed to Berkeley by | |
42 | * Adam de Boor. | 42 | * Adam de Boor. | |
43 | * | 43 | * | |
44 | * Redistribution and use in source and binary forms, with or without | 44 | * Redistribution and use in source and binary forms, with or without | |
45 | * modification, are permitted provided that the following conditions | 45 | * modification, are permitted provided that the following conditions | |
46 | * are met: | 46 | * are met: | |
47 | * 1. Redistributions of source code must retain the above copyright | 47 | * 1. Redistributions of source code must retain the above copyright | |
48 | * notice, this list of conditions and the following disclaimer. | 48 | * notice, this list of conditions and the following disclaimer. | |
49 | * 2. Redistributions in binary form must reproduce the above copyright | 49 | * 2. Redistributions in binary form must reproduce the above copyright | |
50 | * notice, this list of conditions and the following disclaimer in the | 50 | * notice, this list of conditions and the following disclaimer in the | |
51 | * documentation and/or other materials provided with the distribution. | 51 | * documentation and/or other materials provided with the distribution. | |
52 | * 3. All advertising materials mentioning features or use of this software | 52 | * 3. All advertising materials mentioning features or use of this software | |
53 | * must display the following acknowledgement: | 53 | * must display the following acknowledgement: | |
54 | * This product includes software developed by the University of | 54 | * This product includes software developed by the University of | |
55 | * California, Berkeley and its contributors. | 55 | * California, Berkeley and its contributors. | |
56 | * 4. Neither the name of the University nor the names of its contributors | 56 | * 4. Neither the name of the University nor the names of its contributors | |
57 | * may be used to endorse or promote products derived from this software | 57 | * may be used to endorse or promote products derived from this software | |
58 | * without specific prior written permission. | 58 | * without specific prior written permission. | |
59 | * | 59 | * | |
60 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 60 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
61 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 61 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
62 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 62 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
63 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 63 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
64 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 64 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
65 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 65 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
66 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 66 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
67 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 67 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
68 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 68 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
69 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 69 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
70 | * SUCH DAMAGE. | 70 | * SUCH DAMAGE. | |
71 | * | 71 | * | |
72 | * from: @(#)make.h 8.3 (Berkeley) 6/13/95 | 72 | * from: @(#)make.h 8.3 (Berkeley) 6/13/95 | |
73 | */ | 73 | */ | |
74 | 74 | |||
75 | /*- | 75 | /*- | |
76 | * make.h -- | 76 | * make.h -- | |
77 | * The global definitions for pmake | 77 | * The global definitions for pmake | |
78 | */ | 78 | */ | |
79 | 79 | |||
80 | #ifndef MAKE_MAKE_H | 80 | #ifndef MAKE_MAKE_H | |
81 | #define MAKE_MAKE_H | 81 | #define MAKE_MAKE_H | |
82 | 82 | |||
83 | #include <sys/types.h> | 83 | #include <sys/types.h> | |
84 | #include <sys/param.h> | 84 | #include <sys/param.h> | |
85 | #include <sys/stat.h> | 85 | #include <sys/stat.h> | |
86 | 86 | |||
87 | #include <assert.h> | 87 | #include <assert.h> | |
88 | #include <ctype.h> | 88 | #include <ctype.h> | |
89 | #include <fcntl.h> | 89 | #include <fcntl.h> | |
90 | #include <stdarg.h> | 90 | #include <stdarg.h> | |
91 | #include <stdio.h> | 91 | #include <stdio.h> | |
92 | #include <stdlib.h> | 92 | #include <stdlib.h> | |
93 | #include <string.h> | 93 | #include <string.h> | |
94 | #include <unistd.h> | 94 | #include <unistd.h> | |
95 | 95 | |||
96 | #ifdef BSD4_4 | 96 | #ifdef BSD4_4 | |
97 | # include <sys/cdefs.h> | 97 | # include <sys/cdefs.h> | |
98 | #endif | 98 | #endif | |
99 | 99 | |||
100 | #ifndef FD_CLOEXEC | 100 | #ifndef FD_CLOEXEC | |
101 | #define FD_CLOEXEC 1 | 101 | #define FD_CLOEXEC 1 | |
102 | #endif | 102 | #endif | |
103 | 103 | |||
104 | #if defined(__GNUC__) | 104 | #if defined(__GNUC__) | |
105 | #define MAKE_GNUC_PREREQ(x, y) \ | 105 | #define MAKE_GNUC_PREREQ(x, y) \ | |
106 | ((__GNUC__ == (x) && __GNUC_MINOR__ >= (y)) || \ | 106 | ((__GNUC__ == (x) && __GNUC_MINOR__ >= (y)) || \ | |
107 | (__GNUC__ > (x))) | 107 | (__GNUC__ > (x))) | |
108 | #else /* defined(__GNUC__) */ | 108 | #else /* defined(__GNUC__) */ | |
109 | #define MAKE_GNUC_PREREQ(x, y) 0 | 109 | #define MAKE_GNUC_PREREQ(x, y) 0 | |
110 | #endif /* defined(__GNUC__) */ | 110 | #endif /* defined(__GNUC__) */ | |
111 | 111 | |||
112 | #if MAKE_GNUC_PREREQ(2, 7) | 112 | #if MAKE_GNUC_PREREQ(2, 7) | |
113 | #define MAKE_ATTR_UNUSED __attribute__((__unused__)) | 113 | #define MAKE_ATTR_UNUSED __attribute__((__unused__)) | |
114 | #else | 114 | #else | |
115 | #define MAKE_ATTR_UNUSED /* delete */ | 115 | #define MAKE_ATTR_UNUSED /* delete */ | |
116 | #endif | 116 | #endif | |
117 | 117 | |||
118 | #if MAKE_GNUC_PREREQ(2, 5) | 118 | #if MAKE_GNUC_PREREQ(2, 5) | |
119 | #define MAKE_ATTR_DEAD __attribute__((__noreturn__)) | 119 | #define MAKE_ATTR_DEAD __attribute__((__noreturn__)) | |
120 | #elif defined(__GNUC__) | 120 | #elif defined(__GNUC__) | |
121 | #define MAKE_ATTR_DEAD __volatile | 121 | #define MAKE_ATTR_DEAD __volatile | |
122 | #else | 122 | #else | |
123 | #define MAKE_ATTR_DEAD /* delete */ | 123 | #define MAKE_ATTR_DEAD /* delete */ | |
124 | #endif | 124 | #endif | |
125 | 125 | |||
126 | #if MAKE_GNUC_PREREQ(2, 7) | 126 | #if MAKE_GNUC_PREREQ(2, 7) | |
127 | #define MAKE_ATTR_PRINTFLIKE(fmtarg, firstvararg) \ | 127 | #define MAKE_ATTR_PRINTFLIKE(fmtarg, firstvararg) \ | |
128 | __attribute__((__format__ (__printf__, fmtarg, firstvararg))) | 128 | __attribute__((__format__ (__printf__, fmtarg, firstvararg))) | |
129 | #else | 129 | #else | |
130 | #define MAKE_ATTR_PRINTFLIKE(fmtarg, firstvararg) /* delete */ | 130 | #define MAKE_ATTR_PRINTFLIKE(fmtarg, firstvararg) /* delete */ | |
131 | #endif | 131 | #endif | |
132 | 132 | |||
133 | /* | 133 | /* | |
134 | * A boolean type is defined as an integer, not an enum, for historic reasons. | 134 | * A boolean type is defined as an integer, not an enum, for historic reasons. | |
135 | * The only allowed values are the constants TRUE and FALSE (1 and 0). | 135 | * The only allowed values are the constants TRUE and FALSE (1 and 0). | |
136 | */ | 136 | */ | |
137 | 137 | |||
138 | #ifdef USE_DOUBLE_BOOLEAN | 138 | #ifdef USE_DOUBLE_BOOLEAN | |
139 | /* During development, to find type mismatches in function declarations. */ | 139 | /* During development, to find type mismatches in function declarations. */ | |
140 | typedef double Boolean; | 140 | typedef double Boolean; | |
141 | #define TRUE 1.0 | 141 | #define TRUE 1.0 | |
142 | #define FALSE 0.0 | 142 | #define FALSE 0.0 | |
143 | #elif defined(USE_UCHAR_BOOLEAN) | 143 | #elif defined(USE_UCHAR_BOOLEAN) | |
144 | /* During development, to find code that depends on the exact value of TRUE or | 144 | /* During development, to find code that depends on the exact value of TRUE or | |
145 | * that stores other values in Boolean variables. */ | 145 | * that stores other values in Boolean variables. */ | |
146 | typedef unsigned char Boolean; | 146 | typedef unsigned char Boolean; | |
147 | #define TRUE ((unsigned char)0xFF) | 147 | #define TRUE ((unsigned char)0xFF) | |
148 | #define FALSE ((unsigned char)0x00) | 148 | #define FALSE ((unsigned char)0x00) | |
149 | #elif defined(USE_CHAR_BOOLEAN) | 149 | #elif defined(USE_CHAR_BOOLEAN) | |
150 | /* During development, to find code that uses a boolean as array index, via | 150 | /* During development, to find code that uses a boolean as array index, via | |
151 | * -Wchar-subscripts. */ | 151 | * -Wchar-subscripts. */ | |
152 | typedef char Boolean; | 152 | typedef char Boolean; | |
153 | #define TRUE ((char)-1) | 153 | #define TRUE ((char)-1) | |
154 | #define FALSE ((char)0x00) | 154 | #define FALSE ((char)0x00) | |
155 | #elif defined(USE_ENUM_BOOLEAN) | 155 | #elif defined(USE_ENUM_BOOLEAN) | |
156 | typedef enum Boolean { FALSE, TRUE } Boolean; | 156 | typedef enum Boolean { FALSE, TRUE } Boolean; | |
157 | #else | 157 | #else | |
158 | typedef int Boolean; | 158 | typedef int Boolean; | |
159 | #ifndef TRUE | 159 | #ifndef TRUE | |
160 | #define TRUE 1 | 160 | #define TRUE 1 | |
161 | #endif | 161 | #endif | |
162 | #ifndef FALSE | 162 | #ifndef FALSE | |
163 | #define FALSE 0 | 163 | #define FALSE 0 | |
164 | #endif | 164 | #endif | |
165 | #endif | 165 | #endif | |
166 | 166 | |||
167 | #include "lst.h" | 167 | #include "lst.h" | |
168 | #include "enum.h" | 168 | #include "enum.h" | |
169 | #include "hash.h" | 169 | #include "hash.h" | |
170 | #include "config.h" | 170 | #include "config.h" | |
171 | #include "buf.h" | 171 | #include "buf.h" | |
172 | #include "make_malloc.h" | 172 | #include "make_malloc.h" | |
173 | 173 | |||
174 | typedef enum { | 174 | typedef enum { | |
175 | UNMADE, /* Not examined yet */ | 175 | UNMADE, /* Not examined yet */ | |
176 | DEFERRED, /* Examined once (building child) */ | 176 | DEFERRED, /* Examined once (building child) */ | |
177 | REQUESTED, /* on toBeMade list */ | 177 | REQUESTED, /* on toBeMade list */ | |
178 | BEINGMADE, /* Target is already being made. | 178 | BEINGMADE, /* Target is already being made. | |
179 | * Indicates a cycle in the graph. */ | 179 | * Indicates a cycle in the graph. */ | |
180 | MADE, /* Was out-of-date and has been made */ | 180 | MADE, /* Was out-of-date and has been made */ | |
181 | UPTODATE, /* Was already up-to-date */ | 181 | UPTODATE, /* Was already up-to-date */ | |
182 | ERROR, /* An error occurred while it was being | 182 | ERROR, /* An error occurred while it was being | |
183 | * made (used only in compat mode) */ | 183 | * made (used only in compat mode) */ | |
184 | ABORTED /* The target was aborted due to an error | 184 | ABORTED /* The target was aborted due to an error | |
185 | * making an inferior (compat). */ | 185 | * making an inferior (compat). */ | |
186 | } GNodeMade; | 186 | } GNodeMade; | |
187 | 187 | |||
188 | /* The OP_ constants are used when parsing a dependency line as a way of | 188 | /* The OP_ constants are used when parsing a dependency line as a way of | |
189 | * communicating to other parts of the program the way in which a target | 189 | * communicating to other parts of the program the way in which a target | |
190 | * should be made. | 190 | * should be made. | |
191 | * | 191 | * | |
192 | * Some of the OP_ constants can be combined, others cannot. */ | 192 | * Some of the OP_ constants can be combined, others cannot. */ | |
193 | typedef enum GNodeType { | 193 | typedef enum GNodeType { | |
194 | /* The dependency operator ':' is the most common one. The commands of | 194 | /* The dependency operator ':' is the most common one. The commands of | |
195 | * this node are executed if any child is out-of-date. */ | 195 | * this node are executed if any child is out-of-date. */ | |
196 | OP_DEPENDS = 1 << 0, | 196 | OP_DEPENDS = 1 << 0, | |
197 | /* The dependency operator '!' always executes its commands, even if | 197 | /* The dependency operator '!' always executes its commands, even if | |
198 | * its children are up-to-date. */ | 198 | * its children are up-to-date. */ | |
199 | OP_FORCE = 1 << 1, | 199 | OP_FORCE = 1 << 1, | |
200 | /* The dependency operator '::' behaves like ':', except that it allows | 200 | /* The dependency operator '::' behaves like ':', except that it allows | |
201 | * multiple dependency groups to be defined. Each of these groups is | 201 | * multiple dependency groups to be defined. Each of these groups is | |
202 | * executed on its own, independently from the others. */ | 202 | * executed on its own, independently from the others. */ | |
203 | OP_DOUBLEDEP = 1 << 2, | 203 | OP_DOUBLEDEP = 1 << 2, | |
204 | 204 | |||
205 | /* Matches the dependency operators ':', '!' and '::'. */ | 205 | /* Matches the dependency operators ':', '!' and '::'. */ | |
206 | OP_OPMASK = OP_DEPENDS|OP_FORCE|OP_DOUBLEDEP, | 206 | OP_OPMASK = OP_DEPENDS|OP_FORCE|OP_DOUBLEDEP, | |
207 | 207 | |||
208 | /* Don't care if the target doesn't exist and can't be created */ | 208 | /* Don't care if the target doesn't exist and can't be created */ | |
209 | OP_OPTIONAL = 1 << 3, | 209 | OP_OPTIONAL = 1 << 3, | |
210 | /* Use associated commands for parents */ | 210 | /* Use associated commands for parents */ | |
211 | OP_USE = 1 << 4, | 211 | OP_USE = 1 << 4, | |
212 | /* Target is never out of date, but always execute commands anyway. | 212 | /* Target is never out of date, but always execute commands anyway. | |
213 | * Its time doesn't matter, so it has none...sort of */ | 213 | * Its time doesn't matter, so it has none...sort of */ | |
214 | OP_EXEC = 1 << 5, | 214 | OP_EXEC = 1 << 5, | |
215 | /* Ignore non-zero exit status from shell commands when creating the node */ | 215 | /* Ignore non-zero exit status from shell commands when creating the node */ | |
216 | OP_IGNORE = 1 << 6, | 216 | OP_IGNORE = 1 << 6, | |
217 | /* Don't remove the target when interrupted */ | 217 | /* Don't remove the target when interrupted */ | |
218 | OP_PRECIOUS = 1 << 7, | 218 | OP_PRECIOUS = 1 << 7, | |
219 | /* Don't echo commands when executed */ | 219 | /* Don't echo commands when executed */ | |
220 | OP_SILENT = 1 << 8, | 220 | OP_SILENT = 1 << 8, | |
221 | /* Target is a recursive make so its commands should always be executed | 221 | /* Target is a recursive make so its commands should always be executed | |
222 | * when it is out of date, regardless of the state of the -n or -t flags */ | 222 | * when it is out of date, regardless of the state of the -n or -t flags */ | |
223 | OP_MAKE = 1 << 9, | 223 | OP_MAKE = 1 << 9, | |
224 | /* Target is out-of-date only if any of its children was out-of-date */ | 224 | /* Target is out-of-date only if any of its children was out-of-date */ | |
225 | OP_JOIN = 1 << 10, | 225 | OP_JOIN = 1 << 10, | |
226 | /* Assume the children of the node have been already made */ | 226 | /* Assume the children of the node have been already made */ | |
227 | OP_MADE = 1 << 11, | 227 | OP_MADE = 1 << 11, | |
228 | /* Special .BEGIN, .END, .INTERRUPT */ | 228 | /* Special .BEGIN, .END, .INTERRUPT */ | |
229 | OP_SPECIAL = 1 << 12, | 229 | OP_SPECIAL = 1 << 12, | |
230 | /* Like .USE, only prepend commands */ | 230 | /* Like .USE, only prepend commands */ | |
231 | OP_USEBEFORE = 1 << 13, | 231 | OP_USEBEFORE = 1 << 13, | |
232 | /* The node is invisible to its parents. I.e. it doesn't show up in the | 232 | /* The node is invisible to its parents. I.e. it doesn't show up in the | |
233 | * parents' local variables. */ | 233 | * parents' local variables. */ | |
234 | OP_INVISIBLE = 1 << 14, | 234 | OP_INVISIBLE = 1 << 14, | |
235 | /* The node is exempt from normal 'main target' processing in parse.c */ | 235 | /* The node is exempt from normal 'main target' processing in parse.c */ | |
236 | OP_NOTMAIN = 1 << 15, | 236 | OP_NOTMAIN = 1 << 15, | |
237 | /* Not a file target; run always */ | 237 | /* Not a file target; run always */ | |
238 | OP_PHONY = 1 << 16, | 238 | OP_PHONY = 1 << 16, | |
239 | /* Don't search for file in the path */ | 239 | /* Don't search for file in the path */ | |
240 | OP_NOPATH = 1 << 17, | 240 | OP_NOPATH = 1 << 17, | |
241 | /* .WAIT phony node */ | 241 | /* .WAIT phony node */ | |
242 | OP_WAIT = 1 << 18, | 242 | OP_WAIT = 1 << 18, | |
243 | /* .NOMETA do not create a .meta file */ | 243 | /* .NOMETA do not create a .meta file */ | |
244 | OP_NOMETA = 1 << 19, | 244 | OP_NOMETA = 1 << 19, | |
245 | /* .META we _do_ want a .meta file */ | 245 | /* .META we _do_ want a .meta file */ | |
246 | OP_META = 1 << 20, | 246 | OP_META = 1 << 20, | |
247 | /* Do not compare commands in .meta file */ | 247 | /* Do not compare commands in .meta file */ | |
248 | OP_NOMETA_CMP = 1 << 21, | 248 | OP_NOMETA_CMP = 1 << 21, | |
249 | /* Possibly a submake node */ | 249 | /* Possibly a submake node */ | |
250 | OP_SUBMAKE = 1 << 22, | 250 | OP_SUBMAKE = 1 << 22, | |
251 | 251 | |||
252 | /* Attributes applied by PMake */ | 252 | /* Attributes applied by PMake */ | |
253 | 253 | |||
254 | /* The node is a transformation rule */ | 254 | /* The node is a transformation rule */ | |
255 | OP_TRANSFORM = 1 << 31, | 255 | OP_TRANSFORM = 1 << 31, | |
256 | /* Target is a member of an archive */ | 256 | /* Target is a member of an archive */ | |
257 | /* XXX: How does this differ from OP_ARCHV? */ | 257 | /* XXX: How does this differ from OP_ARCHV? */ | |
258 | OP_MEMBER = 1 << 30, | 258 | OP_MEMBER = 1 << 30, | |
259 | /* The node is a library, | 259 | /* The node is a library, | |
260 | * its name has the form "-l<libname>" */ | 260 | * its name has the form "-l<libname>" */ | |
261 | OP_LIB = 1 << 29, | 261 | OP_LIB = 1 << 29, | |
262 | /* The node is an archive member, | 262 | /* The node is an archive member, | |
263 | * its name has the form "archive(member)" */ | 263 | * its name has the form "archive(member)" */ | |
264 | /* XXX: How does this differ from OP_MEMBER? */ | 264 | /* XXX: How does this differ from OP_MEMBER? */ | |
265 | OP_ARCHV = 1 << 28, | 265 | OP_ARCHV = 1 << 28, | |
266 | /* Target has all the commands it should. Used when parsing to catch | 266 | /* Target has all the commands it should. Used when parsing to catch | |
267 | * multiple command groups for a target. Only applies to the dependency | 267 | * multiple command groups for a target. Only applies to the dependency | |
268 | * operators ':' and '!', but not to '::'. */ | 268 | * operators ':' and '!', but not to '::'. */ | |
269 | OP_HAS_COMMANDS = 1 << 27, | 269 | OP_HAS_COMMANDS = 1 << 27, | |
270 | /* The special command "..." has been seen. All further commands from | 270 | /* The special command "..." has been seen. All further commands from | |
271 | * this node will be saved on the .END node instead, to be executed at | 271 | * this node will be saved on the .END node instead, to be executed at | |
272 | * the very end. */ | 272 | * the very end. */ | |
273 | OP_SAVE_CMDS = 1 << 26, | 273 | OP_SAVE_CMDS = 1 << 26, | |
274 | /* Already processed by Suff_FindDeps */ | 274 | /* Already processed by Suff_FindDeps */ | |
275 | OP_DEPS_FOUND = 1 << 25, | 275 | OP_DEPS_FOUND = 1 << 25, | |
276 | /* Node found while expanding .ALLSRC */ | 276 | /* Node found while expanding .ALLSRC */ | |
277 | OP_MARK = 1 << 24, | 277 | OP_MARK = 1 << 24, | |
278 | 278 | |||
279 | OP_NOTARGET = OP_NOTMAIN | OP_USE | OP_EXEC | OP_TRANSFORM | 279 | OP_NOTARGET = OP_NOTMAIN | OP_USE | OP_EXEC | OP_TRANSFORM | |
280 | } GNodeType; | 280 | } GNodeType; | |
281 | 281 | |||
282 | typedef enum GNodeFlags { | 282 | typedef enum GNodeFlags { | |
283 | REMAKE = 0x0001, /* this target needs to be (re)made */ | 283 | REMAKE = 0x0001, /* this target needs to be (re)made */ | |
284 | CHILDMADE = 0x0002, /* children of this target were made */ | 284 | CHILDMADE = 0x0002, /* children of this target were made */ | |
285 | FORCE = 0x0004, /* children don't exist, and we pretend made */ | 285 | FORCE = 0x0004, /* children don't exist, and we pretend made */ | |
286 | DONE_WAIT = 0x0008, /* Set by Make_ProcessWait() */ | 286 | DONE_WAIT = 0x0008, /* Set by Make_ProcessWait() */ | |
287 | DONE_ORDER = 0x0010, /* Build requested by .ORDER processing */ | 287 | DONE_ORDER = 0x0010, /* Build requested by .ORDER processing */ | |
288 | FROM_DEPEND = 0x0020, /* Node created from .depend */ | 288 | FROM_DEPEND = 0x0020, /* Node created from .depend */ | |
289 | DONE_ALLSRC = 0x0040, /* We do it once only */ | 289 | DONE_ALLSRC = 0x0040, /* We do it once only */ | |
290 | CYCLE = 0x1000, /* Used by MakePrintStatus */ | 290 | CYCLE = 0x1000, /* Used by MakePrintStatus */ | |
291 | DONECYCLE = 0x2000, /* Used by MakePrintStatus */ | 291 | DONECYCLE = 0x2000, /* Used by MakePrintStatus */ | |
292 | INTERNAL = 0x4000 /* Internal use only */ | 292 | INTERNAL = 0x4000 /* Internal use only */ | |
293 | } GNodeFlags; | 293 | } GNodeFlags; | |
294 | 294 | |||
295 | typedef struct List StringList; | 295 | typedef struct List StringList; | |
296 | typedef struct ListNode StringListNode; | 296 | typedef struct ListNode StringListNode; | |
297 | 297 | |||
298 | typedef struct List GNodeList; | 298 | typedef struct List GNodeList; | |
299 | typedef struct ListNode GNodeListNode; | 299 | typedef struct ListNode GNodeListNode; | |
300 | 300 | |||
301 | typedef struct List /* of CachedDir */ SearchPath; | 301 | typedef struct List /* of CachedDir */ SearchPath; | |
302 | 302 | |||
303 | /* A graph node represents a target that can possibly be made, including its | 303 | /* A graph node represents a target that can possibly be made, including its | |
304 | * relation to other targets and a lot of other details. */ | 304 | * relation to other targets and a lot of other details. */ | |
305 | typedef struct GNode { | 305 | typedef struct GNode { | |
306 | /* The target's name, such as "clean" or "make.c" */ | 306 | /* The target's name, such as "clean" or "make.c" */ | |
307 | char *name; | 307 | char *name; | |
308 | /* The unexpanded name of a .USE node */ | 308 | /* The unexpanded name of a .USE node */ | |
309 | char *uname; | 309 | char *uname; | |
310 | /* The full pathname of the file belonging to the target. | 310 | /* The full pathname of the file belonging to the target. | |
311 | * XXX: What about .PHONY targets? These don't have an associated path. */ | 311 | * XXX: What about .PHONY targets? These don't have an associated path. */ | |
312 | char *path; | 312 | char *path; | |
313 | 313 | |||
314 | /* The type of operator used to define the sources (see the OP flags below). | 314 | /* The type of operator used to define the sources (see the OP flags below). | |
315 | * XXX: This looks like a wild mixture of type and flags. */ | 315 | * XXX: This looks like a wild mixture of type and flags. */ | |
316 | GNodeType type; | 316 | GNodeType type; | |
317 | GNodeFlags flags; | 317 | GNodeFlags flags; | |
318 | 318 | |||
319 | /* The state of processing on this node */ | 319 | /* The state of processing on this node */ | |
320 | GNodeMade made; | 320 | GNodeMade made; | |
321 | int unmade; /* The number of unmade children */ | 321 | int unmade; /* The number of unmade children */ | |
322 | 322 | |||
323 | /* The modification time; 0 means the node does not have a corresponding | 323 | /* The modification time; 0 means the node does not have a corresponding | |
324 | * file; see Make_OODate. */ | 324 | * file; see Make_OODate. */ | |
325 | time_t mtime; | 325 | time_t mtime; | |
326 | struct GNode *youngestChild; | 326 | struct GNode *youngestChild; | |
327 | 327 | |||
328 | /* The GNodes for which this node is an implied source. May be empty. | 328 | /* The GNodes for which this node is an implied source. May be empty. | |
329 | * For example, when there is an inference rule for .c.o, the node for | 329 | * For example, when there is an inference rule for .c.o, the node for | |
330 | * file.c has the node for file.o in this list. */ | 330 | * file.c has the node for file.o in this list. */ | |
331 | GNodeList *implicitParents; | 331 | GNodeList *implicitParents; | |
332 | 332 | |||
333 | /* Other nodes of the same name, for the '::' operator. */ | 333 | /* Other nodes of the same name, for the '::' operator. */ | |
334 | GNodeList *cohorts; | 334 | GNodeList *cohorts; | |
335 | 335 | |||
336 | /* The nodes that depend on this one, or in other words, the nodes for | 336 | /* The nodes that depend on this one, or in other words, the nodes for | |
337 | * which this is a source. */ | 337 | * which this is a source. */ | |
338 | GNodeList *parents; | 338 | GNodeList *parents; | |
339 | /* The nodes on which this one depends. */ | 339 | /* The nodes on which this one depends. */ | |
340 | GNodeList *children; | 340 | GNodeList *children; | |
341 | 341 | |||
342 | /* .ORDER nodes we need made. The nodes that must be made (if they're | 342 | /* .ORDER nodes we need made. The nodes that must be made (if they're | |
343 | * made) before this node can be made, but that do not enter into the | 343 | * made) before this node can be made, but that do not enter into the | |
344 | * datedness of this node. */ | 344 | * datedness of this node. */ | |
345 | GNodeList *order_pred; | 345 | GNodeList *order_pred; | |
346 | /* .ORDER nodes who need us. The nodes that must be made (if they're made | 346 | /* .ORDER nodes who need us. The nodes that must be made (if they're made | |
347 | * at all) after this node is made, but that do not depend on this node, | 347 | * at all) after this node is made, but that do not depend on this node, | |
348 | * in the normal sense. */ | 348 | * in the normal sense. */ | |
349 | GNodeList *order_succ; | 349 | GNodeList *order_succ; | |
350 | 350 | |||
351 | /* The "#n" suffix for this cohort, or "" for other nodes */ | 351 | /* The "#n" suffix for this cohort, or "" for other nodes */ | |
352 | char cohort_num[8]; | 352 | char cohort_num[8]; | |
353 | /* The number of unmade instances on the cohorts list */ | 353 | /* The number of unmade instances on the cohorts list */ | |
354 | int unmade_cohorts; | 354 | int unmade_cohorts; | |
355 | /* Pointer to the first instance of a '::' node; only set when on a | 355 | /* Pointer to the first instance of a '::' node; only set when on a | |
356 | * cohorts list */ | 356 | * cohorts list */ | |
357 | struct GNode *centurion; | 357 | struct GNode *centurion; | |
358 | 358 | |||
359 | /* Last time (sequence number) we tried to make this node */ | 359 | /* Last time (sequence number) we tried to make this node */ | |
360 | unsigned int checked_seqno; | 360 | unsigned int checked_seqno; | |
361 | 361 | |||
362 | /* The "local" variables that are specific to this target and this target | 362 | /* The "local" variables that are specific to this target and this target | |
363 | * only, such as $@, $<, $?. | 363 | * only, such as $@, $<, $?. | |
364 | * | 364 | * | |
365 | * Also used for the global variable scopes VAR_GLOBAL, VAR_CMDLINE, | 365 | * Also used for the global variable scopes VAR_GLOBAL, VAR_CMDLINE, | |
366 | * VAR_INTERNAL, which contain variables with arbitrary names. */ | 366 | * VAR_INTERNAL, which contain variables with arbitrary names. */ | |
367 | HashTable /* of Var pointer */ context; | 367 | HashTable /* of Var pointer */ context; | |
368 | 368 | |||
369 | /* The commands to be given to a shell to create this target. */ | 369 | /* The commands to be given to a shell to create this target. */ | |
370 | StringList *commands; | 370 | StringList *commands; | |
371 | 371 | |||
372 | /* Suffix for the node (determined by Suff_FindDeps and opaque to everyone | 372 | /* Suffix for the node (determined by Suff_FindDeps and opaque to everyone | |
373 | * but the Suff module) */ | 373 | * but the Suff module) */ | |
374 | struct Suff *suffix; | 374 | struct Suff *suffix; | |
375 | 375 | |||
376 | /* filename where the GNode got defined */ | 376 | /* filename where the GNode got defined */ | |
377 | const char *fname; | 377 | const char *fname; | |
378 | /* line number where the GNode got defined */ | 378 | /* line number where the GNode got defined */ | |
379 | int lineno; | 379 | int lineno; | |
380 | } GNode; | 380 | } GNode; | |
381 | 381 | |||
382 | /* | 382 | /* | |
383 | * Error levels for parsing. PARSE_FATAL means the process cannot continue | 383 | * Error levels for parsing. PARSE_FATAL means the process cannot continue | |
384 | * once the top-level makefile has been parsed. PARSE_WARNING and PARSE_INFO | 384 | * once the top-level makefile has been parsed. PARSE_WARNING and PARSE_INFO | |
385 | * mean it can. | 385 | * mean it can. | |
386 | */ | 386 | */ | |
387 | typedef enum ParseErrorLevel { | 387 | typedef enum ParseErrorLevel { | |
388 | PARSE_FATAL = 1, | 388 | PARSE_FATAL = 1, | |
389 | PARSE_WARNING, | 389 | PARSE_WARNING, | |
390 | PARSE_INFO | 390 | PARSE_INFO | |
391 | } ParseErrorLevel; | 391 | } ParseErrorLevel; | |
392 | 392 | |||
393 | /* | 393 | /* | |
394 | * Values returned by Cond_EvalLine and Cond_EvalCondition. | 394 | * Values returned by Cond_EvalLine and Cond_EvalCondition. | |
395 | */ | 395 | */ | |
396 | typedef enum CondEvalResult { | 396 | typedef enum CondEvalResult { | |
397 | COND_PARSE, /* Parse the next lines */ | 397 | COND_PARSE, /* Parse the next lines */ | |
398 | COND_SKIP, /* Skip the next lines */ | 398 | COND_SKIP, /* Skip the next lines */ | |
399 | COND_INVALID /* Not a conditional statement */ | 399 | COND_INVALID /* Not a conditional statement */ | |
400 | } CondEvalResult; | 400 | } CondEvalResult; | |
401 | 401 | |||
402 | /* | 402 | /* | |
403 | * Definitions for the "local" variables. Used only for clarity. | 403 | * Definitions for the "local" variables. Used only for clarity. | |
404 | */ | 404 | */ | |
405 | #define TARGET "@" /* Target of dependency */ | 405 | #define TARGET "@" /* Target of dependency */ | |
406 | #define OODATE "?" /* All out-of-date sources */ | 406 | #define OODATE "?" /* All out-of-date sources */ | |
407 | #define ALLSRC ">" /* All sources */ | 407 | #define ALLSRC ">" /* All sources */ | |
408 | #define IMPSRC "<" /* Source implied by transformation */ | 408 | #define IMPSRC "<" /* Source implied by transformation */ | |
409 | #define PREFIX "*" /* Common prefix */ | 409 | #define PREFIX "*" /* Common prefix */ | |
410 | #define ARCHIVE "!" /* Archive in "archive(member)" syntax */ | 410 | #define ARCHIVE "!" /* Archive in "archive(member)" syntax */ | |
411 | #define MEMBER "%" /* Member in "archive(member)" syntax */ | 411 | #define MEMBER "%" /* Member in "archive(member)" syntax */ | |
412 | 412 | |||
413 | #define FTARGET "@F" /* file part of TARGET */ | 413 | #define FTARGET "@F" /* file part of TARGET */ | |
414 | #define DTARGET "@D" /* directory part of TARGET */ | 414 | #define DTARGET "@D" /* directory part of TARGET */ | |
415 | #define FIMPSRC "<F" /* file part of IMPSRC */ | 415 | #define FIMPSRC "<F" /* file part of IMPSRC */ | |
416 | #define DIMPSRC "<D" /* directory part of IMPSRC */ | 416 | #define DIMPSRC "<D" /* directory part of IMPSRC */ | |
417 | #define FPREFIX "*F" /* file part of PREFIX */ | 417 | #define FPREFIX "*F" /* file part of PREFIX */ | |
418 | #define DPREFIX "*D" /* directory part of PREFIX */ | 418 | #define DPREFIX "*D" /* directory part of PREFIX */ | |
419 | 419 | |||
420 | /* | 420 | /* | |
421 | * Global Variables | 421 | * Global Variables | |
422 | */ | 422 | */ | |
423 | extern SearchPath *dirSearchPath; | 423 | extern SearchPath *dirSearchPath; | |
424 | /* The list of directories to search when | 424 | /* The list of directories to search when | |
425 | * looking for targets */ | 425 | * looking for targets */ | |
426 | extern Boolean allPrecious; /* True if every target is precious */ | 426 | extern Boolean allPrecious; /* True if every target is precious */ | |
427 | extern Boolean deleteOnError; /* True if failed targets should be deleted */ | 427 | extern Boolean deleteOnError; /* True if failed targets should be deleted */ | |
428 | extern Boolean doing_depend; /* TRUE if processing .depend */ | 428 | extern Boolean doing_depend; /* TRUE if processing .depend */ | |
429 | 429 | |||
430 | extern GNode *DEFAULT; /* .DEFAULT rule */ | 430 | extern GNode *DEFAULT; /* .DEFAULT rule */ | |
431 | 431 | |||
432 | extern GNode *VAR_INTERNAL; /* Variables defined internally by make | 432 | extern GNode *VAR_INTERNAL; /* Variables defined internally by make | |
433 | * which should not override those set by | 433 | * which should not override those set by | |
434 | * makefiles. | 434 | * makefiles. | |
435 | */ | 435 | */ | |
436 | extern GNode *VAR_GLOBAL; /* Variables defined in a global context, e.g | 436 | extern GNode *VAR_GLOBAL; /* Variables defined in a global context, e.g | |
437 | * in the Makefile itself */ | 437 | * in the Makefile itself */ | |
438 | extern GNode *VAR_CMDLINE; /* Variables defined on the command line */ | 438 | extern GNode *VAR_CMDLINE; /* Variables defined on the command line */ | |
439 | extern char var_Error[]; /* Value returned by Var_Parse when an error | 439 | extern char var_Error[]; /* Value returned by Var_Parse when an error | |
440 | * is encountered. It actually points to | 440 | * is encountered. It actually points to | |
441 | * an empty string, so naive callers needn't | 441 | * an empty string, so naive callers needn't | |
442 | * worry about it. */ | 442 | * worry about it. */ | |
443 | 443 | |||
444 | extern time_t now; /* The time at the start of this whole | 444 | extern time_t now; /* The time at the start of this whole | |
445 | * process */ | 445 | * process */ | |
446 | 446 | |||
447 | extern Boolean oldVars; /* Do old-style variable substitution */ | 447 | extern Boolean oldVars; /* Do old-style variable substitution */ | |
448 | 448 | |||
449 | extern SearchPath *sysIncPath; /* The system include path. */ | 449 | extern SearchPath *sysIncPath; /* The system include path. */ | |
450 | extern SearchPath *defSysIncPath; /* The default system include path. */ | 450 | extern SearchPath *defSysIncPath; /* The default system include path. */ | |
451 | 451 | |||
452 | extern char curdir[]; /* Startup directory */ | 452 | extern char curdir[]; /* Startup directory */ | |
453 | extern char *progname; /* The program name */ | 453 | extern char *progname; /* The program name */ | |
454 | extern char *makeDependfile; /* .depend */ | 454 | extern char *makeDependfile; /* .depend */ | |
455 | extern char **savedEnv; /* if we replaced environ this will be non-NULL */ | 455 | extern char **savedEnv; /* if we replaced environ this will be non-NULL */ | |
456 | 456 | |||
457 | extern int makelevel; | 457 | extern int makelevel; | |
458 | 458 | |||
459 | /* | 459 | /* | |
460 | * We cannot vfork() in a child of vfork(). | 460 | * We cannot vfork() in a child of vfork(). | |
461 | * Most systems do not enforce this but some do. | 461 | * Most systems do not enforce this but some do. | |
462 | */ | 462 | */ | |
463 | #define vFork() ((getpid() == myPid) ? vfork() : fork()) | 463 | #define vFork() ((getpid() == myPid) ? vfork() : fork()) | |
464 | extern pid_t myPid; | 464 | extern pid_t myPid; | |
465 | 465 | |||
466 | #define MAKEFLAGS ".MAKEFLAGS" | 466 | #define MAKEFLAGS ".MAKEFLAGS" | |
467 | #define MAKEOVERRIDES ".MAKEOVERRIDES" | 467 | #define MAKEOVERRIDES ".MAKEOVERRIDES" | |
468 | #define MAKE_JOB_PREFIX ".MAKE.JOB.PREFIX" /* prefix for job target output */ | 468 | #define MAKE_JOB_PREFIX ".MAKE.JOB.PREFIX" /* prefix for job target output */ | |
469 | #define MAKE_EXPORTED ".MAKE.EXPORTED" /* variables we export */ | 469 | #define MAKE_EXPORTED ".MAKE.EXPORTED" /* variables we export */ | |
470 | #define MAKE_MAKEFILES ".MAKE.MAKEFILES" /* all makefiles already loaded */ | 470 | #define MAKE_MAKEFILES ".MAKE.MAKEFILES" /* all makefiles already loaded */ | |
471 | #define MAKE_LEVEL ".MAKE.LEVEL" /* recursion level */ | 471 | #define MAKE_LEVEL ".MAKE.LEVEL" /* recursion level */ | |
472 | #define MAKEFILE_PREFERENCE ".MAKE.MAKEFILE_PREFERENCE" | 472 | #define MAKEFILE_PREFERENCE ".MAKE.MAKEFILE_PREFERENCE" | |
473 | #define MAKE_DEPENDFILE ".MAKE.DEPENDFILE" /* .depend */ | 473 | #define MAKE_DEPENDFILE ".MAKE.DEPENDFILE" /* .depend */ | |
474 | #define MAKE_MODE ".MAKE.MODE" | 474 | #define MAKE_MODE ".MAKE.MODE" | |
475 | #ifndef MAKE_LEVEL_ENV | 475 | #ifndef MAKE_LEVEL_ENV | |
476 | # define MAKE_LEVEL_ENV "MAKELEVEL" | 476 | # define MAKE_LEVEL_ENV "MAKELEVEL" | |
477 | #endif | 477 | #endif | |
478 | 478 | |||
479 | typedef enum DebugFlags { | 479 | typedef enum DebugFlags { | |
480 | DEBUG_ARCH = 1 << 0, | 480 | DEBUG_ARCH = 1 << 0, | |
481 | DEBUG_COND = 1 << 1, | 481 | DEBUG_COND = 1 << 1, | |
482 | DEBUG_DIR = 1 << 2, | 482 | DEBUG_DIR = 1 << 2, | |
483 | DEBUG_GRAPH1 = 1 << 3, | 483 | DEBUG_GRAPH1 = 1 << 3, | |
484 | DEBUG_GRAPH2 = 1 << 4, | 484 | DEBUG_GRAPH2 = 1 << 4, | |
485 | DEBUG_JOB = 1 << 5, | 485 | DEBUG_JOB = 1 << 5, | |
486 | DEBUG_MAKE = 1 << 6, | 486 | DEBUG_MAKE = 1 << 6, | |
487 | DEBUG_SUFF = 1 << 7, | 487 | DEBUG_SUFF = 1 << 7, | |
488 | DEBUG_TARG = 1 << 8, | 488 | DEBUG_TARG = 1 << 8, | |
489 | DEBUG_VAR = 1 << 9, | 489 | DEBUG_VAR = 1 << 9, | |
490 | DEBUG_FOR = 1 << 10, | 490 | DEBUG_FOR = 1 << 10, | |
491 | DEBUG_SHELL = 1 << 11, | 491 | DEBUG_SHELL = 1 << 11, | |
492 | DEBUG_ERROR = 1 << 12, | 492 | DEBUG_ERROR = 1 << 12, | |
493 | DEBUG_LOUD = 1 << 13, | 493 | DEBUG_LOUD = 1 << 13, | |
494 | DEBUG_META = 1 << 14, | 494 | DEBUG_META = 1 << 14, | |
495 | DEBUG_HASH = 1 << 15, | 495 | DEBUG_HASH = 1 << 15, | |
496 | 496 | |||
497 | DEBUG_GRAPH3 = 1 << 16, | 497 | DEBUG_GRAPH3 = 1 << 16, | |
498 | DEBUG_SCRIPT = 1 << 17, | 498 | DEBUG_SCRIPT = 1 << 17, | |
499 | DEBUG_PARSE = 1 << 18, | 499 | DEBUG_PARSE = 1 << 18, | |
500 | DEBUG_CWD = 1 << 19, | 500 | DEBUG_CWD = 1 << 19, | |
501 | 501 | |||
502 | DEBUG_LINT = 1 << 20 | 502 | DEBUG_LINT = 1 << 20 | |
503 | } DebugFlags; | 503 | } DebugFlags; | |
504 | 504 | |||
505 | #define CONCAT(a,b) a##b | 505 | #define CONCAT(a,b) a##b | |
506 | 506 | |||
507 | #define DEBUG(module) (opts.debug & CONCAT(DEBUG_,module)) | 507 | #define DEBUG(module) (opts.debug & CONCAT(DEBUG_,module)) | |
508 | 508 | |||
509 | void debug_printf(const char *, ...) MAKE_ATTR_PRINTFLIKE(1, 2); | 509 | void debug_printf(const char *, ...) MAKE_ATTR_PRINTFLIKE(1, 2); | |
510 | 510 | |||
511 | #define DEBUG0(module, text) \ | 511 | #define DEBUG0(module, text) \ | |
512 | if (!DEBUG(module)) (void)0; \ | 512 | if (!DEBUG(module)) (void)0; \ | |
513 | else debug_printf("%s", text) | 513 | else debug_printf("%s", text) | |
514 | 514 | |||
515 | #define DEBUG1(module, fmt, arg1) \ | 515 | #define DEBUG1(module, fmt, arg1) \ | |
516 | if (!DEBUG(module)) (void)0; \ | 516 | if (!DEBUG(module)) (void)0; \ | |
517 | else debug_printf(fmt, arg1) | 517 | else debug_printf(fmt, arg1) | |
518 | 518 | |||
519 | #define DEBUG2(module, fmt, arg1, arg2) \ | 519 | #define DEBUG2(module, fmt, arg1, arg2) \ | |
520 | if (!DEBUG(module)) (void)0; \ | 520 | if (!DEBUG(module)) (void)0; \ | |
521 | else debug_printf(fmt, arg1, arg2) | 521 | else debug_printf(fmt, arg1, arg2) | |
522 | 522 | |||
523 | #define DEBUG3(module, fmt, arg1, arg2, arg3) \ | 523 | #define DEBUG3(module, fmt, arg1, arg2, arg3) \ | |
524 | if (!DEBUG(module)) (void)0; \ | 524 | if (!DEBUG(module)) (void)0; \ | |
525 | else debug_printf(fmt, arg1, arg2, arg3) | 525 | else debug_printf(fmt, arg1, arg2, arg3) | |
526 | 526 | |||
527 | #define DEBUG4(module, fmt, arg1, arg2, arg3, arg4) \ | 527 | #define DEBUG4(module, fmt, arg1, arg2, arg3, arg4) \ | |
528 | if (!DEBUG(module)) (void)0; \ | 528 | if (!DEBUG(module)) (void)0; \ | |
529 | else debug_printf(fmt, arg1, arg2, arg3, arg4) | 529 | else debug_printf(fmt, arg1, arg2, arg3, arg4) | |
530 | 530 | |||
531 | #define DEBUG5(module, fmt, arg1, arg2, arg3, arg4, arg5) \ | 531 | #define DEBUG5(module, fmt, arg1, arg2, arg3, arg4, arg5) \ | |
532 | if (!DEBUG(module)) (void)0; \ | 532 | if (!DEBUG(module)) (void)0; \ | |
533 | else debug_printf(fmt, arg1, arg2, arg3, arg4, arg5) | 533 | else debug_printf(fmt, arg1, arg2, arg3, arg4, arg5) | |
534 | 534 | |||
535 | typedef enum PrintVarsMode { | 535 | typedef enum PrintVarsMode { | |
536 | COMPAT_VARS = 1, | 536 | COMPAT_VARS = 1, | |
537 | EXPAND_VARS | 537 | EXPAND_VARS | |
538 | } PrintVarsMode; | 538 | } PrintVarsMode; | |
539 | 539 | |||
540 | /* Command line options */ | 540 | /* Command line options */ | |
541 | typedef struct CmdOpts { | 541 | typedef struct CmdOpts { | |
542 | /* -B: whether we are make compatible */ | 542 | /* -B: whether we are make compatible */ | |
543 | Boolean compatMake; | 543 | Boolean compatMake; | |
544 | 544 | |||
545 | /* -d: debug control: There is one bit per module. It is up to the | 545 | /* -d: debug control: There is one bit per module. It is up to the | |
546 | * module what debug information to print. */ | 546 | * module what debug information to print. */ | |
547 | DebugFlags debug; | 547 | DebugFlags debug; | |
548 | 548 | |||
549 | /* -df: debug output is written here - default stderr */ | 549 | /* -df: debug output is written here - default stderr */ | |
550 | FILE *debug_file; | 550 | FILE *debug_file; | |
551 | 551 | |||
552 | /* -dV: for the -V option, print unexpanded variable values */ | 552 | /* -dV: for the -V option, print unexpanded variable values */ | |
553 | Boolean debugVflag; | 553 | Boolean debugVflag; | |
554 | 554 | |||
555 | /* -e: check environment variables before global variables */ | 555 | /* -e: check environment variables before global variables */ | |
556 | Boolean checkEnvFirst; | 556 | Boolean checkEnvFirst; | |
557 | 557 | |||
558 | /* -f: the makefiles to read */ | 558 | /* -f: the makefiles to read */ | |
559 | StringList *makefiles; | 559 | StringList *makefiles; | |
560 | 560 | |||
561 | /* -i: if true, ignore all errors from shell commands */ | 561 | /* -i: if true, ignore all errors from shell commands */ | |
562 | Boolean ignoreErrors; | 562 | Boolean ignoreErrors; | |
563 | 563 | |||
564 | /* -j: the maximum number of jobs that can run in parallel; | 564 | /* -j: the maximum number of jobs that can run in parallel; | |
565 | * this is coordinated with the submakes */ | 565 | * this is coordinated with the submakes */ | |
566 | int maxJobs; | 566 | int maxJobs; | |
567 | 567 | |||
568 | /* -k: if true, continue on unaffected portions of the graph when an | 568 | /* -k: if true, continue on unaffected portions of the graph when an | |
569 | * error occurs in one portion */ | 569 | * error occurs in one portion */ | |
570 | Boolean keepgoing; | 570 | Boolean keepgoing; | |
571 | 571 | |||
572 | /* -N: execute no commands from the targets */ | 572 | /* -N: execute no commands from the targets */ | |
573 | Boolean noRecursiveExecute; | 573 | Boolean noRecursiveExecute; | |
574 | 574 | |||
575 | /* -n: execute almost no commands from the targets */ | 575 | /* -n: execute almost no commands from the targets */ | |
576 | Boolean noExecute; | 576 | Boolean noExecute; | |
577 | 577 | |||
578 | /* -q: if true, we aren't supposed to really make anything, just see if | 578 | /* -q: if true, we aren't supposed to really make anything, just see if | |
579 | * the targets are out-of-date */ | 579 | * the targets are out-of-date */ | |
580 | Boolean queryFlag; | 580 | Boolean queryFlag; | |
581 | 581 | |||
582 | /* -r: raw mode, without loading the builtin rules. */ | 582 | /* -r: raw mode, without loading the builtin rules. */ | |
583 | Boolean noBuiltins; | 583 | Boolean noBuiltins; | |
584 | 584 | |||
585 | /* -s: don't echo the shell commands before executing them */ | 585 | /* -s: don't echo the shell commands before executing them */ | |
586 | Boolean beSilent; | 586 | Boolean beSilent; | |
587 | 587 | |||
588 | /* -t: touch the targets if they are out-of-date, but don't actually | 588 | /* -t: touch the targets if they are out-of-date, but don't actually | |
589 | * make them */ | 589 | * make them */ | |
590 | Boolean touchFlag; | 590 | Boolean touchFlag; | |
591 | 591 | |||
592 | /* -[Vv]: print expanded or unexpanded selected variables */ | 592 | /* -[Vv]: print expanded or unexpanded selected variables */ | |
593 | PrintVarsMode printVars; | 593 | PrintVarsMode printVars; | |
594 | /* -[Vv]: the variables to print */ | 594 | /* -[Vv]: the variables to print */ | |
595 | StringList *variables; | 595 | StringList *variables; | |
596 | 596 | |||
597 | /* -W: if true, makefile parsing warnings are treated as errors */ | 597 | /* -W: if true, makefile parsing warnings are treated as errors */ | |
598 | Boolean parseWarnFatal; | 598 | Boolean parseWarnFatal; | |
599 | 599 | |||
600 | /* -w: print Entering and Leaving for submakes */ | 600 | /* -w: print Entering and Leaving for submakes */ | |
601 | Boolean enterFlag; | 601 | Boolean enterFlag; | |
602 | 602 | |||
603 | /* -X: if true, do not export variables set on the command line to the | 603 | /* -X: if true, do not export variables set on the command line to the | |
604 | * environment. */ | 604 | * environment. */ | |
605 | Boolean varNoExportEnv; | 605 | Boolean varNoExportEnv; | |
606 | 606 | |||
607 | /* The target names specified on the command line. | 607 | /* The target names specified on the command line. | |
608 | * Used to resolve .if make(...) statements. */ | 608 | * Used to resolve .if make(...) statements. */ | |
609 | StringList *create; | 609 | StringList *create; | |
610 | 610 | |||
611 | } CmdOpts; | 611 | } CmdOpts; | |
612 | 612 | |||
613 | extern CmdOpts opts; | 613 | extern CmdOpts opts; | |
614 | 614 | |||
615 | #include "nonints.h" | 615 | #include "nonints.h" | |
616 | 616 | |||
617 | void Make_TimeStamp(GNode *, GNode *); | 617 | void Make_TimeStamp(GNode *, GNode *); | |
618 | Boolean Make_OODate(GNode *); | 618 | Boolean Make_OODate(GNode *); | |
619 | void Make_ExpandUse(GNodeList *); | 619 | void Make_ExpandUse(GNodeList *); | |
620 | time_t Make_Recheck(GNode *); | 620 | time_t Make_Recheck(GNode *); | |
621 | void Make_HandleUse(GNode *, GNode *); | 621 | void Make_HandleUse(GNode *, GNode *); | |
622 | void Make_Update(GNode *); | 622 | void Make_Update(GNode *); | |
623 | void Make_DoAllVar(GNode *); | 623 | void Make_DoAllVar(GNode *); | |
624 | Boolean Make_Run(GNodeList *); | 624 | Boolean Make_Run(GNodeList *); | |
625 | int dieQuietly(GNode *, int); | 625 | int dieQuietly(GNode *, int); | |
626 | void PrintOnError(GNode *, const char *); | 626 | void PrintOnError(GNode *, const char *); | |
627 | void Main_ExportMAKEFLAGS(Boolean); | 627 | void Main_ExportMAKEFLAGS(Boolean); | |
628 | Boolean Main_SetObjdir(const char *, ...) MAKE_ATTR_PRINTFLIKE(1, 2); | 628 | Boolean Main_SetObjdir(const char *, ...) MAKE_ATTR_PRINTFLIKE(1, 2); | |
629 | int mkTempFile(const char *, char **); | 629 | int mkTempFile(const char *, char **); | |
630 | int str2Lst_Append(StringList *, char *, const char *); | 630 | int str2Lst_Append(StringList *, char *, const char *); | |
631 | void GNode_FprintDetails(FILE *, const char *, const GNode *, const char *); | 631 | void GNode_FprintDetails(FILE *, const char *, const GNode *, const char *); | |
632 | Boolean NoExecute(GNode *gn); | 632 | Boolean GNode_ShouldExecute(GNode *gn); | |
633 | 633 | |||
634 | /* See if the node was seen on the left-hand side of a dependency operator. */ | 634 | /* See if the node was seen on the left-hand side of a dependency operator. */ | |
635 | static MAKE_ATTR_UNUSED Boolean | 635 | static MAKE_ATTR_UNUSED Boolean | |
636 | GNode_IsTarget(const GNode *gn) | 636 | GNode_IsTarget(const GNode *gn) | |
637 | { | 637 | { | |
638 | return (gn->type & OP_OPMASK) != 0; | 638 | return (gn->type & OP_OPMASK) != 0; | |
639 | } | 639 | } | |
640 | 640 | |||
641 | static MAKE_ATTR_UNUSED const char * | 641 | static MAKE_ATTR_UNUSED const char * | |
642 | GNode_Path(const GNode *gn) | 642 | GNode_Path(const GNode *gn) | |
643 | { | 643 | { | |
644 | return gn->path != NULL ? gn->path : gn->name; | 644 | return gn->path != NULL ? gn->path : gn->name; | |
645 | } | 645 | } | |
646 | 646 | |||
647 | static MAKE_ATTR_UNUSED const char * | 647 | static MAKE_ATTR_UNUSED const char * | |
648 | GNode_VarTarget(GNode *gn) { return Var_ValueDirect(TARGET, gn); } | 648 | GNode_VarTarget(GNode *gn) { return Var_ValueDirect(TARGET, gn); } | |
649 | static MAKE_ATTR_UNUSED const char * | 649 | static MAKE_ATTR_UNUSED const char * | |
650 | GNode_VarOodate(GNode *gn) { return Var_ValueDirect(OODATE, gn); } | 650 | GNode_VarOodate(GNode *gn) { return Var_ValueDirect(OODATE, gn); } | |
651 | static MAKE_ATTR_UNUSED const char * | 651 | static MAKE_ATTR_UNUSED const char * | |
652 | GNode_VarAllsrc(GNode *gn) { return Var_ValueDirect(ALLSRC, gn); } | 652 | GNode_VarAllsrc(GNode *gn) { return Var_ValueDirect(ALLSRC, gn); } | |
653 | static MAKE_ATTR_UNUSED const char * | 653 | static MAKE_ATTR_UNUSED const char * | |
654 | GNode_VarImpsrc(GNode *gn) { return Var_ValueDirect(IMPSRC, gn); } | 654 | GNode_VarImpsrc(GNode *gn) { return Var_ValueDirect(IMPSRC, gn); } | |
655 | static MAKE_ATTR_UNUSED const char * | 655 | static MAKE_ATTR_UNUSED const char * | |
656 | GNode_VarPrefix(GNode *gn) { return Var_ValueDirect(PREFIX, gn); } | 656 | GNode_VarPrefix(GNode *gn) { return Var_ValueDirect(PREFIX, gn); } | |
657 | static MAKE_ATTR_UNUSED const char * | 657 | static MAKE_ATTR_UNUSED const char * | |
658 | GNode_VarArchive(GNode *gn) { return Var_ValueDirect(ARCHIVE, gn); } | 658 | GNode_VarArchive(GNode *gn) { return Var_ValueDirect(ARCHIVE, gn); } | |
659 | static MAKE_ATTR_UNUSED const char * | 659 | static MAKE_ATTR_UNUSED const char * | |
660 | GNode_VarMember(GNode *gn) { return Var_ValueDirect(MEMBER, gn); } | 660 | GNode_VarMember(GNode *gn) { return Var_ValueDirect(MEMBER, gn); } | |
661 | 661 | |||
662 | #ifdef __GNUC__ | 662 | #ifdef __GNUC__ | |
663 | #define UNCONST(ptr) ({ \ | 663 | #define UNCONST(ptr) ({ \ | |
664 | union __unconst { \ | 664 | union __unconst { \ | |
665 | const void *__cp; \ | 665 | const void *__cp; \ | |
666 | void *__p; \ | 666 | void *__p; \ | |
667 | } __d; \ | 667 | } __d; \ | |
668 | __d.__cp = ptr, __d.__p; }) | 668 | __d.__cp = ptr, __d.__p; }) | |
669 | #else | 669 | #else | |
670 | #define UNCONST(ptr) (void *)(ptr) | 670 | #define UNCONST(ptr) (void *)(ptr) | |
671 | #endif | 671 | #endif | |
672 | 672 | |||
673 | /* At least GNU/Hurd systems lack hardcoded MAXPATHLEN/PATH_MAX */ | 673 | /* At least GNU/Hurd systems lack hardcoded MAXPATHLEN/PATH_MAX */ | |
674 | #include <limits.h> | 674 | #include <limits.h> | |
675 | #ifndef MAXPATHLEN | 675 | #ifndef MAXPATHLEN | |
676 | #define MAXPATHLEN 4096 | 676 | #define MAXPATHLEN 4096 | |
677 | #endif | 677 | #endif | |
678 | #ifndef PATH_MAX | 678 | #ifndef PATH_MAX | |
679 | #define PATH_MAX MAXPATHLEN | 679 | #define PATH_MAX MAXPATHLEN | |
680 | #endif | 680 | #endif | |
681 | 681 | |||
682 | #if defined(SYSV) | 682 | #if defined(SYSV) | |
683 | #define KILLPG(pid, sig) kill(-(pid), (sig)) | 683 | #define KILLPG(pid, sig) kill(-(pid), (sig)) | |
684 | #else | 684 | #else | |
685 | #define KILLPG(pid, sig) killpg((pid), (sig)) | 685 | #define KILLPG(pid, sig) killpg((pid), (sig)) | |
686 | #endif | 686 | #endif | |
687 | 687 | |||
688 | static inline MAKE_ATTR_UNUSED Boolean ch_isalnum(char ch) | 688 | static inline MAKE_ATTR_UNUSED Boolean ch_isalnum(char ch) | |
689 | { return isalnum((unsigned char)ch) != 0; } | 689 | { return isalnum((unsigned char)ch) != 0; } | |
690 | static inline MAKE_ATTR_UNUSED Boolean ch_isalpha(char ch) | 690 | static inline MAKE_ATTR_UNUSED Boolean ch_isalpha(char ch) | |
691 | { return isalpha((unsigned char)ch) != 0; } | 691 | { return isalpha((unsigned char)ch) != 0; } | |
692 | static inline MAKE_ATTR_UNUSED Boolean ch_isdigit(char ch) | 692 | static inline MAKE_ATTR_UNUSED Boolean ch_isdigit(char ch) | |
693 | { return isdigit((unsigned char)ch) != 0; } | 693 | { return isdigit((unsigned char)ch) != 0; } | |
694 | static inline MAKE_ATTR_UNUSED Boolean ch_isspace(char ch) | 694 | static inline MAKE_ATTR_UNUSED Boolean ch_isspace(char ch) | |
695 | { return isspace((unsigned char)ch) != 0; } | 695 | { return isspace((unsigned char)ch) != 0; } | |
696 | static inline MAKE_ATTR_UNUSED Boolean ch_isupper(char ch) | 696 | static inline MAKE_ATTR_UNUSED Boolean ch_isupper(char ch) | |
697 | { return isupper((unsigned char)ch) != 0; } | 697 | { return isupper((unsigned char)ch) != 0; } | |
698 | static inline MAKE_ATTR_UNUSED char ch_tolower(char ch) | 698 | static inline MAKE_ATTR_UNUSED char ch_tolower(char ch) | |
699 | { return (char)tolower((unsigned char)ch); } | 699 | { return (char)tolower((unsigned char)ch); } | |
700 | static inline MAKE_ATTR_UNUSED char ch_toupper(char ch) | 700 | static inline MAKE_ATTR_UNUSED char ch_toupper(char ch) | |
701 | { return (char)toupper((unsigned char)ch); } | 701 | { return (char)toupper((unsigned char)ch); } | |
702 | 702 | |||
703 | static inline MAKE_ATTR_UNUSED void | 703 | static inline MAKE_ATTR_UNUSED void | |
704 | cpp_skip_whitespace(const char **pp) | 704 | cpp_skip_whitespace(const char **pp) | |
705 | { | 705 | { | |
706 | while (ch_isspace(**pp)) | 706 | while (ch_isspace(**pp)) | |
707 | (*pp)++; | 707 | (*pp)++; | |
708 | } | 708 | } | |
709 | 709 | |||
710 | static inline MAKE_ATTR_UNUSED void | 710 | static inline MAKE_ATTR_UNUSED void | |
711 | pp_skip_whitespace(char **pp) | 711 | pp_skip_whitespace(char **pp) | |
712 | { | 712 | { | |
713 | while (ch_isspace(**pp)) | 713 | while (ch_isspace(**pp)) | |
714 | (*pp)++; | 714 | (*pp)++; | |
715 | } | 715 | } | |
716 | 716 | |||
717 | #ifdef MAKE_NATIVE | 717 | #ifdef MAKE_NATIVE | |
718 | # include <sys/cdefs.h> | 718 | # include <sys/cdefs.h> | |
719 | # ifndef lint | 719 | # ifndef lint | |
720 | # define MAKE_RCSID(id) __RCSID(id) | 720 | # define MAKE_RCSID(id) __RCSID(id) | |
721 | # endif | 721 | # endif | |
722 | #else | 722 | #else | |
723 | # define MAKE_RCSID(id) static volatile char rcsid[] = id | 723 | # define MAKE_RCSID(id) static volatile char rcsid[] = id | |
724 | #endif | 724 | #endif | |
725 | 725 | |||
726 | #endif /* MAKE_MAKE_H */ | 726 | #endif /* MAKE_MAKE_H */ |