Check result of setenv(putenv) function.
[dragonfly.git] / usr.bin / make / main.c
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  * @(#) Copyright (c) 1988, 1989, 1990, 1993 The Regents of the University of California.  All rights reserved.
39  * @(#)main.c   8.3 (Berkeley) 3/19/94
40  * $FreeBSD: src/usr.bin/make/main.c,v 1.118 2005/02/13 13:33:56 harti Exp $
41  * $DragonFly: src/usr.bin/make/main.c,v 1.141 2005/08/18 07:58:30 okumoto Exp $
42  */
43
44 /*
45  * main.c
46  *      The main file for this entire program. Exit routines etc
47  *      reside here.
48  *
49  * Utility functions defined in this file:
50  *      Main_ParseArgLine
51  *                      Takes a line of arguments, breaks them and
52  *                      treats them as if they were given when first
53  *                      invoked. Used by the parse module to implement
54  *                      the .MFLAGS target.
55  */
56
57 #ifndef MACHINE
58 #include <sys/utsname.h>
59 #endif
60 #include <sys/param.h>
61 #include <sys/stat.h>
62 #include <sys/time.h>
63 #include <sys/queue.h>
64 #include <sys/resource.h>
65 #include <sys/wait.h>
66 #include <err.h>
67 #include <errno.h>
68 #include <stdlib.h>
69 #include <string.h>
70 #include <unistd.h>
71
72 #include "arch.h"
73 #include "buf.h"
74 #include "config.h"
75 #include "dir.h"
76 #include "globals.h"
77 #include "job.h"
78 #include "make.h"
79 #include "parse.h"
80 #include "pathnames.h"
81 #include "shell.h"
82 #include "str.h"
83 #include "suff.h"
84 #include "targ.h"
85 #include "util.h"
86 #include "var.h"
87
88 extern char **environ;  /* XXX what header declares this variable? */
89
90 /*
91  * DEFMAXJOBS
92  *      This control the default concurrency. On no occasion will more
93  *      than DEFMAXJOBS targets be created at once.
94  */
95 #define DEFMAXJOBS      1
96
97 typedef struct CLI {
98         /** ordered list of makefiles to read */
99         Lst makefiles;
100
101         /** list of variables to print */
102         Lst variables;
103
104         /** Targets to be made */
105         Lst create;
106
107         /** directories to search when looking for includes */
108         struct Path     parseIncPath;
109
110         /** directories to search when looking for system includes */
111         struct Path     sysIncPath;
112
113         bool    expandVars;     /* fully expand printed variables */
114         bool    builtins;       /* -r flag */
115         bool    forceJobs;      /* -j argument given */
116
117         /**
118          * -q flag:
119          * true if we aren't supposed to really make anything, just
120          * see if the targets are out-of-date
121          */
122         bool            queryFlag;
123 } CLI;
124
125 /* (-E) vars to override from env */
126 Lst envFirstVars = Lst_Initializer(envFirstVars);
127
128 bool            allPrecious;    /* .PRECIOUS given on line by itself */
129 bool            beSilent;       /* -s flag */
130 bool            beVerbose;      /* -v flag */
131 bool            compatMake;     /* -B argument */
132 int             debug;          /* -d flag */
133 bool            ignoreErrors;   /* -i flag */
134 int             jobLimit;       /* -j argument */
135 bool            jobsRunning;    /* true if the jobs might be running */
136 bool            keepgoing;      /* -k flag */
137 bool            noExecute;      /* -n flag */
138 bool            touchFlag;      /* -t flag */
139 bool            usePipes;       /* !-P flag */
140 uint32_t        warn_cmd;       /* command line warning flags */
141 uint32_t        warn_flags;     /* actual warning flags */
142 uint32_t        warn_nocmd;     /* command line no-warning flags */
143
144 time_t          now;            /* Time at start of make */
145 struct GNode    *DEFAULT;       /* .DEFAULT node */
146
147
148 /**
149  * Exit with usage message.
150  */
151 static void
152 usage(void)
153 {
154         fprintf(stderr,
155             "usage: make [-BPSXeiknqrstv] [-C directory] [-D variable]\n"
156             "\t[-d flags] [-E variable] [-f makefile] [-I directory]\n"
157             "\t[-j max_jobs] [-m directory] [-V variable]\n"
158             "\t[variable=value] [target ...]\n");
159         exit(2);
160 }
161
162 /**
163  * MFLAGS_append
164  *      Append a flag with an optional argument to MAKEFLAGS and MFLAGS
165  */
166 static void
167 MFLAGS_append(const char *flag, char *arg)
168 {
169         char *str;
170
171         Var_Append(".MAKEFLAGS", flag, VAR_GLOBAL);
172         if (arg != NULL) {
173                 str = MAKEFLAGS_quote(arg);
174                 Var_Append(".MAKEFLAGS", str, VAR_GLOBAL);
175                 free(str);
176         }
177
178         Var_Append("MFLAGS", flag, VAR_GLOBAL);
179         if (arg != NULL) {
180                 str = MAKEFLAGS_quote(arg);
181                 Var_Append("MFLAGS", str, VAR_GLOBAL);
182                 free(str);
183         }
184 }
185
186 /**
187  * Open and parse the given makefile.
188  *
189  * Results:
190  *      true if ok. false if couldn't open file.
191  */
192 static bool
193 ReadMakefile(Parser *parser, CLI *cli, const char file[], const char curdir[], const char objdir[])
194 {
195         char    path[MAXPATHLEN];
196         FILE    *stream;
197         char    *fname;
198         char    *name;
199
200         if (!strcmp(file, "-")) {
201                 Parse_File(parser, cli, "(stdin)", stdin);
202                 Var_SetGlobal("MAKEFILE", "");
203                 return (true);
204         }
205
206         if (strcmp(curdir, objdir) == 0 || file[0] == '/') {
207                 strcpy(path, file);
208         } else {
209                 /*
210                  * we've chdir'd, rebuild the path name
211                  */
212                 snprintf(path, MAXPATHLEN, "%s/%s", curdir, file);
213         }
214 #if THIS_BREAKS_THINGS
215         /*
216          * XXX The realpath stuff breaks relative includes
217          * XXX in some cases.   The problem likely is in
218          * XXX parse.c where it does special things in
219          * XXX ParseDoInclude if the file is relateive
220          * XXX or absolute and not a system file.  There
221          * XXX it assumes that if the current file that's
222          * XXX being included is absolute, that any files
223          * XXX that it includes shouldn't do the -I path
224          * XXX stuff, which is inconsistant with historical
225          * XXX behavior.  However, I can't pentrate the mists
226          * XXX further, so I'm putting this workaround in
227          * XXX here until such time as the underlying bug
228          * XXX can be fixed.
229          */
230         if (realpath(path, path) == NULL) {
231                 stream = NULL;
232         } else {
233                 stream = fopen(path, "r");
234         }
235 #else
236         stream = fopen(path, "r");
237 #endif
238         if (stream != NULL) {
239                 if (strcmp(file, ".depend") != 0)
240                         Var_SetGlobal("MAKEFILE", file);
241                 Parse_File(parser, cli, path, stream);
242                 fclose(stream);
243                 return (true);
244         }
245
246         /* look in -I and system include directories. */
247         fname = estrdup(file);
248         name = NULL;
249         if (name == NULL)
250                 name = Path_FindFile(fname, &cli->parseIncPath);
251         if (name == NULL)
252                 name = Path_FindFile(fname, &cli->sysIncPath);
253
254         if (name != NULL) {
255                 stream = fopen(name, "r");
256                 if (stream != NULL) {
257                         /*
258                          * set the MAKEFILE variable desired by System V fans
259                          * -- the placement of the setting here means it gets
260                          * set to the last makefile specified, as it is set
261                          * by SysV make.
262                          */
263                         if (strcmp(file, ".depend") != 0)
264                                 Var_SetGlobal("MAKEFILE", name);
265                         Parse_File(parser, cli, name, stream);
266                         fclose(stream);
267                         return (true);
268                 }
269         }
270
271         return (false); /* no makefile found */
272 }
273
274 /**
275  * Read in the built-in rules first, followed by the specified
276  * makefiles or the one of the default makefiles.  Finally .depend
277  * makefile.
278  */
279 static void
280 ReadInputFiles(Parser *parser, CLI *cli, const char curdir[], const char objdir[])
281 {
282         if (cli->builtins) {
283                 char    defsysmk[] = PATH_DEFSYSMK;     /* Path of sys.mk */
284                 Lst     sysMkPath = Lst_Initializer(sysMkPath);
285                 LstNode *ln;
286
287                 Path_Expand(defsysmk, &cli->sysIncPath, &sysMkPath);
288                 if (Lst_IsEmpty(&sysMkPath))
289                         Fatal("make: no system rules (%s).", PATH_DEFSYSMK);
290
291                 LST_FOREACH(ln, &sysMkPath) {
292                         char *name = Lst_Datum(ln);
293                         if (!ReadMakefile(parser, cli, name, curdir, objdir))
294                                 Fatal("make: cannot open %s.", name);
295                 }
296                 Lst_Destroy(&sysMkPath, free);
297         }
298
299         if (!Lst_IsEmpty(&cli->makefiles)) {
300                 LstNode *ln;
301
302                 LST_FOREACH(ln, &cli->makefiles) {
303                         char *name = Lst_Datum(ln);
304                         if (!ReadMakefile(parser, cli, name, curdir, objdir))
305                                 Fatal("make: cannot open %s.", name);
306                 }
307         } else if (ReadMakefile(parser, cli, "BSDmakefile", curdir, objdir)) {
308                 /* read BSDmakefile */
309         } else if (ReadMakefile(parser, cli, "makefile", curdir, objdir)) {
310                 /* read makefile */
311         } else if (ReadMakefile(parser, cli, "Makefile", curdir, objdir)) {
312                 /* read Makefile */
313         } else {
314                 /* No Makefile found */
315         }
316
317         ReadMakefile(parser, cli, ".depend", curdir, objdir);
318 }
319
320 /**
321  * Main_ParseWarn
322  *
323  *      Handle argument to warning option.
324  */
325 int
326 Main_ParseWarn(const char *arg, int iscmd)
327 {
328         int i, neg;
329
330         static const struct {
331                 const char      *option;
332                 uint32_t        flag;
333         } options[] = {
334                 { "dirsyntax",  WARN_DIRSYNTAX },
335                 { NULL,         0 }
336         };
337
338         neg = 0;
339         if (arg[0] == 'n' && arg[1] == 'o') {
340                 neg = 1;
341                 arg += 2;
342         }
343
344         for (i = 0; options[i].option != NULL; i++)
345                 if (strcmp(arg, options[i].option) == 0)
346                         break;
347
348         if (options[i].option == NULL)
349                 /* unknown option */
350                 return (-1);
351
352         if (iscmd) {
353                 if (!neg) {
354                         warn_cmd |= options[i].flag;
355                         warn_nocmd &= ~options[i].flag;
356                         warn_flags |= options[i].flag;
357                 } else {
358                         warn_nocmd |= options[i].flag;
359                         warn_cmd &= ~options[i].flag;
360                         warn_flags &= ~options[i].flag;
361                 }
362         } else {
363                 if (!neg) {
364                         warn_flags |= (options[i].flag & ~warn_nocmd);
365                 } else {
366                         warn_flags &= ~(options[i].flag | warn_cmd);
367                 }
368         }
369         return (0);
370 }
371
372 /**
373  * MainParseArgs
374  *      Parse a given argument vector. Called from main() and from
375  *      Main_ParseArgLine() when the .MAKEFLAGS target is used.
376  *
377  *      XXX: Deal with command line overriding .MAKEFLAGS in makefile
378  *
379  * Side Effects:
380  *      Various global and local flags will be set depending on the flags
381  *      given
382  */
383 static void
384 MainParseArgs(CLI *cli, int argc, char **argv)
385 {
386         int c;
387         bool    found_dd = false;
388
389 rearg:
390         optind = 1;     /* since we're called more than once */
391         optreset = 1;
392 #define OPTFLAGS "ABC:D:E:I:PSV:Xd:ef:ij:km:nqrstvx:"
393         for (;;) {
394                 if ((optind < argc) && strcmp(argv[optind], "--") == 0) {
395                         found_dd = true;
396                 }
397                 if ((c = getopt(argc, argv, OPTFLAGS)) == -1) {
398                         break;
399                 }
400                 switch(c) {
401
402                 case 'A':
403                         arch_fatal = false;
404                         MFLAGS_append("-A", NULL);
405                         break;
406                 case 'C':
407                         if (chdir(optarg) == -1)
408                                 err(1, "chdir %s", optarg);
409                         break;
410                 case 'D':
411                         Var_SetGlobal(optarg, "1");
412                         MFLAGS_append("-D", optarg);
413                         break;
414                 case 'I':
415                         Path_AddDir(&cli->parseIncPath, optarg);
416                         MFLAGS_append("-I", optarg);
417                         break;
418                 case 'V':
419                         Lst_AtEnd(&cli->variables, estrdup(optarg));
420                         MFLAGS_append("-V", optarg);
421                         break;
422                 case 'X':
423                         cli->expandVars = false;
424                         break;
425                 case 'B':
426                         compatMake = true;
427                         MFLAGS_append("-B", NULL);
428                         unsetenv("MAKE_JOBS_FIFO");
429                         break;
430                 case 'P':
431                         usePipes = false;
432                         MFLAGS_append("-P", NULL);
433                         break;
434                 case 'S':
435                         keepgoing = false;
436                         MFLAGS_append("-S", NULL);
437                         break;
438                 case 'd': {
439                         char *modules = optarg;
440
441                         for (; *modules; ++modules)
442                                 switch (*modules) {
443                                 case 'A':
444                                         debug = ~0;
445                                         break;
446                                 case 'a':
447                                         debug |= DEBUG_ARCH;
448                                         break;
449                                 case 'c':
450                                         debug |= DEBUG_COND;
451                                         break;
452                                 case 'd':
453                                         debug |= DEBUG_DIR;
454                                         break;
455                                 case 'f':
456                                         debug |= DEBUG_FOR;
457                                         break;
458                                 case 'g':
459                                         if (modules[1] == '1') {
460                                                 debug |= DEBUG_GRAPH1;
461                                                 ++modules;
462                                         }
463                                         else if (modules[1] == '2') {
464                                                 debug |= DEBUG_GRAPH2;
465                                                 ++modules;
466                                         }
467                                         break;
468                                 case 'j':
469                                         debug |= DEBUG_JOB;
470                                         break;
471                                 case 'l':
472                                         debug |= DEBUG_LOUD;
473                                         break;
474                                 case 'm':
475                                         debug |= DEBUG_MAKE;
476                                         break;
477                                 case 's':
478                                         debug |= DEBUG_SUFF;
479                                         break;
480                                 case 't':
481                                         debug |= DEBUG_TARG;
482                                         break;
483                                 case 'v':
484                                         debug |= DEBUG_VAR;
485                                         break;
486                                 default:
487                                         warnx("illegal argument to d option "
488                                             "-- %c", *modules);
489                                         usage();
490                                 }
491                         MFLAGS_append("-d", optarg);
492                         break;
493                 }
494                 case 'E':
495                         Lst_AtEnd(&envFirstVars, estrdup(optarg));
496                         MFLAGS_append("-E", optarg);
497                         break;
498                 case 'e':
499                         checkEnvFirst = true;
500                         MFLAGS_append("-e", NULL);
501                         break;
502                 case 'f':
503                         Lst_AtEnd(&cli->makefiles, estrdup(optarg));
504                         break;
505                 case 'i':
506                         ignoreErrors = true;
507                         MFLAGS_append("-i", NULL);
508                         break;
509                 case 'j': {
510                         char *endptr;
511
512                         cli->forceJobs = true;
513                         jobLimit = strtol(optarg, &endptr, 10);
514                         if (jobLimit <= 0 || *endptr != '\0') {
515                                 warnx("illegal number, -j argument -- %s",
516                                     optarg);
517                                 usage();
518                         }
519                         MFLAGS_append("-j", optarg);
520                         break;
521                 }
522                 case 'k':
523                         keepgoing = true;
524                         MFLAGS_append("-k", NULL);
525                         break;
526                 case 'm':
527                         Path_AddDir(&cli->sysIncPath, optarg);
528                         MFLAGS_append("-m", optarg);
529                         break;
530                 case 'n':
531                         noExecute = true;
532                         MFLAGS_append("-n", NULL);
533                         break;
534                 case 'q':
535                         cli->queryFlag = true;
536                         /* Kind of nonsensical, wot? */
537                         MFLAGS_append("-q", NULL);
538                         break;
539                 case 'r':
540                         cli->builtins = false;
541                         MFLAGS_append("-r", NULL);
542                         break;
543                 case 's':
544                         beSilent = true;
545                         MFLAGS_append("-s", NULL);
546                         break;
547                 case 't':
548                         touchFlag = true;
549                         MFLAGS_append("-t", NULL);
550                         break;
551                 case 'v':
552                         beVerbose = true;
553                         MFLAGS_append("-v", NULL);
554                         break;
555                 case 'x':
556                         if (Main_ParseWarn(optarg, 1) != -1)
557                                 MFLAGS_append("-x", optarg);
558                         break;
559                 default:
560                 case '?':
561                         usage();
562                 }
563         }
564         argv += optind;
565         argc -= optind;
566
567         oldVars = true;
568
569         /*
570          * Parse the rest of the arguments.
571          *      o Check for variable assignments and perform them if so.
572          *      o Check for more flags and restart getopt if so.
573          *      o Anything else is taken to be a target and added
574          *        to the end of the "create" list.
575          */
576         for (; *argv != NULL; ++argv, --argc) {
577                 if (Parse_IsVar(*argv)) {
578                         char *ptr = MAKEFLAGS_quote(*argv);
579
580                         Var_Append(".MAKEFLAGS", ptr, VAR_GLOBAL);
581                         Parse_DoVar(*argv, VAR_CMD);
582                         free(ptr);
583
584                 } else if ((*argv)[0] == '-') {
585                         if ((*argv)[1] == '\0') {
586                                 /*
587                                  * (*argv) is a single dash, so we
588                                  * just ignore it.
589                                  */
590                         } else if (found_dd) {
591                                 /*
592                                  * Double dash has been found, ignore
593                                  * any more options.  But what do we do
594                                  * with it?  For now treat it like a target.
595                                  */
596                                 Lst_AtEnd(&cli->create, estrdup(*argv));
597                         } else {
598                                 /*
599                                  * (*argv) is a -flag, so backup argv and
600                                  * argc.  getopt() expects options to start
601                                  * in the 2nd position.
602                                  */
603                                 argc++;
604                                 argv--;
605                                 goto rearg;
606                         }
607
608                 } else if ((*argv)[0] == '\0') {
609                         Punt("illegal (null) argument.");
610
611                 } else {
612                         Lst_AtEnd(&cli->create, estrdup(*argv));
613                 }
614         }
615 }
616
617 /**
618  * Main_ParseArgLine
619  *      Used by the parse module when a .MFLAGS or .MAKEFLAGS target
620  *      is encountered and by main() when reading the .MAKEFLAGS envariable.
621  *      Takes a line of arguments and breaks it into its
622  *      component words and passes those words and the number of them to the
623  *      MainParseArgs function.
624  *      The line should have all its leading whitespace removed.
625  *
626  * Side Effects:
627  *      Only those that come from the various arguments.
628  */
629 void
630 Main_ParseArgLine(CLI *cli, const char line[], int mflags)
631 {
632         ArgArray        aa;
633
634         if (mflags) {
635                 MAKEFLAGS_break(&aa, line);
636         } else {
637                 brk_string(&aa, line, true);
638         }
639         MainParseArgs(cli, aa.argc, aa.argv);
640         ArgArray_Done(&aa);
641 }
642
643 /**
644  * Try to change the current working directory to path, and return
645  * the whole path using getcwd().
646  *
647  * @note for amd managed mount points we really should use pawd(1).
648  */
649 static int
650 CheckDir(const char path[], char newdir[])
651 {
652         struct stat sb;
653
654         /*
655          * Check if the path is a directory.  If not fail without reporting
656          * an error.
657          */
658         if (stat(path, &sb) < 0) {
659                 return (0);
660         }
661         if (S_ISDIR(sb.st_mode) == 0) {
662                 return (0);
663         }
664
665         /*
666          * The path refers to a directory, so we try to change into it. If we
667          * fail, or we fail to obtain the path from root to the directory,
668          * then report an error and fail.
669          */
670         if (chdir(path) < 0) {
671                 warn("warning: %s", path);
672                 return (0);
673         }
674         if (getcwd(newdir, MAXPATHLEN) == NULL) {
675                 warn("warning: %s", path);
676                 return (0);
677         }
678
679         /*
680          * Directory in path is accessable, newdir should now contain the
681          * path to it.
682          */
683         return (1);
684 }
685
686 /**
687  * Determine location of the object directory.
688  */
689 static void
690 FindObjDir(const char machine[], char curdir[], char objdir[])
691 {
692         struct stat     sa;
693         char            newdir[MAXPATHLEN];
694         char            mdpath[MAXPATHLEN];
695         const char      *env;
696
697         /*
698          * Find a path to where we are... [-C directory] might have changed
699          * our current directory.
700          */
701         if (getcwd(curdir, MAXPATHLEN) == NULL)
702                 err(2, NULL);
703
704         if (stat(curdir, &sa) == -1)
705                 err(2, "%s", curdir);
706
707         /*
708          * The object directory location is determined using the
709          * following order of preference:
710          *
711          *      1. MAKEOBJDIRPREFIX`cwd`
712          *      2. MAKEOBJDIR
713          *      3. PATH_OBJDIR.${MACHINE}
714          *      4. PATH_OBJDIR
715          *      5. PATH_OBJDIRPREFIX`cwd`
716          *
717          * If one of the first two fails, use the current directory.
718          * If the remaining three all fail, use the current directory.
719          */
720         if ((env = getenv("MAKEOBJDIRPREFIX")) != NULL) {
721                 snprintf(mdpath, MAXPATHLEN, "%s%s", env, curdir);
722                 if (CheckDir(mdpath, newdir)) {
723                         strcpy(objdir, newdir);
724                         return;
725                 }
726                 strcpy(objdir, curdir);
727                 return;
728         }
729
730         if ((env = getenv("MAKEOBJDIR")) != NULL) {
731                 if (CheckDir(env, newdir)) {
732                         strcpy(objdir, newdir);
733                         return;
734                 }
735                 strcpy(objdir, curdir);
736                 return;
737         }
738
739         snprintf(mdpath, MAXPATHLEN, "%s.%s", PATH_OBJDIR, machine);
740         if (CheckDir(mdpath, newdir)) {
741                 strcpy(objdir, newdir);
742                 return;
743         }
744
745         if (CheckDir(PATH_OBJDIR, newdir)) {
746                 strcpy(objdir, newdir);
747                 return;
748         }
749
750         snprintf(mdpath, MAXPATHLEN, "%s%s", PATH_OBJDIRPREFIX, curdir);
751         if (CheckDir(mdpath, newdir)) {
752                 strcpy(objdir, newdir);
753                 return;
754         }
755
756         strcpy(objdir, curdir);
757 }
758
759 /**
760  * Initialize various make variables.
761  *      MAKE also gets this name, for compatibility
762  *      .MAKEFLAGS gets set to the empty string just in case.
763  *      MFLAGS also gets initialized empty, for compatibility.
764  */
765 static void
766 InitVariables(const char progname[])
767 {
768         const char      *machine;
769         const char      *machine_arch;
770         const char      *machine_cpu;
771
772         Var_SetGlobal("MAKE", progname);
773         Var_SetGlobal(".MAKEFLAGS", "");
774         Var_SetGlobal("MFLAGS", "");
775
776         Var_SetGlobal(".DIRECTIVE_MAKEENV", "YES");
777         Var_SetGlobal(".ST_EXPORTVAR", "YES");
778 #ifdef MAKE_VERSION
779         Var_SetGlobal("MAKE_VERSION", MAKE_VERSION);
780 #endif
781
782         /*
783          * Get the name of this type of MACHINE from utsname
784          * so we can share an executable for similar machines.
785          * (i.e. m68k: amiga hp300, mac68k, sun3, ...)
786          *
787          * Note that while MACHINE is decided at run-time,
788          * MACHINE_ARCH is always known at compile time.
789          */
790         if ((machine = getenv("MACHINE")) == NULL) {
791 #ifdef MACHINE
792                 machine = MACHINE;
793 #else
794                 static struct utsname   utsname;
795                 if (uname(&utsname) == -1)
796                         err(2, "uname");
797                 machine = utsname.machine;
798 #endif
799         }
800
801         if ((machine_arch = getenv("MACHINE_ARCH")) == NULL) {
802 #ifdef MACHINE_ARCH
803                 machine_arch = MACHINE_ARCH;
804 #else
805                 machine_arch = "unknown";
806 #endif
807         }
808
809         /*
810          * Set machine_cpu to the minumum supported CPU revision based
811          * on the target architecture, if not already set.
812          */
813         if ((machine_cpu = getenv("MACHINE_CPU")) == NULL) {
814                 if (!strcmp(machine_arch, "i386"))
815                         machine_cpu = "i386";
816                 else if (!strcmp(machine_arch, "alpha"))
817                         machine_cpu = "ev4";
818                 else
819                         machine_cpu = "unknown";
820         }
821
822         Var_SetGlobal("MACHINE", machine);
823         Var_SetGlobal("MACHINE_ARCH", machine_arch);
824         Var_SetGlobal("MACHINE_CPU", machine_cpu);
825 }
826
827 /**
828  * Build targets given in the command line or if none were given
829  * use the main target determined by the parsing module.
830  */
831 static int
832 BuildStuff(CLI *cli)
833 {
834         int     status;
835         Lst     targs = Lst_Initializer(targs);
836
837         if (Lst_IsEmpty(&cli->create))
838                 Parse_MainName(&targs);
839         else
840                 Targ_FindList(&targs, &cli->create, TARG_CREATE);
841
842         /* Traverse the graph, checking on all the targets */
843         if (compatMake) {
844                 Sig_Init(true);
845                 status = Compat_Run(&targs, cli->queryFlag);
846         } else {
847                 Sig_Init(false);
848                 status = Make_Run(&targs, cli->queryFlag);
849         }
850
851         Lst_Destroy(&targs, NOFREE);
852         return (status);
853 }
854
855 /**
856  * main
857  *      The main function, for obvious reasons. Initializes variables
858  *      and a few modules, then parses the arguments give it in the
859  *      environment and on the command line. Reads the system makefile
860  *      followed by either Makefile, makefile or the file given by the
861  *      -f argument. Sets the .MAKEFLAGS PMake variable based on all the
862  *      flags it has received by then uses either the Make or the Compat
863  *      module to create the initial list of targets.
864  *
865  * Results:
866  *      If -q was given, exits -1 if anything was out-of-date. Else it exits
867  *      0.
868  *
869  * Side Effects:
870  *      The program exits when done. Targets are created. etc. etc. etc.
871  */
872 int
873 main(int argc, char **argv)
874 {
875         CLI             cli;
876         Parser          parser;
877         int             status;         /* exit status */
878         char            curdir[MAXPATHLEN];     /* startup directory */
879         char            objdir[MAXPATHLEN];     /* where we chdir'ed to */
880         const char      *make_flags;
881
882         /*------------------------------------------------------------*
883          * This section initializes stuff that require no input.
884          *------------------------------------------------------------*/
885         /*
886          * Initialize program globals.
887          */
888         beSilent = false;               /* Print commands as executed */
889         ignoreErrors = false;           /* Pay attention to non-zero returns */
890         noExecute = false;              /* Execute all commands */
891         keepgoing = false;              /* Stop on error */
892         allPrecious = false;            /* Remove targets when interrupted */
893         touchFlag = false;              /* Actually update targets */
894         usePipes = true;                /* Catch child output in pipes */
895         debug = 0;                      /* No debug verbosity, please. */
896         jobsRunning = false;
897
898         jobLimit = DEFMAXJOBS;
899         compatMake = false;             /* No compat mode */
900
901         /*
902          * Initialize program flags.
903          */
904         Lst_Init(&cli.makefiles);
905         Lst_Init(&cli.variables);
906         Lst_Init(&cli.create);
907         TAILQ_INIT(&cli.parseIncPath);
908         TAILQ_INIT(&cli.sysIncPath);
909
910         cli.expandVars = true;
911         cli.builtins = true;            /* Read the built-in rules */
912         cli.queryFlag = false;
913         cli.forceJobs = false;
914
915         /*
916          * Initialize the various modules.
917          */
918         Proc_Init();
919         Shell_Init(DEFSHELLNAME);
920         Targ_Init();
921         Suff_Init();
922         Dir_Init();
923
924         /*------------------------------------------------------------*
925          * This section initializes stuff that depend on things
926          * in the enviornment, command line, or a input file.
927          *------------------------------------------------------------*/
928         Var_Init(environ);
929
930         InitVariables(argv[0]);
931
932         /*
933          * First snag things out of the MAKEFLAGS environment
934          * variable.  Then parse the command line arguments.
935          */
936         if ((make_flags = getenv("MAKEFLAGS")) != NULL) {
937                 Main_ParseArgLine(&cli, make_flags, 1);
938         }
939         MainParseArgs(&cli, argc, argv);
940
941         FindObjDir(Var_Value("MACHINE", VAR_GLOBAL), curdir, objdir);
942         Var_SetGlobal(".CURDIR", curdir);
943         Var_SetGlobal(".OBJDIR", objdir);
944
945         /*
946          * Set up the .TARGETS variable to contain the list of targets to be
947          * created. If none specified, make the variable empty -- the parser
948          * will fill the thing in with the default or .MAIN target.
949          */
950         if (Lst_IsEmpty(&cli.create)) {
951                 Var_SetGlobal(".TARGETS", "");
952         } else {
953                 LstNode *ln;
954
955                 LST_FOREACH(ln, &cli.create) {
956                         char *name = Lst_Datum(ln);
957
958                         Var_Append(".TARGETS", name, VAR_GLOBAL);
959                 }
960         }
961
962         Dir_CurObj(curdir, objdir);
963
964         /*
965          * If no user-supplied system path was given (through the -m option)
966          * add the directories from the DEFSYSPATH (more than one may be given
967          * as dir1:...:dirn) to the system include path.
968          */
969         if (TAILQ_EMPTY(&cli.sysIncPath)) {
970                 char syspath[] = PATH_DEFSYSPATH;
971                 char *start = syspath;
972                 char *cp;
973
974                 while ((cp = strsep(&start, ":")) != NULL) {
975                         Path_AddDir(&cli.sysIncPath, cp);
976                 }
977         }
978
979         if (getenv("MAKE_JOBS_FIFO") != NULL)
980                 cli.forceJobs = true;
981
982         /*
983          * Be compatible if user did not specify -j and did not explicitly
984          * turned compatibility on
985          */
986         if (compatMake == false && cli.forceJobs == false)
987                 compatMake = true;
988
989         DEFAULT = NULL;
990         time(&now);
991
992         parser.create = &cli.create;
993         parser.parseIncPath = &cli.parseIncPath;
994         parser.sysIncPath = &cli.sysIncPath;
995
996         ReadInputFiles(&parser, &cli, curdir, objdir);
997
998         /*------------------------------------------------------------*
999          * We are finished processing inputs.
1000          *------------------------------------------------------------*/
1001
1002         /* Install all the flags into the MAKE envariable. */
1003         {
1004                 const char *p;
1005
1006                 p = Var_Value(".MAKEFLAGS", VAR_GLOBAL);
1007                 if (p != NULL && *p != '\0') {
1008                         if (setenv("MAKEFLAGS", p, 1) == -1)
1009                                 Punt("setenv: MAKEFLAGS: can't allocate memory");
1010                 }
1011         }
1012
1013         /*
1014          * For compatibility, look at the directories in the VPATH variable
1015          * and add them to the search path, if the variable is defined. The
1016          * variable's value is in the same format as the PATH envariable, i.e.
1017          * <directory>:<directory>:<directory>...
1018          */
1019         if (Var_Exists("VPATH", VAR_CMD)) {
1020                 Buffer  *buf = Var_Subst("${VPATH}", VAR_CMD, false);
1021                 char    *start = Buf_Data(buf);
1022                 char    *cp;
1023
1024                 while ((cp = strsep(&start, ":")) != NULL) {
1025                         Path_AddDir(&dirSearchPath, cp);
1026                 }
1027
1028                 Buf_Destroy(buf, true);
1029         }
1030
1031         /*
1032          * Now that all search paths have been read for suffixes et al, it's
1033          * time to add the default search path to their lists...
1034          */
1035         Suff_DoPaths();
1036
1037         /* print the initial graph, if the user requested it */
1038         if (DEBUG(GRAPH1))
1039                 Targ_PrintGraph(1);
1040
1041         if (Lst_IsEmpty(&cli.variables)) {
1042                 status = BuildStuff(&cli);
1043         } else {
1044                 /* Print the values of variables requested by the user. */
1045                 Var_Print(&cli.variables, cli.expandVars);
1046
1047                 /*
1048                  * XXX
1049                  * This should be a "don't care", we do not check
1050                  * the status of any files.  It might make sense to
1051                  * modify Var_Print() to indicate that one of the
1052                  * requested variables did not exist, and use that
1053                  * as the return status.
1054                  * XXX
1055                  */
1056                 status = cli.queryFlag ? 1 : 0;
1057         }
1058
1059         /* print the graph now it's been processed if the user requested it */
1060         if (DEBUG(GRAPH2))
1061                 Targ_PrintGraph(2);
1062
1063 #if 0
1064         TAILQ_DESTROY(&cli.sysIncPath);
1065         TAILQ_DESTROY(&cli.parseIncPath);
1066 #endif
1067         Lst_Destroy(&cli.create, free);
1068         Lst_Destroy(&cli.variables, free);
1069         Lst_Destroy(&cli.makefiles, free);
1070
1071         return (status);
1072 }
1073