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