1 |
|
|
/* $OpenBSD: compat.c,v 1.85 2015/01/23 13:38:16 espie Exp $ */ |
2 |
|
|
/* $NetBSD: compat.c,v 1.14 1996/11/06 17:59:01 christos Exp $ */ |
3 |
|
|
|
4 |
|
|
/* |
5 |
|
|
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California. |
6 |
|
|
* Copyright (c) 1988, 1989 by Adam de Boor |
7 |
|
|
* Copyright (c) 1989 by Berkeley Softworks |
8 |
|
|
* All rights reserved. |
9 |
|
|
* |
10 |
|
|
* This code is derived from software contributed to Berkeley by |
11 |
|
|
* Adam de Boor. |
12 |
|
|
* |
13 |
|
|
* Redistribution and use in source and binary forms, with or without |
14 |
|
|
* modification, are permitted provided that the following conditions |
15 |
|
|
* are met: |
16 |
|
|
* 1. Redistributions of source code must retain the above copyright |
17 |
|
|
* notice, this list of conditions and the following disclaimer. |
18 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
19 |
|
|
* notice, this list of conditions and the following disclaimer in the |
20 |
|
|
* documentation and/or other materials provided with the distribution. |
21 |
|
|
* 3. Neither the name of the University nor the names of its contributors |
22 |
|
|
* may be used to endorse or promote products derived from this software |
23 |
|
|
* without specific prior written permission. |
24 |
|
|
* |
25 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
26 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
27 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
28 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
29 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
30 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
31 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
32 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
33 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
34 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
35 |
|
|
* SUCH DAMAGE. |
36 |
|
|
*/ |
37 |
|
|
|
38 |
|
|
#include <limits.h> |
39 |
|
|
#include <signal.h> |
40 |
|
|
#include <stdint.h> |
41 |
|
|
#include <stdio.h> |
42 |
|
|
#include <stdlib.h> |
43 |
|
|
#include "config.h" |
44 |
|
|
#include "defines.h" |
45 |
|
|
#include "dir.h" |
46 |
|
|
#include "engine.h" |
47 |
|
|
#include "job.h" |
48 |
|
|
#include "compat.h" |
49 |
|
|
#include "suff.h" |
50 |
|
|
#include "var.h" |
51 |
|
|
#include "targ.h" |
52 |
|
|
#include "targequiv.h" |
53 |
|
|
#include "error.h" |
54 |
|
|
#include "extern.h" |
55 |
|
|
#include "gnode.h" |
56 |
|
|
#include "timestamp.h" |
57 |
|
|
#include "lst.h" |
58 |
|
|
|
59 |
|
|
static void CompatMake(void *, void *); |
60 |
|
|
|
61 |
|
|
/*- |
62 |
|
|
*----------------------------------------------------------------------- |
63 |
|
|
* CompatMake -- |
64 |
|
|
* Make a target. |
65 |
|
|
* |
66 |
|
|
* Side Effects: |
67 |
|
|
* If an error is detected and not being ignored, the process exits. |
68 |
|
|
*----------------------------------------------------------------------- |
69 |
|
|
*/ |
70 |
|
|
static void |
71 |
|
|
CompatMake(void *gnp, /* The node to make */ |
72 |
|
|
void *pgnp) /* Parent to abort if necessary */ |
73 |
|
7779 |
{ |
74 |
|
7779 |
GNode *gn = gnp; |
75 |
|
7779 |
GNode *pgn = pgnp; |
76 |
|
|
|
77 |
|
|
GNode *sib; |
78 |
|
|
bool cmdsOk; |
79 |
|
|
|
80 |
✗✓ |
7779 |
if (DEBUG(MAKE)) |
81 |
|
|
printf("CompatMake(%s, %s)\n", pgn ? pgn->name : "NULL", |
82 |
|
|
gn->name); |
83 |
|
|
|
84 |
|
|
/* XXX some loops are not loops, people write dependencies |
85 |
|
|
* between siblings to make sure they get built. |
86 |
|
|
* Also, we don't recognize direct loops. |
87 |
|
|
*/ |
88 |
✗✓ |
7779 |
if (gn == pgn) |
89 |
|
|
return; |
90 |
|
|
/* handle .USE right away */ |
91 |
✓✓ |
7779 |
if (gn->type & OP_USE) { |
92 |
|
498 |
Make_HandleUse(gn, pgn); |
93 |
|
498 |
return; |
94 |
|
|
} |
95 |
|
|
|
96 |
|
7281 |
look_harder_for_target(gn); |
97 |
|
|
|
98 |
✓✓✗✓
|
7281 |
if (pgn != NULL && is_sibling(gn, pgn)) |
99 |
|
|
return; |
100 |
|
|
|
101 |
✓✓ |
7281 |
if (pgn == NULL) |
102 |
|
764 |
pgn = gn; |
103 |
|
|
|
104 |
✗✓ |
7281 |
if (pgn->type & OP_MADE) { |
105 |
|
|
sib = gn; |
106 |
|
|
do { |
107 |
|
|
sib->mtime = gn->mtime; |
108 |
|
|
sib->built_status = UPTODATE; |
109 |
|
|
sib = sib->sibling; |
110 |
|
|
} while (sib != gn); |
111 |
|
|
} |
112 |
|
|
|
113 |
✓✗✗✓ ✓✗ |
7281 |
switch(gn->built_status) { |
114 |
|
|
case UNKNOWN: |
115 |
|
|
/* First mark ourselves to be made, then apply whatever |
116 |
|
|
* transformations the suffix module thinks are necessary. |
117 |
|
|
* Once that's done, we can descend and make all our children. |
118 |
|
|
* If any of them has an error but the -k flag was given, |
119 |
|
|
* our 'must_make' field will be set false again. This is our |
120 |
|
|
* signal to not attempt to do anything but abort our |
121 |
|
|
* parent as well. */ |
122 |
|
6405 |
gn->must_make = true; |
123 |
|
6405 |
gn->built_status = BEINGMADE; |
124 |
|
|
/* note that, in case we have siblings, we only check all |
125 |
|
|
* children for all siblings, but we don't try to apply |
126 |
|
|
* any other rule. |
127 |
|
|
*/ |
128 |
|
6405 |
sib = gn; |
129 |
|
|
do { |
130 |
|
6405 |
Suff_FindDeps(sib); |
131 |
|
6405 |
Lst_ForEach(&sib->children, CompatMake, gn); |
132 |
|
6386 |
sib = sib->sibling; |
133 |
✗✓ |
6386 |
} while (sib != gn); |
134 |
|
|
|
135 |
✗✓ |
6386 |
if (!gn->must_make) { |
136 |
|
|
Error("Build for %s aborted", gn->name); |
137 |
|
|
gn->built_status = ABORTED; |
138 |
|
|
pgn->must_make = false; |
139 |
|
|
return; |
140 |
|
|
} |
141 |
|
|
|
142 |
|
|
/* All the children were made ok. Now youngest points to |
143 |
|
|
* the newest child, we need to find out |
144 |
|
|
* if we exist and when we were modified last. The criteria |
145 |
|
|
* for datedness are defined by the Make_OODate function. */ |
146 |
✗✓ |
6386 |
if (DEBUG(MAKE)) |
147 |
|
|
printf("Examining %s...", gn->name); |
148 |
✓✓ |
6386 |
if (!Make_OODate(gn)) { |
149 |
|
3488 |
gn->built_status = UPTODATE; |
150 |
✗✓ |
3488 |
if (DEBUG(MAKE)) |
151 |
|
|
printf("up-to-date.\n"); |
152 |
|
|
return; |
153 |
✗✓ |
2898 |
} else if (DEBUG(MAKE)) |
154 |
|
|
printf("out-of-date.\n"); |
155 |
|
|
|
156 |
|
|
/* If the user is just seeing if something is out-of-date, |
157 |
|
|
* exit now to tell him/her "yes". */ |
158 |
✗✓ |
2898 |
if (queryFlag) |
159 |
|
|
exit(1); |
160 |
|
|
|
161 |
|
|
/* normally, we run the job, but if we can't find any |
162 |
|
|
* commands, we defer to siblings instead. |
163 |
|
|
*/ |
164 |
|
2898 |
sib = gn; |
165 |
|
|
do { |
166 |
|
|
/* We need to be re-made. We also have to make sure |
167 |
|
|
* we've got a $? variable. To be nice, we also define |
168 |
|
|
* the $> variable using Make_DoAllVar(). |
169 |
|
|
*/ |
170 |
|
2898 |
Make_DoAllVar(sib); |
171 |
|
2898 |
cmdsOk = node_find_valid_commands(sib); |
172 |
✗✓✗✗
|
2898 |
if (cmdsOk || (gn->type & OP_OPTIONAL)) |
173 |
|
|
break; |
174 |
|
|
|
175 |
|
|
sib = sib->sibling; |
176 |
|
|
} while (sib != gn); |
177 |
|
|
|
178 |
✓✗ |
2898 |
if (cmdsOk) { |
179 |
|
|
/* Our commands are ok, but we still have to worry |
180 |
|
|
* about the -t flag... */ |
181 |
✓✗ |
2898 |
if (!touchFlag) |
182 |
|
2898 |
run_gnode(sib); |
183 |
|
|
else { |
184 |
|
|
Job_Touch(sib); |
185 |
|
|
if (gn != sib) |
186 |
|
|
Job_Touch(gn); |
187 |
|
|
} |
188 |
|
|
} else { |
189 |
|
|
node_failure(gn); |
190 |
|
|
sib->built_status = ERROR; |
191 |
|
|
} |
192 |
|
|
|
193 |
|
|
/* copy over what we just did */ |
194 |
|
2898 |
gn->built_status = sib->built_status; |
195 |
|
|
|
196 |
✓✓ |
2898 |
if (gn->built_status != ERROR) { |
197 |
|
|
/* If the node was made successfully, mark it so, |
198 |
|
|
* update its modification time and timestamp all |
199 |
|
|
* its parents. |
200 |
|
|
* This is to keep its state from affecting that of |
201 |
|
|
* its parent. */ |
202 |
|
2856 |
gn->built_status = MADE; |
203 |
|
2856 |
sib->built_status = MADE; |
204 |
|
|
/* This is what Make does and it's actually a good |
205 |
|
|
* thing, as it allows rules like |
206 |
|
|
* |
207 |
|
|
* cmp -s y.tab.h parse.h || cp y.tab.h parse.h |
208 |
|
|
* |
209 |
|
|
* to function as intended. Unfortunately, thanks to |
210 |
|
|
* the stateless nature of NFS (and the speed of |
211 |
|
|
* this program), there are times when the |
212 |
|
|
* modification time of a file created on a remote |
213 |
|
|
* machine will not be modified before the stat() |
214 |
|
|
* implied by the Dir_MTime occurs, thus leading us |
215 |
|
|
* to believe that the file is unchanged, wreaking |
216 |
|
|
* havoc with files that depend on this one. |
217 |
|
|
*/ |
218 |
✓✗✓✓ ✓✗ |
2856 |
if (noExecute || is_out_of_date(Dir_MTime(gn))) |
219 |
|
1555 |
clock_gettime(CLOCK_REALTIME, &gn->mtime); |
220 |
✓✓✓✓
|
2856 |
if (is_strictly_before(gn->mtime, gn->youngest->mtime)) |
221 |
|
5 |
gn->mtime = gn->youngest->mtime; |
222 |
✗✓ |
2856 |
if (sib != gn) { |
223 |
|
|
if (noExecute || is_out_of_date(Dir_MTime(sib))) |
224 |
|
|
clock_gettime(CLOCK_REALTIME, |
225 |
|
|
&sib->mtime); |
226 |
|
|
if (is_strictly_before(sib->mtime, |
227 |
|
|
sib->youngest->mtime)) |
228 |
|
|
sib->mtime = sib->youngest->mtime; |
229 |
|
|
} |
230 |
✗✓ |
2856 |
if (DEBUG(MAKE)) |
231 |
|
|
printf("update time: %s\n", |
232 |
|
|
time_to_string(&gn->mtime)); |
233 |
✓✗ |
2856 |
if (!(gn->type & OP_EXEC)) { |
234 |
|
2856 |
pgn->childMade = true; |
235 |
|
2856 |
Make_TimeStamp(pgn, gn); |
236 |
|
|
} |
237 |
✗✓ |
42 |
} else if (keepgoing) |
238 |
|
|
pgn->must_make = false; |
239 |
|
|
else { |
240 |
|
42 |
print_errors(); |
241 |
|
42 |
exit(1); |
242 |
|
|
} |
243 |
|
|
break; |
244 |
|
|
case ERROR: |
245 |
|
|
/* Already had an error when making this beastie. Tell the |
246 |
|
|
* parent to abort. */ |
247 |
|
|
pgn->must_make = false; |
248 |
|
|
break; |
249 |
|
|
case BEINGMADE: |
250 |
|
|
Error("Graph cycles through %s", gn->name); |
251 |
|
|
gn->built_status = ERROR; |
252 |
|
|
pgn->must_make = false; |
253 |
|
|
break; |
254 |
|
|
case MADE: |
255 |
✓✗ |
112 |
if ((gn->type & OP_EXEC) == 0) { |
256 |
|
112 |
pgn->childMade = true; |
257 |
|
112 |
Make_TimeStamp(pgn, gn); |
258 |
|
|
} |
259 |
|
|
break; |
260 |
|
|
case UPTODATE: |
261 |
✓✗ |
764 |
if ((gn->type & OP_EXEC) == 0) |
262 |
|
764 |
Make_TimeStamp(pgn, gn); |
263 |
|
|
break; |
264 |
|
|
default: |
265 |
|
|
break; |
266 |
|
|
} |
267 |
|
|
} |
268 |
|
|
|
269 |
|
|
void |
270 |
|
|
Compat_Run(Lst targs) /* List of target nodes to re-create */ |
271 |
|
729 |
{ |
272 |
|
729 |
GNode *gn = NULL; /* Current root target */ |
273 |
|
|
int errors; /* Number of targets not remade due to errors */ |
274 |
|
|
|
275 |
|
|
/* For each entry in the list of targets to create, call CompatMake on |
276 |
|
|
* it to create the thing. CompatMake will leave the 'built_status' |
277 |
|
|
* field of gn in one of several states: |
278 |
|
|
* UPTODATE gn was already up-to-date |
279 |
|
|
* MADE gn was recreated successfully |
280 |
|
|
* ERROR An error occurred while gn was being |
281 |
|
|
* created |
282 |
|
|
* ABORTED gn was not remade because one of its |
283 |
|
|
* inferiors could not be made due to errors. |
284 |
|
|
*/ |
285 |
|
729 |
errors = 0; |
286 |
✓✓ |
2180 |
while ((gn = (GNode *)Lst_DeQueue(targs)) != NULL) { |
287 |
|
764 |
CompatMake(gn, NULL); |
288 |
|
|
|
289 |
✓✓ |
722 |
if (gn->built_status == UPTODATE) |
290 |
|
3 |
printf("`%s' is up to date.\n", gn->name); |
291 |
✗✓ |
719 |
else if (gn->built_status == ABORTED) { |
292 |
|
|
printf("`%s' not remade because of errors.\n", |
293 |
|
|
gn->name); |
294 |
|
|
errors++; |
295 |
|
|
} |
296 |
|
|
} |
297 |
|
|
|
298 |
|
|
/* If the user has defined a .END target, run its commands. */ |
299 |
✓✗ |
687 |
if (errors == 0) |
300 |
|
687 |
run_gnode(end_node); |
301 |
|
687 |
} |