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