1 /* $OpenBSD: compat.c,v 1.94 2023/09/04 11:35:11 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 "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 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 250 Compat_Init() 251 { 252 } 253 254 void 255 Compat_Update(GNode *gn) 256 { 257 } 258 259 void 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