| 1 | /* |
| 2 | * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. |
| 3 | * Copyright (c) 1988, 1989 by Adam de Boor |
| 4 | * Copyright (c) 1989 by Berkeley Softworks |
| 5 | * All rights reserved. |
| 6 | * |
| 7 | * This code is derived from software contributed to Berkeley by |
| 8 | * Adam de Boor. |
| 9 | * |
| 10 | * Redistribution and use in source and binary forms, with or without |
| 11 | * modification, are permitted provided that the following conditions |
| 12 | * are met: |
| 13 | * 1. Redistributions of source code must retain the above copyright |
| 14 | * notice, this list of conditions and the following disclaimer. |
| 15 | * 2. Redistributions in binary form must reproduce the above copyright |
| 16 | * notice, this list of conditions and the following disclaimer in the |
| 17 | * documentation and/or other materials provided with the distribution. |
| 18 | * 3. All advertising materials mentioning features or use of this software |
| 19 | * must display the following acknowledgement: |
| 20 | * This product includes software developed by the University of |
| 21 | * California, Berkeley and its contributors. |
| 22 | * 4. 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 | #ifndef lint |
| 40 | char copyright[] = |
| 41 | "@(#) Copyright (c) 1989 The Regents of the University of California.\n\ |
| 42 | All rights reserved.\n"; |
| 43 | #endif /* not lint */ |
| 44 | |
| 45 | #ifndef lint |
| 46 | static char sccsid[] = "@(#)main.c 5.25 (Berkeley) 4/1/91"; |
| 47 | #endif /* not lint */ |
| 48 | |
| 49 | /*- |
| 50 | * main.c -- |
| 51 | * The main file for this entire program. Exit routines etc |
| 52 | * reside here. |
| 53 | * |
| 54 | * Utility functions defined in this file: |
| 55 | * Main_ParseArgLine Takes a line of arguments, breaks them and |
| 56 | * treats them as if they were given when first |
| 57 | * invoked. Used by the parse module to implement |
| 58 | * the .MFLAGS target. |
| 59 | * |
| 60 | * Error Print a tagged error message. The global |
| 61 | * MAKE variable must have been defined. This |
| 62 | * takes a format string and two optional |
| 63 | * arguments for it. |
| 64 | * |
| 65 | * Fatal Print an error message and exit. Also takes |
| 66 | * a format string and two arguments. |
| 67 | * |
| 68 | * Punt Aborts all jobs and exits with a message. Also |
| 69 | * takes a format string and two arguments. |
| 70 | * |
| 71 | * Finish Finish things up by printing the number of |
| 72 | * errors which occured, as passed to it, and |
| 73 | * exiting. |
| 74 | */ |
| 75 | |
| 76 | #include <sys/param.h> |
| 77 | #include <sys/signal.h> |
| 78 | #include <sys/stat.h> |
| 79 | #include <errno.h> |
| 80 | #include <fcntl.h> |
| 81 | #include <stdio.h> |
| 82 | #include <varargs.h> |
| 83 | #include "make.h" |
| 84 | #include "pathnames.h" |
| 85 | |
| 86 | #ifndef DEFMAXLOCAL |
| 87 | #define DEFMAXLOCAL DEFMAXJOBS |
| 88 | #endif DEFMAXLOCAL |
| 89 | |
| 90 | #define MAKEFLAGS ".MAKEFLAGS" |
| 91 | |
| 92 | Lst create; /* Targets to be made */ |
| 93 | time_t now; /* Time at start of make */ |
| 94 | GNode *DEFAULT; /* .DEFAULT node */ |
| 95 | Boolean allPrecious; /* .PRECIOUS given on line by itself */ |
| 96 | |
| 97 | static Boolean noBuiltins; /* -r flag */ |
| 98 | static Lst makefiles; /* ordered list of makefiles to read */ |
| 99 | int maxJobs; /* -J argument */ |
| 100 | static int maxLocal; /* -L argument */ |
| 101 | Boolean debug; /* -d flag */ |
| 102 | Boolean noExecute; /* -n flag */ |
| 103 | Boolean keepgoing; /* -k flag */ |
| 104 | Boolean queryFlag; /* -q flag */ |
| 105 | Boolean touchFlag; /* -t flag */ |
| 106 | Boolean usePipes; /* !-P flag */ |
| 107 | Boolean ignoreErrors; /* -i flag */ |
| 108 | Boolean beSilent; /* -s flag */ |
| 109 | Boolean oldVars; /* variable substitution style */ |
| 110 | Boolean checkEnvFirst; /* -e flag */ |
| 111 | static Boolean jobsRunning; /* TRUE if the jobs might be running */ |
| 112 | |
| 113 | static Boolean ReadMakefile(); |
| 114 | |
| 115 | static char *curdir; /* if chdir'd for an architecture */ |
| 116 | |
| 117 | /*- |
| 118 | * MainParseArgs -- |
| 119 | * Parse a given argument vector. Called from main() and from |
| 120 | * Main_ParseArgLine() when the .MAKEFLAGS target is used. |
| 121 | * |
| 122 | * XXX: Deal with command line overriding .MAKEFLAGS in makefile |
| 123 | * |
| 124 | * Results: |
| 125 | * None |
| 126 | * |
| 127 | * Side Effects: |
| 128 | * Various global and local flags will be set depending on the flags |
| 129 | * given |
| 130 | */ |
| 131 | static void |
| 132 | MainParseArgs(argc, argv) |
| 133 | int argc; |
| 134 | char **argv; |
| 135 | { |
| 136 | extern int optind; |
| 137 | extern char *optarg; |
| 138 | register int i; |
| 139 | register char *cp; |
| 140 | char c; |
| 141 | |
| 142 | optind = 1; /* since we're called more than once */ |
| 143 | rearg: while((c = getopt(argc, argv, "D:I:d:ef:ij:knqrst")) != EOF) { |
| 144 | switch(c) { |
| 145 | case 'D': |
| 146 | Var_Set(optarg, "1", VAR_GLOBAL); |
| 147 | Var_Append(MAKEFLAGS, "-D", VAR_GLOBAL); |
| 148 | Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); |
| 149 | break; |
| 150 | case 'I': |
| 151 | Parse_AddIncludeDir(optarg); |
| 152 | Var_Append(MAKEFLAGS, "-I", VAR_GLOBAL); |
| 153 | Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); |
| 154 | break; |
| 155 | #ifdef notdef |
| 156 | case 'L': |
| 157 | maxLocal = atoi(optarg); |
| 158 | Var_Append(MAKEFLAGS, "-L", VAR_GLOBAL); |
| 159 | Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); |
| 160 | break; |
| 161 | case 'P': |
| 162 | usePipes = FALSE; |
| 163 | Var_Append(MAKEFLAGS, "-P", VAR_GLOBAL); |
| 164 | break; |
| 165 | case 'S': |
| 166 | keepgoing = FALSE; |
| 167 | Var_Append(MAKEFLAGS, "-S", VAR_GLOBAL); |
| 168 | break; |
| 169 | #endif |
| 170 | case 'd': { |
| 171 | char *modules = optarg; |
| 172 | |
| 173 | for (; *modules; ++modules) |
| 174 | switch (*modules) { |
| 175 | case 'A': |
| 176 | debug = ~0; |
| 177 | break; |
| 178 | case 'a': |
| 179 | debug |= DEBUG_ARCH; |
| 180 | break; |
| 181 | case 'c': |
| 182 | debug |= DEBUG_COND; |
| 183 | break; |
| 184 | case 'd': |
| 185 | debug |= DEBUG_DIR; |
| 186 | break; |
| 187 | case 'g': |
| 188 | if (modules[1] == '1') { |
| 189 | debug |= DEBUG_GRAPH1; |
| 190 | ++modules; |
| 191 | } |
| 192 | else if (modules[1] == '2') { |
| 193 | debug |= DEBUG_GRAPH2; |
| 194 | ++modules; |
| 195 | } |
| 196 | break; |
| 197 | case 'j': |
| 198 | debug |= DEBUG_JOB; |
| 199 | break; |
| 200 | case 'm': |
| 201 | debug |= DEBUG_MAKE; |
| 202 | break; |
| 203 | case 's': |
| 204 | debug |= DEBUG_SUFF; |
| 205 | break; |
| 206 | case 't': |
| 207 | debug |= DEBUG_TARG; |
| 208 | break; |
| 209 | case 'v': |
| 210 | debug |= DEBUG_VAR; |
| 211 | break; |
| 212 | default: |
| 213 | (void)fprintf(stderr, |
| 214 | "make: illegal argument to d option -- %c\n", |
| 215 | *modules); |
| 216 | usage(); |
| 217 | } |
| 218 | Var_Append(MAKEFLAGS, "-d", VAR_GLOBAL); |
| 219 | Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); |
| 220 | break; |
| 221 | } |
| 222 | case 'e': |
| 223 | checkEnvFirst = TRUE; |
| 224 | Var_Append(MAKEFLAGS, "-e", VAR_GLOBAL); |
| 225 | break; |
| 226 | case 'f': |
| 227 | (void)Lst_AtEnd(makefiles, (ClientData)optarg); |
| 228 | break; |
| 229 | case 'i': |
| 230 | ignoreErrors = TRUE; |
| 231 | Var_Append(MAKEFLAGS, "-i", VAR_GLOBAL); |
| 232 | break; |
| 233 | case 'j': |
| 234 | maxJobs = atoi(optarg); |
| 235 | Var_Append(MAKEFLAGS, "-J", VAR_GLOBAL); |
| 236 | Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); |
| 237 | break; |
| 238 | case 'k': |
| 239 | keepgoing = TRUE; |
| 240 | Var_Append(MAKEFLAGS, "-k", VAR_GLOBAL); |
| 241 | break; |
| 242 | case 'n': |
| 243 | noExecute = TRUE; |
| 244 | Var_Append(MAKEFLAGS, "-n", VAR_GLOBAL); |
| 245 | break; |
| 246 | case 'q': |
| 247 | queryFlag = TRUE; |
| 248 | /* Kind of nonsensical, wot? */ |
| 249 | Var_Append(MAKEFLAGS, "-q", VAR_GLOBAL); |
| 250 | break; |
| 251 | case 'r': |
| 252 | noBuiltins = TRUE; |
| 253 | Var_Append(MAKEFLAGS, "-r", VAR_GLOBAL); |
| 254 | break; |
| 255 | case 's': |
| 256 | beSilent = TRUE; |
| 257 | Var_Append(MAKEFLAGS, "-s", VAR_GLOBAL); |
| 258 | break; |
| 259 | case 't': |
| 260 | touchFlag = TRUE; |
| 261 | Var_Append(MAKEFLAGS, "-t", VAR_GLOBAL); |
| 262 | break; |
| 263 | default: |
| 264 | case '?': |
| 265 | usage(); |
| 266 | } |
| 267 | } |
| 268 | |
| 269 | oldVars = TRUE; |
| 270 | |
| 271 | /* |
| 272 | * See if the rest of the arguments are variable assignments and |
| 273 | * perform them if so. Else take them to be targets and stuff them |
| 274 | * on the end of the "create" list. |
| 275 | */ |
| 276 | for (argv += optind, argc -= optind; *argv; ++argv, --argc) |
| 277 | if (Parse_IsVar(*argv)) |
| 278 | Parse_DoVar(*argv, VAR_CMD); |
| 279 | else { |
| 280 | if (!**argv) |
| 281 | Punt("illegal (null) argument."); |
| 282 | if (**argv == '-') { |
| 283 | optind = 0; |
| 284 | goto rearg; |
| 285 | } |
| 286 | (void)Lst_AtEnd(create, (ClientData)*argv); |
| 287 | } |
| 288 | } |
| 289 | |
| 290 | /*- |
| 291 | * Main_ParseArgLine -- |
| 292 | * Used by the parse module when a .MFLAGS or .MAKEFLAGS target |
| 293 | * is encountered and by main() when reading the .MAKEFLAGS envariable. |
| 294 | * Takes a line of arguments and breaks it into its |
| 295 | * component words and passes those words and the number of them to the |
| 296 | * MainParseArgs function. |
| 297 | * The line should have all its leading whitespace removed. |
| 298 | * |
| 299 | * Results: |
| 300 | * None |
| 301 | * |
| 302 | * Side Effects: |
| 303 | * Only those that come from the various arguments. |
| 304 | */ |
| 305 | void |
| 306 | Main_ParseArgLine(line) |
| 307 | char *line; /* Line to fracture */ |
| 308 | { |
| 309 | char **argv; /* Manufactured argument vector */ |
| 310 | int argc; /* Number of arguments in argv */ |
| 311 | |
| 312 | if (line == NULL) |
| 313 | return; |
| 314 | for (; *line == ' '; ++line); |
| 315 | if (!*line) |
| 316 | return; |
| 317 | |
| 318 | argv = brk_string(line, &argc); |
| 319 | MainParseArgs(argc, argv); |
| 320 | } |
| 321 | |
| 322 | /*- |
| 323 | * main -- |
| 324 | * The main function, for obvious reasons. Initializes variables |
| 325 | * and a few modules, then parses the arguments give it in the |
| 326 | * environment and on the command line. Reads the system makefile |
| 327 | * followed by either Makefile, makefile or the file given by the |
| 328 | * -f argument. Sets the .MAKEFLAGS PMake variable based on all the |
| 329 | * flags it has received by then uses either the Make or the Compat |
| 330 | * module to create the initial list of targets. |
| 331 | * |
| 332 | * Results: |
| 333 | * If -q was given, exits -1 if anything was out-of-date. Else it exits |
| 334 | * 0. |
| 335 | * |
| 336 | * Side Effects: |
| 337 | * The program exits when done. Targets are created. etc. etc. etc. |
| 338 | */ |
| 339 | main(argc, argv) |
| 340 | int argc; |
| 341 | char **argv; |
| 342 | { |
| 343 | Lst targs; /* target nodes to create -- passed to Make_Init */ |
| 344 | Boolean outOfDate; /* FALSE if all targets up to date */ |
| 345 | struct stat sb; |
| 346 | char *p, *path, *getenv(); |
| 347 | |
| 348 | /* |
| 349 | * if the MAKEOBJDIR (or by default, the _PATH_OBJDIR) directory |
| 350 | * exists, change into it and build there. Once things are |
| 351 | * initted, have to add the original directory to the search path, |
| 352 | * and modify the paths for the Makefiles apropriately. The |
| 353 | * current directory is also placed as a variable for make scripts. |
| 354 | */ |
| 355 | if (!(path = getenv("MAKEOBJDIR"))) |
| 356 | path = _PATH_OBJDIR; |
| 357 | if (!lstat(path, &sb)) { |
| 358 | if (S_ISDIR(sb.st_mode)) |
| 359 | curdir = ".."; |
| 360 | else { |
| 361 | curdir = emalloc((u_int)MAXPATHLEN + 1); |
| 362 | if (!getwd(curdir)) { |
| 363 | (void)fprintf(stderr, "make: %s.\n", curdir); |
| 364 | exit(2); |
| 365 | } |
| 366 | } |
| 367 | if (chdir(path)) { |
| 368 | (void)fprintf(stderr, "make: %s: %s.\n", |
| 369 | path, strerror(errno)); |
| 370 | exit(2); |
| 371 | } |
| 372 | } |
| 373 | |
| 374 | create = Lst_Init(FALSE); |
| 375 | makefiles = Lst_Init(FALSE); |
| 376 | beSilent = FALSE; /* Print commands as executed */ |
| 377 | ignoreErrors = FALSE; /* Pay attention to non-zero returns */ |
| 378 | noExecute = FALSE; /* Execute all commands */ |
| 379 | keepgoing = FALSE; /* Stop on error */ |
| 380 | allPrecious = FALSE; /* Remove targets when interrupted */ |
| 381 | queryFlag = FALSE; /* This is not just a check-run */ |
| 382 | noBuiltins = FALSE; /* Read the built-in rules */ |
| 383 | touchFlag = FALSE; /* Actually update targets */ |
| 384 | usePipes = TRUE; /* Catch child output in pipes */ |
| 385 | debug = 0; /* No debug verbosity, please. */ |
| 386 | jobsRunning = FALSE; |
| 387 | |
| 388 | maxJobs = DEFMAXJOBS; /* Set default max concurrency */ |
| 389 | maxLocal = DEFMAXLOCAL; /* Set default local max concurrency */ |
| 390 | |
| 391 | /* |
| 392 | * Initialize the parsing, directory and variable modules to prepare |
| 393 | * for the reading of inclusion paths and variable settings on the |
| 394 | * command line |
| 395 | */ |
| 396 | Dir_Init(); /* Initialize directory structures so -I flags |
| 397 | * can be processed correctly */ |
| 398 | Parse_Init(); /* Need to initialize the paths of #include |
| 399 | * directories */ |
| 400 | Var_Init(); /* As well as the lists of variables for |
| 401 | * parsing arguments */ |
| 402 | |
| 403 | if (curdir) { |
| 404 | Dir_AddDir(dirSearchPath, curdir); |
| 405 | Var_Set(".CURDIR", curdir, VAR_GLOBAL); |
| 406 | } else |
| 407 | Var_Set(".CURDIR", ".", VAR_GLOBAL); |
| 408 | |
| 409 | /* |
| 410 | * Initialize various variables. |
| 411 | * MAKE also gets this name, for compatibility |
| 412 | * .MAKEFLAGS gets set to the empty string just in case. |
| 413 | * MFLAGS also gets initialized empty, for compatibility. |
| 414 | */ |
| 415 | Var_Set("MAKE", argv[0], VAR_GLOBAL); |
| 416 | Var_Set(MAKEFLAGS, "", VAR_GLOBAL); |
| 417 | Var_Set("MFLAGS", "", VAR_GLOBAL); |
| 418 | Var_Set("MACHINE", MACHINE, VAR_GLOBAL); |
| 419 | |
| 420 | /* |
| 421 | * First snag any flags out of the MAKE environment variable. |
| 422 | * (Note this is *not* MAKEFLAGS since /bin/make uses that and it's |
| 423 | * in a different format). |
| 424 | */ |
| 425 | #ifdef POSIX |
| 426 | Main_ParseArgLine(getenv("MAKEFLAGS")); |
| 427 | #else |
| 428 | Main_ParseArgLine(getenv("MAKE")); |
| 429 | #endif |
| 430 | |
| 431 | MainParseArgs(argc, argv); |
| 432 | |
| 433 | /* |
| 434 | * Initialize archive, target and suffix modules in preparation for |
| 435 | * parsing the makefile(s) |
| 436 | */ |
| 437 | Arch_Init(); |
| 438 | Targ_Init(); |
| 439 | Suff_Init(); |
| 440 | |
| 441 | DEFAULT = NILGNODE; |
| 442 | (void)time(&now); |
| 443 | |
| 444 | /* |
| 445 | * Set up the .TARGETS variable to contain the list of targets to be |
| 446 | * created. If none specified, make the variable empty -- the parser |
| 447 | * will fill the thing in with the default or .MAIN target. |
| 448 | */ |
| 449 | if (!Lst_IsEmpty(create)) { |
| 450 | LstNode ln; |
| 451 | |
| 452 | for (ln = Lst_First(create); ln != NILLNODE; |
| 453 | ln = Lst_Succ(ln)) { |
| 454 | char *name = (char *)Lst_Datum(ln); |
| 455 | |
| 456 | Var_Append(".TARGETS", name, VAR_GLOBAL); |
| 457 | } |
| 458 | } else |
| 459 | Var_Set(".TARGETS", "", VAR_GLOBAL); |
| 460 | |
| 461 | /* |
| 462 | * Read in the built-in rules first, followed by the specified makefile, |
| 463 | * if it was (makefile != (char *) NULL), or the default Makefile and |
| 464 | * makefile, in that order, if it wasn't. |
| 465 | */ |
| 466 | if (!noBuiltins && !ReadMakefile(_PATH_DEFSYSMK)) |
| 467 | Fatal("make: no system rules (%s).", _PATH_DEFSYSMK); |
| 468 | |
| 469 | if (!Lst_IsEmpty(makefiles)) { |
| 470 | LstNode ln; |
| 471 | |
| 472 | ln = Lst_Find(makefiles, (ClientData)NULL, ReadMakefile); |
| 473 | if (ln != NILLNODE) |
| 474 | Fatal("make: cannot open %s.", (char *)Lst_Datum(ln)); |
| 475 | } else if (!ReadMakefile("makefile")) |
| 476 | (void)ReadMakefile("Makefile"); |
| 477 | |
| 478 | (void)ReadMakefile(".depend"); |
| 479 | |
| 480 | Var_Append("MFLAGS", Var_Value(MAKEFLAGS, VAR_GLOBAL), VAR_GLOBAL); |
| 481 | |
| 482 | /* Install all the flags into the MAKE envariable. */ |
| 483 | if ((p = Var_Value(MAKEFLAGS, VAR_GLOBAL)) && *p) |
| 484 | #ifdef POSIX |
| 485 | setenv("MAKEFLAGS", p, 1); |
| 486 | #else |
| 487 | setenv("MAKE", p, 1); |
| 488 | #endif |
| 489 | |
| 490 | /* |
| 491 | * For compatibility, look at the directories in the VPATH variable |
| 492 | * and add them to the search path, if the variable is defined. The |
| 493 | * variable's value is in the same format as the PATH envariable, i.e. |
| 494 | * <directory>:<directory>:<directory>... |
| 495 | */ |
| 496 | if (Var_Exists("VPATH", VAR_CMD)) { |
| 497 | char *vpath, *path, *cp, savec; |
| 498 | /* |
| 499 | * GCC stores string constants in read-only memory, but |
| 500 | * Var_Subst will want to write this thing, so store it |
| 501 | * in an array |
| 502 | */ |
| 503 | static char VPATH[] = "${VPATH}"; |
| 504 | |
| 505 | vpath = Var_Subst(VPATH, VAR_CMD, FALSE); |
| 506 | path = vpath; |
| 507 | do { |
| 508 | /* skip to end of directory */ |
| 509 | for (cp = path; *cp != ':' && *cp != '\0'; cp++); |
| 510 | /* Save terminator character so know when to stop */ |
| 511 | savec = *cp; |
| 512 | *cp = '\0'; |
| 513 | /* Add directory to search path */ |
| 514 | Dir_AddDir(dirSearchPath, path); |
| 515 | *cp = savec; |
| 516 | path = cp + 1; |
| 517 | } while (savec == ':'); |
| 518 | (void)free((Address)vpath); |
| 519 | } |
| 520 | |
| 521 | /* |
| 522 | * Now that all search paths have been read for suffixes et al, it's |
| 523 | * time to add the default search path to their lists... |
| 524 | */ |
| 525 | Suff_DoPaths(); |
| 526 | |
| 527 | /* print the initial graph, if the user requested it */ |
| 528 | if (DEBUG(GRAPH1)) |
| 529 | Targ_PrintGraph(1); |
| 530 | |
| 531 | /* |
| 532 | * Have now read the entire graph and need to make a list of targets |
| 533 | * to create. If none was given on the command line, we consult the |
| 534 | * parsing module to find the main target(s) to create. |
| 535 | */ |
| 536 | if (Lst_IsEmpty(create)) |
| 537 | targs = Parse_MainName(); |
| 538 | else |
| 539 | targs = Targ_FindList(create, TARG_CREATE); |
| 540 | |
| 541 | /* |
| 542 | * this was original amMake -- want to allow parallelism, so put this |
| 543 | * back in, eventually. |
| 544 | */ |
| 545 | if (0) { |
| 546 | /* |
| 547 | * Initialize job module before traversing the graph, now that |
| 548 | * any .BEGIN and .END targets have been read. This is done |
| 549 | * only if the -q flag wasn't given (to prevent the .BEGIN from |
| 550 | * being executed should it exist). |
| 551 | */ |
| 552 | if (!queryFlag) { |
| 553 | if (maxLocal == -1) |
| 554 | maxLocal = maxJobs; |
| 555 | Job_Init(maxJobs, maxLocal); |
| 556 | jobsRunning = TRUE; |
| 557 | } |
| 558 | |
| 559 | /* Traverse the graph, checking on all the targets */ |
| 560 | outOfDate = Make_Run(targs); |
| 561 | } else |
| 562 | /* |
| 563 | * Compat_Init will take care of creating all the targets as |
| 564 | * well as initializing the module. |
| 565 | */ |
| 566 | Compat_Run(targs); |
| 567 | |
| 568 | /* print the graph now it's been processed if the user requested it */ |
| 569 | if (DEBUG(GRAPH2)) |
| 570 | Targ_PrintGraph(2); |
| 571 | |
| 572 | if (queryFlag && outOfDate) |
| 573 | exit(1); |
| 574 | else |
| 575 | exit(0); |
| 576 | } |
| 577 | |
| 578 | /*- |
| 579 | * ReadMakefile -- |
| 580 | * Open and parse the given makefile. |
| 581 | * |
| 582 | * Results: |
| 583 | * TRUE if ok. FALSE if couldn't open file. |
| 584 | * |
| 585 | * Side Effects: |
| 586 | * lots |
| 587 | */ |
| 588 | static Boolean |
| 589 | ReadMakefile(fname) |
| 590 | char *fname; /* makefile to read */ |
| 591 | { |
| 592 | extern Lst parseIncPath, sysIncPath; |
| 593 | FILE *stream; |
| 594 | char *name, path[MAXPATHLEN + 1]; |
| 595 | |
| 596 | if (!strcmp(fname, "-")) { |
| 597 | Parse_File("(stdin)", stdin); |
| 598 | Var_Set("MAKEFILE", "", VAR_GLOBAL); |
| 599 | } else { |
| 600 | if (stream = fopen(fname, "r")) |
| 601 | goto found; |
| 602 | /* if we've chdir'd, rebuild the path name */ |
| 603 | if (curdir && *fname != '/') { |
| 604 | (void)sprintf(path, "%s/%s", curdir, fname); |
| 605 | if (stream = fopen(path, "r")) { |
| 606 | fname = path; |
| 607 | goto found; |
| 608 | } |
| 609 | } |
| 610 | /* look in -I and system include directories. */ |
| 611 | name = Dir_FindFile(fname, parseIncPath); |
| 612 | if (!name) |
| 613 | name = Dir_FindFile(fname, sysIncPath); |
| 614 | if (!name || !(stream = fopen(name, "r"))) |
| 615 | return(FALSE); |
| 616 | fname = name; |
| 617 | /* |
| 618 | * set the MAKEFILE variable desired by System V fans -- the |
| 619 | * placement of the setting here means it gets set to the last |
| 620 | * makefile specified, as it is set by SysV make. |
| 621 | */ |
| 622 | found: Var_Set("MAKEFILE", fname, VAR_GLOBAL); |
| 623 | Parse_File(fname, stream); |
| 624 | (void)fclose(stream); |
| 625 | } |
| 626 | return(TRUE); |
| 627 | } |
| 628 | |
| 629 | /*- |
| 630 | * Error -- |
| 631 | * Print an error message given its format. |
| 632 | * |
| 633 | * Results: |
| 634 | * None. |
| 635 | * |
| 636 | * Side Effects: |
| 637 | * The message is printed. |
| 638 | */ |
| 639 | /* VARARGS */ |
| 640 | void |
| 641 | Error(va_alist) |
| 642 | va_dcl |
| 643 | { |
| 644 | va_list ap; |
| 645 | char *fmt; |
| 646 | |
| 647 | va_start(ap); |
| 648 | fmt = va_arg(ap, char *); |
| 649 | (void)vfprintf(stderr, fmt, ap); |
| 650 | va_end(ap); |
| 651 | (void)fprintf(stderr, "\n"); |
| 652 | (void)fflush(stderr); |
| 653 | } |
| 654 | |
| 655 | /*- |
| 656 | * Fatal -- |
| 657 | * Produce a Fatal error message. If jobs are running, waits for them |
| 658 | * to finish. |
| 659 | * |
| 660 | * Results: |
| 661 | * None |
| 662 | * |
| 663 | * Side Effects: |
| 664 | * The program exits |
| 665 | */ |
| 666 | /* VARARGS */ |
| 667 | void |
| 668 | Fatal(va_alist) |
| 669 | va_dcl |
| 670 | { |
| 671 | va_list ap; |
| 672 | char *fmt; |
| 673 | |
| 674 | if (jobsRunning) |
| 675 | Job_Wait(); |
| 676 | |
| 677 | va_start(ap); |
| 678 | fmt = va_arg(ap, char *); |
| 679 | (void)vfprintf(stderr, fmt, ap); |
| 680 | va_end(ap); |
| 681 | (void)fprintf(stderr, "\n"); |
| 682 | (void)fflush(stderr); |
| 683 | |
| 684 | if (DEBUG(GRAPH2)) |
| 685 | Targ_PrintGraph(2); |
| 686 | exit(2); /* Not 1 so -q can distinguish error */ |
| 687 | } |
| 688 | |
| 689 | /* |
| 690 | * Punt -- |
| 691 | * Major exception once jobs are being created. Kills all jobs, prints |
| 692 | * a message and exits. |
| 693 | * |
| 694 | * Results: |
| 695 | * None |
| 696 | * |
| 697 | * Side Effects: |
| 698 | * All children are killed indiscriminately and the program Lib_Exits |
| 699 | */ |
| 700 | /* VARARGS */ |
| 701 | void |
| 702 | Punt(va_alist) |
| 703 | va_dcl |
| 704 | { |
| 705 | va_list ap; |
| 706 | char *fmt; |
| 707 | |
| 708 | (void)fprintf(stderr, "make: "); |
| 709 | va_start(ap); |
| 710 | fmt = va_arg(ap, char *); |
| 711 | (void)vfprintf(stderr, fmt, ap); |
| 712 | va_end(ap); |
| 713 | (void)fprintf(stderr, "\n"); |
| 714 | (void)fflush(stderr); |
| 715 | |
| 716 | DieHorribly(); |
| 717 | } |
| 718 | |
| 719 | /*- |
| 720 | * DieHorribly -- |
| 721 | * Exit without giving a message. |
| 722 | * |
| 723 | * Results: |
| 724 | * None |
| 725 | * |
| 726 | * Side Effects: |
| 727 | * A big one... |
| 728 | */ |
| 729 | void |
| 730 | DieHorribly() |
| 731 | { |
| 732 | if (jobsRunning) |
| 733 | Job_AbortAll(); |
| 734 | if (DEBUG(GRAPH2)) |
| 735 | Targ_PrintGraph(2); |
| 736 | exit(2); /* Not 1, so -q can distinguish error */ |
| 737 | } |
| 738 | |
| 739 | /* |
| 740 | * Finish -- |
| 741 | * Called when aborting due to errors in child shell to signal |
| 742 | * abnormal exit. |
| 743 | * |
| 744 | * Results: |
| 745 | * None |
| 746 | * |
| 747 | * Side Effects: |
| 748 | * The program exits |
| 749 | */ |
| 750 | void |
| 751 | Finish(errors) |
| 752 | int errors; /* number of errors encountered in Make_Make */ |
| 753 | { |
| 754 | Fatal("%d error%s", errors, errors == 1 ? "" : "s"); |
| 755 | } |
| 756 | |
| 757 | /* |
| 758 | * emalloc -- |
| 759 | * malloc, but die on error. |
| 760 | */ |
| 761 | char * |
| 762 | emalloc(len) |
| 763 | u_int len; |
| 764 | { |
| 765 | char *p, *malloc(); |
| 766 | |
| 767 | if (!(p = malloc(len))) |
| 768 | enomem(); |
| 769 | return(p); |
| 770 | } |
| 771 | |
| 772 | /* |
| 773 | * enomem -- |
| 774 | * die when out of memory. |
| 775 | */ |
| 776 | enomem() |
| 777 | { |
| 778 | (void)fprintf(stderr, "make: %s.\n", strerror(errno)); |
| 779 | exit(2); |
| 780 | } |
| 781 | |
| 782 | /* |
| 783 | * usage -- |
| 784 | * exit with usage message |
| 785 | */ |
| 786 | usage() |
| 787 | { |
| 788 | (void)fprintf(stderr, |
| 789 | "usage: make [-eiknqrst] [-D variable] [-d flags] [-f makefile ]\n\ |
| 790 | [-I directory] [-j max_jobs] [variable=value]\n"); |
| 791 | exit(2); |
| 792 | } |