1 /* $OpenBSD: compat.c,v 1.95 2024/06/18 02:11:03 millert 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 "defines.h"
44 #include "dir.h"
45 #include "engine.h"
46 #include "job.h"
47 #include "compat.h"
48 #include "suff.h"
49 #include "var.h"
50 #include "targ.h"
51 #include "targequiv.h"
52 #include "error.h"
53 #include "extern.h"
54 #include "gnode.h"
55 #include "timestamp.h"
56 #include "lst.h"
57
58 static void CompatMake(void *, void *);
59
60 /*-
61 *-----------------------------------------------------------------------
62 * CompatMake --
63 * Make a target.
64 *
65 * Side Effects:
66 * If an error is detected and not being ignored, the process exits.
67 *-----------------------------------------------------------------------
68 */
69 static void
CompatMake(void * gnp,void * pgnp)70 CompatMake(void *gnp, /* The node to make */
71 void *pgnp) /* Parent to abort if necessary */
72 {
73 GNode *gn = gnp;
74 GNode *pgn = pgnp;
75
76 GNode *sib;
77 bool cmdsOk;
78
79 if (DEBUG(MAKE))
80 printf("CompatMake(%s, %s)\n", pgn ? pgn->name : "NULL",
81 gn->name);
82
83 /* XXX some loops are not loops, people write dependencies
84 * between siblings to make sure they get built.
85 * Also, we don't recognize direct loops.
86 */
87 if (gn == pgn)
88 return;
89 /* handle .USE right away */
90 if (gn->type & OP_USE) {
91 Make_HandleUse(gn, pgn);
92 return;
93 }
94
95 look_harder_for_target(gn);
96
97 if (pgn != NULL && is_sibling(gn, pgn))
98 return;
99
100 if (pgn == NULL)
101 pgn = gn;
102
103 switch(gn->built_status) {
104 case UNKNOWN:
105 /* First mark ourselves to be built, then apply whatever
106 * transformations the suffix module thinks are necessary.
107 * Once that's done, we can descend and make all our children.
108 * If any of them has an error but the -k flag was given,
109 * we will abort. */
110 gn->must_make = true;
111 gn->built_status = BUILDING;
112 /* note that, in case we have siblings, we only check all
113 * children for all siblings, but we don't try to apply
114 * any other rule.
115 */
116 sib = gn;
117 do {
118 Suff_FindDeps(sib);
119 Lst_ForEach(&sib->children, CompatMake, gn);
120 sib = sib->sibling;
121 } while (sib != gn);
122
123 if (gn->built_status == ABORTED) {
124 Error("Build for %s aborted", gn->name);
125 pgn->built_status = ABORTED;
126 return;
127 }
128
129 /* All the children built ok. Now youngest points to
130 * the newest child, we need to find out
131 * if we exist and when we were modified last. The criteria
132 * for datedness are defined by the Make_OODate function. */
133 if (DEBUG(MAKE))
134 printf("Examining %s...", gn->name);
135 if (!Make_OODate(gn)) {
136 gn->built_status = UPTODATE;
137 if (DEBUG(MAKE))
138 printf("up-to-date.\n");
139 return;
140 } else if (DEBUG(MAKE))
141 printf("out-of-date.\n");
142
143 /* If the user is just seeing if something is out-of-date,
144 * exit now to tell him/her "yes". */
145 if (queryFlag)
146 exit(1);
147
148 /* normally, we run the job, but if we can't find any
149 * commands, we defer to siblings instead.
150 */
151 sib = gn;
152 do {
153 /* We need to be rebuilt. We also have to make sure
154 * we've got a $? variable. To be nice, we also define
155 * the $> variable using Make_DoAllVar().
156 */
157 Make_DoAllVar(sib);
158 cmdsOk = node_find_valid_commands(sib);
159 if (cmdsOk || (gn->type & OP_OPTIONAL))
160 break;
161
162 sib = sib->sibling;
163 } while (sib != gn);
164
165 if (cmdsOk) {
166 /* Our commands are ok, but we still have to worry
167 * about the -t flag... */
168 if (!touchFlag)
169 run_gnode(sib);
170 else {
171 Job_Touch(sib);
172 if (gn != sib)
173 Job_Touch(gn);
174 }
175 } else {
176 node_failure(gn);
177 sib->built_status = ERROR;
178 }
179
180 /* copy over what we just did */
181 gn->built_status = sib->built_status;
182
183 if (gn->built_status == REBUILT) {
184 /* If the node was built successfully,
185 * update its modification time and timestamp all
186 * its parents.
187 * This is to keep its state from affecting that of
188 * its parent. */
189 /* This is what Make does and it's actually a good
190 * thing, as it allows rules like
191 *
192 * cmp -s y.tab.h parse.h || cp y.tab.h parse.h
193 *
194 * to function as intended. Unfortunately, thanks to
195 * the stateless nature of NFS (and the speed of
196 * this program), there are times when the
197 * modification time of a file created on a remote
198 * machine will not be modified before the stat()
199 * implied by the Dir_MTime occurs, thus leading us
200 * to believe that the file is unchanged, wreaking
201 * havoc with files that depend on this one.
202 */
203 if (noExecute || is_out_of_date(Dir_MTime(gn)))
204 clock_gettime(CLOCK_REALTIME, &gn->mtime);
205 if (is_strictly_before(gn->mtime, gn->youngest->mtime))
206 gn->mtime = gn->youngest->mtime;
207 if (sib != gn) {
208 if (noExecute || is_out_of_date(Dir_MTime(sib)))
209 clock_gettime(CLOCK_REALTIME,
210 &sib->mtime);
211 if (is_strictly_before(sib->mtime,
212 sib->youngest->mtime))
213 sib->mtime = sib->youngest->mtime;
214 }
215 if (DEBUG(MAKE))
216 printf("update time: %s\n",
217 time_to_string(&gn->mtime));
218 pgn->child_rebuilt = true;
219 Make_TimeStamp(pgn, gn);
220 } else if (keepgoing)
221 pgn->built_status = ABORTED;
222 else {
223 print_errors();
224 exit(1);
225 }
226 break;
227 case ERROR:
228 /* Already had an error when making this beastie. Tell the
229 * parent to abort. */
230 pgn->built_status = ABORTED;
231 break;
232 case BUILDING:
233 Error("Graph cycles through %s", gn->name);
234 gn->built_status = ERROR;
235 pgn->built_status = ABORTED;
236 break;
237 case REBUILT:
238 pgn->child_rebuilt = true;
239 Make_TimeStamp(pgn, gn);
240 break;
241 case UPTODATE:
242 Make_TimeStamp(pgn, gn);
243 break;
244 default:
245 break;
246 }
247 }
248
249 void
Compat_Init(void)250 Compat_Init(void)
251 {
252 }
253
254 void
Compat_Update(GNode * gn UNUSED)255 Compat_Update(GNode *gn UNUSED)
256 {
257 }
258
259 void
Compat_Run(Lst targs,bool * has_errors,bool * out_of_date)260 Compat_Run(Lst targs, bool *has_errors, bool *out_of_date)
261 {
262 GNode *gn = NULL; /* Current root target */
263
264 /* For each entry in the list of targets to create, call CompatMake on
265 * it to create the thing. CompatMake will leave the 'built_status'
266 * field of gn in one of several states:
267 * UPTODATE gn was already up-to-date
268 * REBUILT gn was recreated successfully
269 * ERROR An error occurred while gn was being
270 * created
271 * ABORTED gn was not built because one of its
272 * dependencies could not be built due
273 * to errors. */
274 while ((gn = Lst_DeQueue(targs)) != NULL) {
275 CompatMake(gn, NULL);
276
277 if (gn->built_status == UPTODATE)
278 printf("`%s' is up to date.\n", gn->name);
279 else if (gn->built_status == ABORTED) {
280 printf("`%s' not remade because of errors.\n",
281 gn->name);
282 *out_of_date = true;
283 *has_errors = true;
284 } else {
285 *out_of_date = true;
286 }
287 }
288
289 }
290