VirtualBox

source: kBuild/trunk/src/kmk/main.c@ 30

Last change on this file since 30 was 30, checked in by bird, 22 years ago

Basic nmake emulation.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 33.3 KB
Line 
1/*
2 * Copyright (c) 1988, 1989, 1990, 1993
3 * The Regents of the University of California. All rights reserved.
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
40static const char copyright[] =
41"@(#) Copyright (c) 1988, 1989, 1990, 1993\n\
42 The Regents of the University of California. All rights reserved.\n";
43#endif /* not lint */
44
45#ifndef lint
46#if 0
47static char sccsid[] = "@(#)main.c 8.3 (Berkeley) 3/19/94";
48#else
49static const char rcsid[] =
50 "$FreeBSD: src/usr.bin/make/main.c,v 1.35.2.6 2002/07/24 16:50:18 ru Exp $";
51#endif
52#endif /* not lint */
53
54/*-
55 * main.c --
56 * The main file for this entire program. Exit routines etc
57 * reside here.
58 *
59 * Utility functions defined in this file:
60 * Main_ParseArgLine Takes a line of arguments, breaks them and
61 * treats them as if they were given when first
62 * invoked. Used by the parse module to implement
63 * the .MFLAGS target.
64 *
65 * Error Print a tagged error message. The global
66 * MAKE variable must have been defined. This
67 * takes a format string and two optional
68 * arguments for it.
69 *
70 * Fatal Print an error message and exit. Also takes
71 * a format string and two arguments.
72 *
73 * Punt Aborts all jobs and exits with a message. Also
74 * takes a format string and two arguments.
75 *
76 * Finish Finish things up by printing the number of
77 * errors which occured, as passed to it, and
78 * exiting.
79 */
80
81#ifdef USE_KLIB
82 #include <kLib/kLib.h>
83#endif
84
85#include <sys/types.h>
86#include <sys/time.h>
87#include <sys/param.h>
88#if !defined(__IBMC__)
89#include <sys/resource.h>
90#include <sys/signal.h>
91#endif
92#include <sys/stat.h>
93#if defined(__i386__)
94#include <sys/sysctl.h>
95#endif
96#ifndef MACHINE
97# if !defined(__IBMC__)
98# include <sys/utsname.h>
99# endif
100#endif
101#if !defined(__IBMC__)
102#include <sys/wait.h>
103#include <err.h>
104#endif
105#include <stdlib.h>
106#include <errno.h>
107#include <fcntl.h>
108#include <stdio.h>
109#if !defined(__IBMC__)
110#include <sysexits.h>
111#endif
112#if defined(__STDC__) || defined(__IBMC__)
113#include <stdarg.h>
114#else
115#include <varargs.h>
116#endif
117#if defined(__IBMC__)
118 #include <io.h>
119 #include <direct.h>
120 #ifndef MAXPATHLEN
121 #define MAXPATHLEN _MAX_PATH
122 #endif
123 #ifndef EISDIR
124 #define EISDIR 21 /* unused in errno.h, defined like this in DDK header. */
125 #endif
126 #ifndef S_ISDIR
127 #define S_IFMT (S_IFDIR | S_IFCHR | S_IFREG)
128 #define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
129 #endif
130#endif
131#include "make.h"
132#include "hash.h"
133#include "dir.h"
134#include "job.h"
135#include "pathnames.h"
136
137#ifndef DEFMAXLOCAL
138#define DEFMAXLOCAL DEFMAXJOBS
139#endif /* DEFMAXLOCAL */
140
141#define MAKEFLAGS ".MAKEFLAGS"
142
143Lst create; /* Targets to be made */
144time_t now; /* Time at start of make */
145GNode *DEFAULT; /* .DEFAULT node */
146Boolean allPrecious; /* .PRECIOUS given on line by itself */
147
148static Boolean noBuiltins; /* -r flag */
149static Lst makefiles; /* ordered list of makefiles to read */
150static Boolean printVars; /* print value of one or more vars */
151static Boolean expandVars; /* fully expand printed variables */
152static Lst variables; /* list of variables to print */
153int maxJobs; /* -j argument */
154static Boolean forceJobs; /* -j argument given */
155static int maxLocal; /* -L argument */
156Boolean compatMake; /* -B argument */
157Boolean debug; /* -d flag */
158Boolean noExecute; /* -n flag */
159Boolean keepgoing; /* -k flag */
160Boolean queryFlag; /* -q flag */
161Boolean touchFlag; /* -t flag */
162Boolean usePipes; /* !-P flag */
163Boolean ignoreErrors; /* -i flag */
164Boolean beSilent; /* -s flag */
165Boolean beVerbose; /* -v flag */
166Boolean oldVars; /* variable substitution style */
167Boolean checkEnvFirst; /* -e flag */
168Lst envFirstVars; /* (-E) vars to override from env */
169static Boolean jobsRunning; /* TRUE if the jobs might be running */
170#ifdef NMAKE
171static Boolean go_to_objdir; /* ! -o flag */
172#endif
173static void MainParseArgs __P((int, char **));
174char * chdir_verify_path __P((char *, char *));
175static int ReadMakefile __P((ClientData, ClientData));
176static void usage __P((void));
177
178static char *curdir; /* startup directory */
179static char *objdir; /* where we chdir'ed to */
180
181/*-
182 * MainParseArgs --
183 * Parse a given argument vector. Called from main() and from
184 * Main_ParseArgLine() when the .MAKEFLAGS target is used.
185 *
186 * XXX: Deal with command line overriding .MAKEFLAGS in makefile
187 *
188 * Results:
189 * None
190 *
191 * Side Effects:
192 * Various global and local flags will be set depending on the flags
193 * given
194 */
195static void
196MainParseArgs(argc, argv)
197 int argc;
198 char **argv;
199{
200 extern int optind;
201 extern char *optarg;
202 char *p;
203 int c;
204
205 optind = 1; /* since we're called more than once */
206#ifdef REMOTE
207# ifdef NMAKE
208# define OPTFLAGS "BD:E:I:L:PSV:Xd:ef:ij:km:nqrstvo"
209# else
210# define OPTFLAGS "BD:E:I:L:PSV:Xd:ef:ij:km:nqrstv"
211# endif
212#else
213# ifdef NMAKE
214# define OPTFLAGS "BD:E:I:PSV:Xd:ef:ij:km:nqrstvo"
215# else
216# define OPTFLAGS "BD:E:I:PSV:Xd:ef:ij:km:nqrstv"
217# endif
218#endif
219rearg: while((c = getopt(argc, argv, OPTFLAGS)) != -1) {
220 switch(c) {
221 case 'D':
222 Var_Set(optarg, "1", VAR_GLOBAL);
223 Var_Append(MAKEFLAGS, "-D", VAR_GLOBAL);
224 Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);
225 break;
226 case 'I':
227 Parse_AddIncludeDir(optarg);
228 Var_Append(MAKEFLAGS, "-I", VAR_GLOBAL);
229 Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);
230 break;
231 case 'V':
232 printVars = TRUE;
233 (void)Lst_AtEnd(variables, (ClientData)optarg);
234 Var_Append(MAKEFLAGS, "-V", VAR_GLOBAL);
235 Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);
236 break;
237 case 'X':
238 expandVars = FALSE;
239 break;
240 case 'B':
241 compatMake = TRUE;
242 Var_Append(MAKEFLAGS, "-B", VAR_GLOBAL);
243 break;
244#ifdef REMOTE
245 case 'L': {
246 char *endptr;
247
248 maxLocal = strtol(optarg, &endptr, 10);
249 if (maxLocal < 0 || *endptr != '\0') {
250 warnx("illegal number, -L argument -- %s",
251 optarg);
252 usage();
253 }
254 Var_Append(MAKEFLAGS, "-L", VAR_GLOBAL);
255 Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);
256 break;
257 }
258#endif
259 case 'P':
260 usePipes = FALSE;
261 Var_Append(MAKEFLAGS, "-P", VAR_GLOBAL);
262 break;
263 case 'S':
264 keepgoing = FALSE;
265 Var_Append(MAKEFLAGS, "-S", VAR_GLOBAL);
266 break;
267 case 'd': {
268 char *modules = optarg;
269
270 for (; *modules; ++modules)
271 switch (*modules) {
272 case 'A':
273 debug = ~0;
274 break;
275 case 'a':
276 debug |= DEBUG_ARCH;
277 break;
278 case 'c':
279 debug |= DEBUG_COND;
280 break;
281 case 'd':
282 debug |= DEBUG_DIR;
283 break;
284 case 'f':
285 debug |= DEBUG_FOR;
286 break;
287 case 'g':
288 if (modules[1] == '1') {
289 debug |= DEBUG_GRAPH1;
290 ++modules;
291 }
292 else if (modules[1] == '2') {
293 debug |= DEBUG_GRAPH2;
294 ++modules;
295 }
296 break;
297 case 'j':
298 debug |= DEBUG_JOB;
299 break;
300 case 'l':
301 debug |= DEBUG_LOUD;
302 break;
303 case 'm':
304 debug |= DEBUG_MAKE;
305 break;
306 case 's':
307 debug |= DEBUG_SUFF;
308 break;
309 case 't':
310 debug |= DEBUG_TARG;
311 break;
312 case 'v':
313 debug |= DEBUG_VAR;
314 break;
315 default:
316 warnx("illegal argument to d option -- %c", *modules);
317 usage();
318 }
319 Var_Append(MAKEFLAGS, "-d", VAR_GLOBAL);
320 Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);
321 break;
322 }
323 case 'E':
324 p = malloc(strlen(optarg) + 1);
325 if (!p)
326 Punt("make: cannot allocate memory.");
327 (void)strcpy(p, optarg);
328 (void)Lst_AtEnd(envFirstVars, (ClientData)p);
329 Var_Append(MAKEFLAGS, "-E", VAR_GLOBAL);
330 Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);
331 break;
332 case 'e':
333 checkEnvFirst = TRUE;
334 Var_Append(MAKEFLAGS, "-e", VAR_GLOBAL);
335 break;
336 case 'f':
337 (void)Lst_AtEnd(makefiles, (ClientData)optarg);
338 break;
339 case 'i':
340 ignoreErrors = TRUE;
341 Var_Append(MAKEFLAGS, "-i", VAR_GLOBAL);
342 break;
343 case 'j': {
344 char *endptr;
345
346 forceJobs = TRUE;
347 maxJobs = strtol(optarg, &endptr, 10);
348 if (maxJobs <= 0 || *endptr != '\0') {
349 warnx("illegal number, -j argument -- %s",
350 optarg);
351 usage();
352 }
353#ifndef REMOTE
354 maxLocal = maxJobs;
355#endif
356 Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL);
357 Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);
358 break;
359 }
360 case 'k':
361 keepgoing = TRUE;
362 Var_Append(MAKEFLAGS, "-k", VAR_GLOBAL);
363 break;
364 case 'm':
365 Dir_AddDir(sysIncPath, optarg);
366 Var_Append(MAKEFLAGS, "-m", VAR_GLOBAL);
367 Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);
368 break;
369 case 'n':
370 noExecute = TRUE;
371 Var_Append(MAKEFLAGS, "-n", VAR_GLOBAL);
372 break;
373#ifdef NMAKE
374 case 'o':
375 go_to_objdir = TRUE;
376 Var_Append(MAKEFLAGS, "-o", VAR_GLOBAL);
377 break;
378#endif
379 case 'q':
380 queryFlag = TRUE;
381 /* Kind of nonsensical, wot? */
382 Var_Append(MAKEFLAGS, "-q", VAR_GLOBAL);
383 break;
384 case 'r':
385 noBuiltins = TRUE;
386 Var_Append(MAKEFLAGS, "-r", VAR_GLOBAL);
387 break;
388 case 's':
389 beSilent = TRUE;
390 Var_Append(MAKEFLAGS, "-s", VAR_GLOBAL);
391 break;
392 case 't':
393 touchFlag = TRUE;
394 Var_Append(MAKEFLAGS, "-t", VAR_GLOBAL);
395 break;
396 case 'v':
397 beVerbose = TRUE;
398 Var_Append(MAKEFLAGS, "-v", VAR_GLOBAL);
399 break;
400 default:
401 case '?':
402 usage();
403 }
404 }
405
406 oldVars = TRUE;
407
408 /*
409 * See if the rest of the arguments are variable assignments and
410 * perform them if so. Else take them to be targets and stuff them
411 * on the end of the "create" list.
412 */
413 for (argv += optind, argc -= optind; *argv; ++argv, --argc)
414 if (Parse_IsVar(*argv))
415 Parse_DoVar(*argv, VAR_CMD);
416 else {
417 if (!**argv)
418 Punt("illegal (null) argument.");
419 if (**argv == '-') {
420 if ((*argv)[1])
421 optind = 0; /* -flag... */
422 else
423 optind = 1; /* - */
424 goto rearg;
425 }
426 (void)Lst_AtEnd(create, (ClientData)estrdup(*argv));
427 }
428}
429
430/*-
431 * Main_ParseArgLine --
432 * Used by the parse module when a .MFLAGS or .MAKEFLAGS target
433 * is encountered and by main() when reading the .MAKEFLAGS envariable.
434 * Takes a line of arguments and breaks it into its
435 * component words and passes those words and the number of them to the
436 * MainParseArgs function.
437 * The line should have all its leading whitespace removed.
438 *
439 * Results:
440 * None
441 *
442 * Side Effects:
443 * Only those that come from the various arguments.
444 */
445void
446Main_ParseArgLine(line)
447 char *line; /* Line to fracture */
448{
449 char **argv; /* Manufactured argument vector */
450 int argc; /* Number of arguments in argv */
451
452 if (line == NULL)
453 return;
454 for (; *line == ' '; ++line)
455 continue;
456 if (!*line)
457 return;
458
459 argv = brk_string(line, &argc, TRUE);
460 MainParseArgs(argc, argv);
461}
462
463char *
464chdir_verify_path(path, obpath)
465 char *path;
466 char *obpath;
467{
468 struct stat sb;
469#ifdef NMAKE
470 if (!go_to_objdir)
471 return NULL;
472#endif
473
474 if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) {
475 if (chdir(path)) {
476 warn("warning: %s", path);
477 return 0;
478 }
479 else {
480 if (path[0] != '/') {
481 (void) snprintf(obpath, MAXPATHLEN, "%s/%s",
482 curdir, path);
483 return obpath;
484 }
485 else
486 return path;
487 }
488 }
489
490 return 0;
491}
492
493
494/*-
495 * main --
496 * The main function, for obvious reasons. Initializes variables
497 * and a few modules, then parses the arguments give it in the
498 * environment and on the command line. Reads the system makefile
499 * followed by either Makefile, makefile or the file given by the
500 * -f argument. Sets the .MAKEFLAGS PMake variable based on all the
501 * flags it has received by then uses either the Make or the Compat
502 * module to create the initial list of targets.
503 *
504 * Results:
505 * If -q was given, exits -1 if anything was out-of-date. Else it exits
506 * 0.
507 *
508 * Side Effects:
509 * The program exits when done. Targets are created. etc. etc. etc.
510 */
511int
512main(argc, argv)
513 int argc;
514 char **argv;
515{
516 Lst targs; /* target nodes to create -- passed to Make_Init */
517 Boolean outOfDate = TRUE; /* FALSE if all targets up to date */
518 struct stat sa;
519 char *p, *p1, *path, *pathp;
520#ifdef WANT_ENV_PWD
521 struct stat sb;
522 char *pwd;
523#endif
524 char mdpath[MAXPATHLEN + 1];
525 char obpath[MAXPATHLEN + 1];
526 char cdpath[MAXPATHLEN + 1];
527 char *machine = getenv("MACHINE");
528 char *machine_arch = getenv("MACHINE_ARCH");
529 char *machine_cpu = getenv("MACHINE_CPU");
530 Lst sysMkPath; /* Path of sys.mk */
531 char *cp = NULL, *start;
532 /* avoid faults on read-only strings */
533 static char syspath[] = _PATH_DEFSYSPATH;
534
535#ifdef RLIMIT_NOFILE
536 /*
537 * get rid of resource limit on file descriptors
538 */
539 {
540 struct rlimit rl;
541 if (getrlimit(RLIMIT_NOFILE, &rl) != -1 &&
542 rl.rlim_cur != rl.rlim_max) {
543 rl.rlim_cur = rl.rlim_max;
544 (void) setrlimit(RLIMIT_NOFILE, &rl);
545 }
546 }
547#endif
548 /*
549 * Find where we are and take care of PWD for the automounter...
550 * All this code is so that we know where we are when we start up
551 * on a different machine with pmake.
552 */
553 curdir = cdpath;
554 if (getcwd(curdir, MAXPATHLEN) == NULL)
555 err(2, NULL);
556
557 if (stat(curdir, &sa) == -1)
558 err(2, "%s", curdir);
559
560#ifdef WANT_ENV_PWD
561 if ((pwd = getenv("PWD")) != NULL) {
562 if (stat(pwd, &sb) == 0 && sa.st_ino == sb.st_ino &&
563 sa.st_dev == sb.st_dev)
564 (void) strcpy(curdir, pwd);
565 }
566#endif
567
568#if defined(__i386__) && defined(__FreeBSD_version) && \
569 __FreeBSD_version > 300003
570 /*
571 * PC-98 kernel sets the `i386' string to the utsname.machine and
572 * it cannot be distinguished from IBM-PC by uname(3). Therefore,
573 * we check machine.ispc98 and adjust the machine variable before
574 * using usname(3) below.
575 * NOTE: machdep.ispc98 was defined on 1998/8/31. At that time,
576 * __FreeBSD_version was defined as 300003. So, this check can
577 * safely be done with any kernel with version > 300003.
578 */
579 if (!machine) {
580 int ispc98;
581 size_t len;
582
583 len = sizeof(ispc98);
584 if (!sysctlbyname("machdep.ispc98", &ispc98, &len, NULL, 0)) {
585 if (ispc98)
586 machine = "pc98";
587 }
588 }
589#endif
590
591 /*
592 * Get the name of this type of MACHINE from utsname
593 * so we can share an executable for similar machines.
594 * (i.e. m68k: amiga hp300, mac68k, sun3, ...)
595 *
596 * Note that while MACHINE is decided at run-time,
597 * MACHINE_ARCH is always known at compile time.
598 */
599 if (!machine) {
600#ifndef MACHINE
601 struct utsname utsname;
602
603 if (uname(&utsname) == -1) {
604 perror("make: uname");
605 exit(2);
606 }
607 machine = utsname.machine;
608#else
609 machine = MACHINE;
610#endif
611 }
612
613 if (!machine_arch) {
614#ifndef MACHINE_ARCH
615 machine_arch = "unknown";
616#else
617 machine_arch = MACHINE_ARCH;
618#endif
619 }
620
621 /*
622 * Set machine_cpu to the minumum supported CPU revision based
623 * on the target architecture, if not already set.
624 */
625 if (!machine_cpu) {
626 if (!strcmp(machine_arch, "i386"))
627 machine_cpu = "i386";
628 else if (!strcmp(machine_arch, "alpha"))
629 machine_cpu = "ev4";
630 else
631 machine_cpu = "unknown";
632 }
633
634 /*
635 * The object directory location is determined using the
636 * following order of preference:
637 *
638 * 1. MAKEOBJDIRPREFIX`cwd`
639 * 2. MAKEOBJDIR
640 * 3. _PATH_OBJDIR.${MACHINE}
641 * 4. _PATH_OBJDIR
642 * 5. _PATH_OBJDIRPREFIX`cwd`
643 *
644 * If one of the first two fails, use the current directory.
645 * If the remaining three all fail, use the current directory.
646 *
647 * Once things are initted,
648 * have to add the original directory to the search path,
649 * and modify the paths for the Makefiles apropriately. The
650 * current directory is also placed as a variable for make scripts.
651 */
652 if (!(pathp = getenv("MAKEOBJDIRPREFIX"))) {
653 if (!(path = getenv("MAKEOBJDIR"))) {
654 path = _PATH_OBJDIR;
655 pathp = _PATH_OBJDIRPREFIX;
656 (void) snprintf(mdpath, MAXPATHLEN, "%s.%s",
657 path, machine);
658 if (!(objdir = chdir_verify_path(mdpath, obpath)))
659 if (!(objdir=chdir_verify_path(path, obpath))) {
660 (void) snprintf(mdpath, MAXPATHLEN,
661 "%s%s", pathp, curdir);
662 if (!(objdir=chdir_verify_path(mdpath,
663 obpath)))
664 objdir = curdir;
665 }
666 }
667 else if (!(objdir = chdir_verify_path(path, obpath)))
668 objdir = curdir;
669 }
670 else {
671 (void) snprintf(mdpath, MAXPATHLEN, "%s%s", pathp, curdir);
672 if (!(objdir = chdir_verify_path(mdpath, obpath)))
673 objdir = curdir;
674 }
675
676#ifdef WANT_ENV_PWD
677 #ifdef USE_KLIB
678 kEnvSet("PWD", objdir);
679 #else
680 setenv("PWD", objdir, 1);
681 #endif
682#endif
683
684 create = Lst_Init(FALSE);
685 makefiles = Lst_Init(FALSE);
686 envFirstVars = Lst_Init(FALSE);
687 printVars = FALSE;
688 expandVars = TRUE;
689 variables = Lst_Init(FALSE);
690 beSilent = FALSE; /* Print commands as executed */
691 ignoreErrors = FALSE; /* Pay attention to non-zero returns */
692 noExecute = FALSE; /* Execute all commands */
693 keepgoing = FALSE; /* Stop on error */
694 allPrecious = FALSE; /* Remove targets when interrupted */
695 queryFlag = FALSE; /* This is not just a check-run */
696 noBuiltins = FALSE; /* Read the built-in rules */
697 touchFlag = FALSE; /* Actually update targets */
698 usePipes = TRUE; /* Catch child output in pipes */
699 debug = 0; /* No debug verbosity, please. */
700 jobsRunning = FALSE;
701#ifdef NMAKE
702 go_to_objdir = FALSE;
703#endif
704
705 maxLocal = DEFMAXLOCAL; /* Set default local max concurrency */
706#ifdef REMOTE
707 maxJobs = DEFMAXJOBS; /* Set default max concurrency */
708#else
709 maxJobs = maxLocal;
710#endif
711 forceJobs = FALSE; /* No -j flag */
712 compatMake = FALSE; /* No compat mode */
713
714
715 /*
716 * Initialize the parsing, directory and variable modules to prepare
717 * for the reading of inclusion paths and variable settings on the
718 * command line
719 */
720 Dir_Init(); /* Initialize directory structures so -I flags
721 * can be processed correctly */
722 Parse_Init(); /* Need to initialize the paths of #include
723 * directories */
724 Var_Init(); /* As well as the lists of variables for
725 * parsing arguments */
726 str_init();
727 if (objdir != curdir)
728 Dir_AddDir(dirSearchPath, curdir);
729 Var_Set(".CURDIR", curdir, VAR_GLOBAL);
730 Var_Set(".OBJDIR", objdir, VAR_GLOBAL);
731
732 /*
733 * Initialize various variables.
734 * MAKE also gets this name, for compatibility
735 * .MAKEFLAGS gets set to the empty string just in case.
736 * MFLAGS also gets initialized empty, for compatibility.
737 */
738 Var_Set("MAKE", argv[0], VAR_GLOBAL);
739 Var_Set(MAKEFLAGS, "", VAR_GLOBAL);
740 Var_Set("MFLAGS", "", VAR_GLOBAL);
741 Var_Set("MACHINE", machine, VAR_GLOBAL);
742 Var_Set("MACHINE_ARCH", machine_arch, VAR_GLOBAL);
743 Var_Set("MACHINE_CPU", machine_cpu, VAR_GLOBAL);
744
745 /*
746 * First snag any flags out of the MAKE environment variable.
747 * (Note this is *not* MAKEFLAGS since /bin/make uses that and it's
748 * in a different format).
749 */
750#ifdef POSIX
751 Main_ParseArgLine(getenv("MAKEFLAGS"));
752#else
753 Main_ParseArgLine(getenv("MAKE"));
754#endif
755
756 MainParseArgs(argc, argv);
757
758 /*
759 * Be compatible if user did not specify -j and did not explicitly
760 * turned compatibility on
761 */
762 if (!compatMake && !forceJobs)
763 compatMake = TRUE;
764
765 /*
766 * Initialize archive, target and suffix modules in preparation for
767 * parsing the makefile(s)
768 */
769 Arch_Init();
770 Targ_Init();
771 Suff_Init();
772
773 DEFAULT = NILGNODE;
774 (void)time(&now);
775
776 /*
777 * Set up the .TARGETS variable to contain the list of targets to be
778 * created. If none specified, make the variable empty -- the parser
779 * will fill the thing in with the default or .MAIN target.
780 */
781 if (!Lst_IsEmpty(create)) {
782 LstNode ln;
783
784 for (ln = Lst_First(create); ln != NILLNODE;
785 ln = Lst_Succ(ln)) {
786 char *name = (char *)Lst_Datum(ln);
787
788 Var_Append(".TARGETS", name, VAR_GLOBAL);
789 }
790 } else
791 Var_Set(".TARGETS", "", VAR_GLOBAL);
792
793
794 /*
795 * If no user-supplied system path was given (through the -m option)
796 * add the directories from the DEFSYSPATH (more than one may be given
797 * as dir1:...:dirn) to the system include path.
798 */
799 if (Lst_IsEmpty(sysIncPath)) {
800 for (start = syspath; *start != '\0'; start = cp) {
801 for (cp = start; *cp != '\0' && *cp != ':'; cp++)
802 continue;
803 if (*cp == '\0') {
804 Dir_AddDir(sysIncPath, start);
805 } else {
806 *cp++ = '\0';
807 Dir_AddDir(sysIncPath, start);
808 }
809 }
810 }
811
812 /*
813 * Read in the built-in rules first, followed by the specified
814 * makefile, if it was (makefile != (char *) NULL), or the default
815 * Makefile and makefile, in that order, if it wasn't.
816 */
817 if (!noBuiltins) {
818 LstNode ln;
819
820 sysMkPath = Lst_Init (FALSE);
821 Dir_Expand (_PATH_DEFSYSMK, sysIncPath, sysMkPath);
822 if (Lst_IsEmpty(sysMkPath))
823 Fatal("make: no system rules (%s).", _PATH_DEFSYSMK);
824 ln = Lst_Find(sysMkPath, (ClientData)NULL, ReadMakefile);
825 if (ln != NILLNODE)
826 Fatal("make: cannot open %s.", (char *)Lst_Datum(ln));
827 }
828
829 if (!Lst_IsEmpty(makefiles)) {
830 LstNode ln;
831
832 ln = Lst_Find(makefiles, (ClientData)NULL, ReadMakefile);
833 if (ln != NILLNODE)
834 Fatal("make: cannot open %s.", (char *)Lst_Datum(ln));
835 } else if (!ReadMakefile("makefile", NULL))
836 (void)ReadMakefile("Makefile", NULL);
837
838 (void)ReadMakefile(".depend", NULL);
839
840 Var_Append("MFLAGS", Var_Value(MAKEFLAGS, VAR_GLOBAL, &p1), VAR_GLOBAL);
841 efree(p1);
842
843 /* Install all the flags into the MAKE envariable. */
844 if (((p = Var_Value(MAKEFLAGS, VAR_GLOBAL, &p1)) != NULL) && *p)
845#ifdef POSIX
846 #ifdef USE_KLIB
847 kEnvSet("MAKEFLAGS", p);
848 #else
849 setenv("MAKEFLAGS", p, 1);
850 #endif
851#else
852 #ifdef USE_KLIB
853 kEnvSet("MAKE", p);
854 #else
855 setenv("MAKE", p, 1);
856 #endif
857#endif
858 efree(p1);
859
860 /*
861 * For compatibility, look at the directories in the VPATH variable
862 * and add them to the search path, if the variable is defined. The
863 * variable's value is in the same format as the PATH envariable, i.e.
864 * <directory>:<directory>:<directory>...
865 */
866 if (Var_Exists("VPATH", VAR_CMD)) {
867 char *vpath, *path, *cp, savec;
868 /*
869 * GCC stores string constants in read-only memory, but
870 * Var_Subst will want to write this thing, so store it
871 * in an array
872 */
873 static char VPATH[] = "${VPATH}";
874
875 vpath = Var_Subst(NULL, VPATH, VAR_CMD, FALSE);
876 path = vpath;
877 do {
878 /* skip to end of directory */
879 for (cp = path; *cp != ':' && *cp != '\0'; cp++)
880 continue;
881 /* Save terminator character so know when to stop */
882 savec = *cp;
883 *cp = '\0';
884 /* Add directory to search path */
885 Dir_AddDir(dirSearchPath, path);
886 *cp = savec;
887 path = cp + 1;
888 } while (savec == ':');
889 (void)free((Address)vpath);
890 }
891
892 /*
893 * Now that all search paths have been read for suffixes et al, it's
894 * time to add the default search path to their lists...
895 */
896 Suff_DoPaths();
897
898 /* print the initial graph, if the user requested it */
899 if (DEBUG(GRAPH1))
900 Targ_PrintGraph(1);
901
902 /* print the values of any variables requested by the user */
903 if (printVars) {
904 LstNode ln;
905
906 for (ln = Lst_First(variables); ln != NILLNODE;
907 ln = Lst_Succ(ln)) {
908 char *value;
909 if (expandVars) {
910 p1 = malloc(strlen((char *)Lst_Datum(ln)) + 1 + 3);
911 if (!p1)
912 Punt("make: cannot allocate memory.");
913 /* This sprintf is safe, because of the malloc above */
914 (void)sprintf(p1, "${%s}", (char *)Lst_Datum(ln));
915 value = Var_Subst(NULL, p1, VAR_GLOBAL, FALSE);
916 } else {
917 value = Var_Value((char *)Lst_Datum(ln),
918 VAR_GLOBAL, &p1);
919 }
920 printf("%s\n", value ? value : "");
921 if (p1)
922 free(p1);
923 }
924 }
925
926 /*
927 * Have now read the entire graph and need to make a list of targets
928 * to create. If none was given on the command line, we consult the
929 * parsing module to find the main target(s) to create.
930 */
931 if (Lst_IsEmpty(create))
932 targs = Parse_MainName();
933 else
934 targs = Targ_FindList(create, TARG_CREATE);
935
936 if (!compatMake && !printVars) {
937 /*
938 * Initialize job module before traversing the graph, now that
939 * any .BEGIN and .END targets have been read. This is done
940 * only if the -q flag wasn't given (to prevent the .BEGIN from
941 * being executed should it exist).
942 */
943 if (!queryFlag) {
944 if (maxLocal == -1)
945 maxLocal = maxJobs;
946 Job_Init(maxJobs, maxLocal);
947 jobsRunning = TRUE;
948 }
949
950 /* Traverse the graph, checking on all the targets */
951 outOfDate = Make_Run(targs);
952 } else if (!printVars) {
953 /*
954 * Compat_Init will take care of creating all the targets as
955 * well as initializing the module.
956 */
957 Compat_Run(targs);
958 }
959
960 Lst_Destroy(targs, NOFREE);
961 Lst_Destroy(variables, NOFREE);
962 Lst_Destroy(makefiles, NOFREE);
963 Lst_Destroy(create, (void (*) __P((ClientData))) free);
964
965 /* print the graph now it's been processed if the user requested it */
966 if (DEBUG(GRAPH2))
967 Targ_PrintGraph(2);
968
969 Suff_End();
970 Targ_End();
971 Arch_End();
972 str_end();
973 Var_End();
974 Parse_End();
975 Dir_End();
976
977 if (queryFlag && outOfDate)
978 return(1);
979 else
980 return(0);
981}
982
983/*-
984 * ReadMakefile --
985 * Open and parse the given makefile.
986 *
987 * Results:
988 * TRUE if ok. FALSE if couldn't open file.
989 *
990 * Side Effects:
991 * lots
992 */
993static Boolean
994ReadMakefile(p, q)
995 ClientData p, q;
996{
997 char *fname = p; /* makefile to read */
998 extern Lst parseIncPath;
999 FILE *stream;
1000 char *name, path[MAXPATHLEN + 1];
1001 char *MAKEFILE;
1002 int setMAKEFILE;
1003
1004 if (!strcmp(fname, "-")) {
1005 Parse_File("(stdin)", stdin);
1006 Var_Set("MAKEFILE", "", VAR_GLOBAL);
1007 } else {
1008 setMAKEFILE = strcmp(fname, ".depend");
1009
1010 /* if we've chdir'd, rebuild the path name */
1011 if (curdir != objdir && *fname != '/') {
1012 (void)snprintf(path, MAXPATHLEN, "%s/%s", curdir, fname);
1013 if (realpath(path, path) != NULL &&
1014 (stream = fopen(path, "r")) != NULL) {
1015 MAKEFILE = fname;
1016 fname = path;
1017 goto found;
1018 }
1019 } else if (realpath(fname, path) != NULL) {
1020 MAKEFILE = fname;
1021 fname = path;
1022 if ((stream = fopen(fname, "r")) != NULL)
1023 goto found;
1024 }
1025 /* look in -I and system include directories. */
1026 name = Dir_FindFile(fname, parseIncPath);
1027 if (!name)
1028 name = Dir_FindFile(fname, sysIncPath);
1029 if (!name || !(stream = fopen(name, "r")))
1030 return(FALSE);
1031 MAKEFILE = fname = name;
1032 /*
1033 * set the MAKEFILE variable desired by System V fans -- the
1034 * placement of the setting here means it gets set to the last
1035 * makefile specified, as it is set by SysV make.
1036 */
1037found:
1038 if (setMAKEFILE)
1039 Var_Set("MAKEFILE", MAKEFILE, VAR_GLOBAL);
1040 Parse_File(fname, stream);
1041 (void)fclose(stream);
1042 }
1043 return(TRUE);
1044}
1045
1046/*-
1047 * Cmd_Exec --
1048 * Execute the command in cmd, and return the output of that command
1049 * in a string.
1050 *
1051 * Results:
1052 * A string containing the output of the command, or the empty string
1053 * If err is not NULL, it contains the reason for the command failure
1054 *
1055 * Side Effects:
1056 * The string must be freed by the caller.
1057 */
1058char *
1059Cmd_Exec(cmd, err)
1060 char *cmd;
1061 char **err;
1062{
1063 char *args[4]; /* Args for invoking the shell */
1064 int fds[2]; /* Pipe streams */
1065 int cpid; /* Child PID */
1066 int pid; /* PID from wait() */
1067 char *res; /* result */
1068 int status; /* command exit status */
1069 Buffer buf; /* buffer to store the result */
1070 char *cp;
1071 int cc;
1072
1073
1074 *err = NULL;
1075
1076 /*
1077 * Set up arguments for shell
1078 */
1079 args[0] = "sh";
1080 args[1] = "-c";
1081 args[2] = cmd;
1082 args[3] = NULL;
1083
1084 /*
1085 * Open a pipe for fetching its output
1086 */
1087 if (pipe(fds) == -1) {
1088 *err = "Couldn't create pipe for \"%s\"";
1089 goto bad;
1090 }
1091
1092 /*
1093 * Fork
1094 */
1095 switch (cpid = vfork()) {
1096 case 0:
1097 /*
1098 * Close input side of pipe
1099 */
1100 (void) close(fds[0]);
1101
1102 /*
1103 * Duplicate the output stream to the shell's output, then
1104 * shut the extra thing down. Note we don't fetch the error
1105 * stream...why not? Why?
1106 */
1107 (void) dup2(fds[1], 1);
1108 (void) close(fds[1]);
1109
1110 (void) execv("/bin/sh", args);
1111 _exit(1);
1112 /*NOTREACHED*/
1113
1114 case -1:
1115 *err = "Couldn't exec \"%s\"";
1116 goto bad;
1117
1118 default:
1119 /*
1120 * No need for the writing half
1121 */
1122 (void) close(fds[1]);
1123
1124 buf = Buf_Init (MAKE_BSIZE);
1125
1126 do {
1127 char result[BUFSIZ];
1128 cc = read(fds[0], result, sizeof(result));
1129 if (cc > 0)
1130 Buf_AddBytes(buf, cc, (Byte *) result);
1131 }
1132 while (cc > 0 || (cc == -1 && errno == EINTR));
1133
1134 /*
1135 * Close the input side of the pipe.
1136 */
1137 (void) close(fds[0]);
1138
1139 /*
1140 * Wait for the process to exit.
1141 */
1142 while(((pid = wait(&status)) != cpid) && (pid >= 0))
1143 continue;
1144
1145 if (cc == -1)
1146 *err = "Error reading shell's output for \"%s\"";
1147
1148 res = (char *)Buf_GetAll (buf, &cc);
1149 Buf_Destroy (buf, FALSE);
1150
1151 if (status)
1152 *err = "\"%s\" returned non-zero status";
1153
1154 /*
1155 * Null-terminate the result, convert newlines to spaces and
1156 * install it in the variable.
1157 */
1158 res[cc] = '\0';
1159 cp = &res[cc] - 1;
1160
1161 if (*cp == '\n') {
1162 /*
1163 * A final newline is just stripped
1164 */
1165 *cp-- = '\0';
1166 }
1167 while (cp >= res) {
1168 if (*cp == '\n') {
1169 *cp = ' ';
1170 }
1171 cp--;
1172 }
1173 break;
1174 }
1175 return res;
1176bad:
1177 res = emalloc(1);
1178 *res = '\0';
1179 return res;
1180}
1181
1182/*-
1183 * Error --
1184 * Print an error message given its format.
1185 *
1186 * Results:
1187 * None.
1188 *
1189 * Side Effects:
1190 * The message is printed.
1191 */
1192/* VARARGS */
1193void
1194#if defined(__STDC__) || defined(__IBMC__)
1195Error(char *fmt, ...)
1196#else
1197Error(va_alist)
1198 va_dcl
1199#endif
1200{
1201 va_list ap;
1202#if defined(__STDC__) || defined(__IBMC__)
1203 va_start(ap, fmt);
1204#else
1205 char *fmt;
1206
1207 va_start(ap);
1208 fmt = va_arg(ap, char *);
1209#endif
1210 (void)vfprintf(stderr, fmt, ap);
1211 va_end(ap);
1212 (void)fprintf(stderr, "\n");
1213 (void)fflush(stderr);
1214}
1215
1216/*-
1217 * Fatal --
1218 * Produce a Fatal error message. If jobs are running, waits for them
1219 * to finish.
1220 *
1221 * Results:
1222 * None
1223 *
1224 * Side Effects:
1225 * The program exits
1226 */
1227/* VARARGS */
1228void
1229#if defined(__STDC__) || defined(__IBMC__)
1230Fatal(char *fmt, ...)
1231#else
1232Fatal(va_alist)
1233 va_dcl
1234#endif
1235{
1236 va_list ap;
1237#if defined(__STDC__) || defined(__IBMC__)
1238 va_start(ap, fmt);
1239#else
1240 char *fmt;
1241
1242 va_start(ap);
1243 fmt = va_arg(ap, char *);
1244#endif
1245 if (jobsRunning)
1246 Job_Wait();
1247
1248 (void)vfprintf(stderr, fmt, ap);
1249 va_end(ap);
1250 (void)fprintf(stderr, "\n");
1251 (void)fflush(stderr);
1252
1253 if (DEBUG(GRAPH2))
1254 Targ_PrintGraph(2);
1255 exit(2); /* Not 1 so -q can distinguish error */
1256}
1257
1258/*
1259 * Punt --
1260 * Major exception once jobs are being created. Kills all jobs, prints
1261 * a message and exits.
1262 *
1263 * Results:
1264 * None
1265 *
1266 * Side Effects:
1267 * All children are killed indiscriminately and the program Lib_Exits
1268 */
1269/* VARARGS */
1270void
1271#if defined(__STDC__) || defined(__IBMC__)
1272Punt(char *fmt, ...)
1273#else
1274Punt(va_alist)
1275 va_dcl
1276#endif
1277{
1278 va_list ap;
1279#if defined(__STDC__) || defined(__IBMC__)
1280 va_start(ap, fmt);
1281#else
1282 char *fmt;
1283
1284 va_start(ap);
1285 fmt = va_arg(ap, char *);
1286#endif
1287
1288 (void)fprintf(stderr, "make: ");
1289 (void)vfprintf(stderr, fmt, ap);
1290 va_end(ap);
1291 (void)fprintf(stderr, "\n");
1292 (void)fflush(stderr);
1293
1294 DieHorribly();
1295}
1296
1297/*-
1298 * DieHorribly --
1299 * Exit without giving a message.
1300 *
1301 * Results:
1302 * None
1303 *
1304 * Side Effects:
1305 * A big one...
1306 */
1307void
1308DieHorribly()
1309{
1310 if (jobsRunning)
1311 Job_AbortAll();
1312 if (DEBUG(GRAPH2))
1313 Targ_PrintGraph(2);
1314 exit(2); /* Not 1, so -q can distinguish error */
1315}
1316
1317/*
1318 * Finish --
1319 * Called when aborting due to errors in child shell to signal
1320 * abnormal exit.
1321 *
1322 * Results:
1323 * None
1324 *
1325 * Side Effects:
1326 * The program exits
1327 */
1328void
1329Finish(errors)
1330 int errors; /* number of errors encountered in Make_Make */
1331{
1332 Fatal("%d error%s", errors, errors == 1 ? "" : "s");
1333}
1334
1335/*
1336 * emalloc --
1337 * malloc, but die on error.
1338 */
1339void *
1340emalloc(len)
1341 size_t len;
1342{
1343 void *p;
1344
1345 if ((p = malloc(len)) == NULL)
1346 enomem();
1347 return(p);
1348}
1349
1350/*
1351 * estrdup --
1352 * strdup, but die on error.
1353 */
1354char *
1355estrdup(str)
1356 const char *str;
1357{
1358 char *p;
1359
1360 if ((p = strdup(str)) == NULL)
1361 enomem();
1362 return(p);
1363}
1364
1365/*
1366 * erealloc --
1367 * realloc, but die on error.
1368 */
1369void *
1370erealloc(ptr, size)
1371 void *ptr;
1372 size_t size;
1373{
1374 if ((ptr = realloc(ptr, size)) == NULL)
1375 enomem();
1376 return(ptr);
1377}
1378
1379/*
1380 * enomem --
1381 * die when out of memory.
1382 */
1383void
1384enomem()
1385{
1386 err(2, NULL);
1387}
1388
1389/*
1390 * enunlink --
1391 * Remove a file carefully, avoiding directories.
1392 */
1393int
1394eunlink(file)
1395 const char *file;
1396{
1397 struct stat st;
1398
1399 if (lstat(file, &st) == -1)
1400 return -1;
1401
1402 if (S_ISDIR(st.st_mode)) {
1403 errno = EISDIR;
1404 return -1;
1405 }
1406 return unlink(file);
1407}
1408
1409/*
1410 * usage --
1411 * exit with usage message
1412 */
1413static void
1414usage()
1415{
1416 (void)fprintf(stderr, "%s\n%s\n%s\n"
1417#ifdef NMAKE
1418"%s\n"
1419#endif
1420 ,
1421"usage: kmk [-Beiknqrstv] [-D variable] [-d flags] [-E variable] [-f makefile]",
1422" [-I directory] [-j max_jobs] [-m directory] [-V variable]",
1423" [variable=value] [target ...]"
1424#ifdef NMAKE
1425,"NMAKE compatible mode enabled."
1426
1427#endif
1428);
1429 exit(2);
1430}
1431
1432
1433int
1434PrintAddr(a, b)
1435 ClientData a;
1436 ClientData b;
1437{
1438 printf("%lx ", (unsigned long) a);
1439 return b ? 0 : 0;
1440}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette