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