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 { 74 GNode *gn = gnp; 75 GNode *pgn = pgnp; 76 77 GNode *sib; 78 bool cmdsOk; 79 80 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 if (gn == pgn) 89 return; 90 /* handle .USE right away */ 91 if (gn->type & OP_USE) { 92 Make_HandleUse(gn, pgn); 93 return; 94 } 95 96 look_harder_for_target(gn); 97 98 if (pgn != NULL && is_sibling(gn, pgn)) 99 return; 100 101 if (pgn == NULL) 102 pgn = gn; 103 104 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 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 gn->must_make = true; 123 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 sib = gn; 129 do { 130 Suff_FindDeps(sib); 131 Lst_ForEach(&sib->children, CompatMake, gn); 132 sib = sib->sibling; 133 } while (sib != gn); 134 135 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 if (DEBUG(MAKE)) 147 printf("Examining %s...", gn->name); 148 if (!Make_OODate(gn)) { 149 gn->built_status = UPTODATE; 150 if (DEBUG(MAKE)) 151 printf("up-to-date.\n"); 152 return; 153 } 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 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 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 Make_DoAllVar(sib); 171 cmdsOk = node_find_valid_commands(sib); 172 if (cmdsOk || (gn->type & OP_OPTIONAL)) 173 break; 174 175 sib = sib->sibling; 176 } while (sib != gn); 177 178 if (cmdsOk) { 179 /* Our commands are ok, but we still have to worry 180 * about the -t flag... */ 181 if (!touchFlag) 182 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 gn->built_status = sib->built_status; 195 196 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 gn->built_status = MADE; 203 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 if (noExecute || is_out_of_date(Dir_MTime(gn))) 219 clock_gettime(CLOCK_REALTIME, &gn->mtime); 220 if (is_strictly_before(gn->mtime, gn->youngest->mtime)) 221 gn->mtime = gn->youngest->mtime; 222 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 if (DEBUG(MAKE)) 231 printf("update time: %s\n", 232 time_to_string(&gn->mtime)); 233 if (!(gn->type & OP_EXEC)) { 234 pgn->childMade = true; 235 Make_TimeStamp(pgn, gn); 236 } 237 } else if (keepgoing) 238 pgn->must_make = false; 239 else { 240 print_errors(); 241 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 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 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 /* 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 errors = 0; 286 while ((gn = (GNode *)Lst_DeQueue(targs)) != NULL) { 287 CompatMake(gn, NULL); 288 289 if (gn->built_status == UPTODATE) 290 printf("`%s' is up to date.\n", gn->name); 291 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 if (errors == 0) 300 run_gnode(end_node); 301 } 302