Sat Oct 31 16:13:00 2020 UTC ()
make(1): revert requiring a writable objdir

The change in main.c 1.413 broke the NetBSD build.sh if it uses a
read-only source tree, as in the daily builds.

Original commit:
https://mail-index.netbsd.org/source-changes/2020/10/31/msg123560.html

Build log:
make warning: /home/source/ab/HEAD/src: Permission denied.
[1]   Segmentation fault      "${make}" -m ${T...


(rillig)
diff -r1.418 -r1.419 src/usr.bin/make/main.c

cvs diff -r1.418 -r1.419 src/usr.bin/make/main.c (switch to unified diff)

--- src/usr.bin/make/main.c 2020/10/31 11:34:30 1.418
+++ src/usr.bin/make/main.c 2020/10/31 16:13:00 1.419
@@ -1,1723 +1,1723 @@ @@ -1,1723 +1,1723 @@
1/* $NetBSD: main.c,v 1.418 2020/10/31 11:34:30 rillig Exp $ */ 1/* $NetBSD: main.c,v 1.419 2020/10/31 16:13:00 rillig Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 1988, 1989, 1990, 1993 4 * Copyright (c) 1988, 1989, 1990, 1993
5 * The Regents of the University of California. All rights reserved. 5 * The Regents of the University of California. All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to Berkeley by 7 * This code is derived from software contributed to Berkeley by
8 * Adam de Boor. 8 * Adam de Boor.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright 15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the 16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution. 17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors 18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software 19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission. 20 * without specific prior written permission.
21 * 21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE. 32 * SUCH DAMAGE.
33 */ 33 */
34 34
35/* 35/*
36 * Copyright (c) 1989 by Berkeley Softworks 36 * Copyright (c) 1989 by Berkeley Softworks
37 * All rights reserved. 37 * All rights reserved.
38 * 38 *
39 * This code is derived from software contributed to Berkeley by 39 * This code is derived from software contributed to Berkeley by
40 * Adam de Boor. 40 * Adam de Boor.
41 * 41 *
42 * Redistribution and use in source and binary forms, with or without 42 * Redistribution and use in source and binary forms, with or without
43 * modification, are permitted provided that the following conditions 43 * modification, are permitted provided that the following conditions
44 * are met: 44 * are met:
45 * 1. Redistributions of source code must retain the above copyright 45 * 1. Redistributions of source code must retain the above copyright
46 * notice, this list of conditions and the following disclaimer. 46 * notice, this list of conditions and the following disclaimer.
47 * 2. Redistributions in binary form must reproduce the above copyright 47 * 2. Redistributions in binary form must reproduce the above copyright
48 * notice, this list of conditions and the following disclaimer in the 48 * notice, this list of conditions and the following disclaimer in the
49 * documentation and/or other materials provided with the distribution. 49 * documentation and/or other materials provided with the distribution.
50 * 3. All advertising materials mentioning features or use of this software 50 * 3. All advertising materials mentioning features or use of this software
51 * must display the following acknowledgement: 51 * must display the following acknowledgement:
52 * This product includes software developed by the University of 52 * This product includes software developed by the University of
53 * California, Berkeley and its contributors. 53 * California, Berkeley and its contributors.
54 * 4. Neither the name of the University nor the names of its contributors 54 * 4. Neither the name of the University nor the names of its contributors
55 * may be used to endorse or promote products derived from this software 55 * may be used to endorse or promote products derived from this software
56 * without specific prior written permission. 56 * without specific prior written permission.
57 * 57 *
58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
68 * SUCH DAMAGE. 68 * SUCH DAMAGE.
69 */ 69 */
70 70
71/*- 71/*-
72 * main.c -- 72 * main.c --
73 * The main file for this entire program. Exit routines etc 73 * The main file for this entire program. Exit routines etc
74 * reside here. 74 * reside here.
75 * 75 *
76 * Utility functions defined in this file: 76 * Utility functions defined in this file:
77 * Main_ParseArgLine Takes a line of arguments, breaks them and 77 * Main_ParseArgLine Takes a line of arguments, breaks them and
78 * treats them as if they were given when first 78 * treats them as if they were given when first
79 * invoked. Used by the parse module to implement 79 * invoked. Used by the parse module to implement
80 * the .MFLAGS target. 80 * the .MFLAGS target.
81 * 81 *
82 * Error Print a tagged error message. The global 82 * Error Print a tagged error message. The global
83 * MAKE variable must have been defined. This 83 * MAKE variable must have been defined. This
84 * takes a format string and optional arguments 84 * takes a format string and optional arguments
85 * for it. 85 * for it.
86 * 86 *
87 * Fatal Print an error message and exit. Also takes 87 * Fatal Print an error message and exit. Also takes
88 * a format string and arguments for it. 88 * a format string and arguments for it.
89 * 89 *
90 * Punt Aborts all jobs and exits with a message. Also 90 * Punt Aborts all jobs and exits with a message. Also
91 * takes a format string and arguments for it. 91 * takes a format string and arguments for it.
92 * 92 *
93 * Finish Finish things up by printing the number of 93 * Finish Finish things up by printing the number of
94 * errors which occurred, as passed to it, and 94 * errors which occurred, as passed to it, and
95 * exiting. 95 * exiting.
96 */ 96 */
97 97
98#include <sys/types.h> 98#include <sys/types.h>
99#include <sys/time.h> 99#include <sys/time.h>
100#include <sys/param.h> 100#include <sys/param.h>
101#include <sys/resource.h> 101#include <sys/resource.h>
102#include <sys/stat.h> 102#include <sys/stat.h>
103#ifdef MAKE_NATIVE 103#ifdef MAKE_NATIVE
104#include <sys/sysctl.h> 104#include <sys/sysctl.h>
105#endif 105#endif
106#include <sys/utsname.h> 106#include <sys/utsname.h>
107#include <sys/wait.h> 107#include <sys/wait.h>
108 108
109#include <errno.h> 109#include <errno.h>
110#include <signal.h> 110#include <signal.h>
111#include <stdarg.h> 111#include <stdarg.h>
112#include <time.h> 112#include <time.h>
113 113
114#include "make.h" 114#include "make.h"
115#include "dir.h" 115#include "dir.h"
116#include "job.h" 116#include "job.h"
117#include "pathnames.h" 117#include "pathnames.h"
118#include "trace.h" 118#include "trace.h"
119 119
120/* "@(#)main.c 8.3 (Berkeley) 3/19/94" */ 120/* "@(#)main.c 8.3 (Berkeley) 3/19/94" */
121MAKE_RCSID("$NetBSD: main.c,v 1.418 2020/10/31 11:34:30 rillig Exp $"); 121MAKE_RCSID("$NetBSD: main.c,v 1.419 2020/10/31 16:13:00 rillig Exp $");
122#if defined(MAKE_NATIVE) && !defined(lint) 122#if defined(MAKE_NATIVE) && !defined(lint)
123__COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1990, 1993 " 123__COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1990, 1993 "
124 "The Regents of the University of California. " 124 "The Regents of the University of California. "
125 "All rights reserved."); 125 "All rights reserved.");
126#endif 126#endif
127 127
128#ifndef DEFMAXLOCAL 128#ifndef DEFMAXLOCAL
129#define DEFMAXLOCAL DEFMAXJOBS 129#define DEFMAXLOCAL DEFMAXJOBS
130#endif 130#endif
131 131
132CmdOpts opts; 132CmdOpts opts;
133time_t now; /* Time at start of make */ 133time_t now; /* Time at start of make */
134GNode *DEFAULT; /* .DEFAULT node */ 134GNode *DEFAULT; /* .DEFAULT node */
135Boolean allPrecious; /* .PRECIOUS given on line by itself */ 135Boolean allPrecious; /* .PRECIOUS given on line by itself */
136Boolean deleteOnError; /* .DELETE_ON_ERROR: set */ 136Boolean deleteOnError; /* .DELETE_ON_ERROR: set */
137 137
138static int maxJobTokens; /* -j argument */ 138static int maxJobTokens; /* -j argument */
139Boolean enterFlagObj; /* -w and objdir != srcdir */ 139Boolean enterFlagObj; /* -w and objdir != srcdir */
140 140
141Boolean oldVars; /* variable substitution style */ 141Boolean oldVars; /* variable substitution style */
142static int jp_0 = -1, jp_1 = -1; /* ends of parent job pipe */ 142static int jp_0 = -1, jp_1 = -1; /* ends of parent job pipe */
143Boolean doing_depend; /* Set while reading .depend */ 143Boolean doing_depend; /* Set while reading .depend */
144static Boolean jobsRunning; /* TRUE if the jobs might be running */ 144static Boolean jobsRunning; /* TRUE if the jobs might be running */
145static const char * tracefile; 145static const char * tracefile;
146static int ReadMakefile(const char *); 146static int ReadMakefile(const char *);
147static void usage(void) MAKE_ATTR_DEAD; 147static void usage(void) MAKE_ATTR_DEAD;
148static void purge_cached_realpaths(void); 148static void purge_cached_realpaths(void);
149 149
150static Boolean ignorePWD; /* if we use -C, PWD is meaningless */ 150static Boolean ignorePWD; /* if we use -C, PWD is meaningless */
151static char objdir[MAXPATHLEN + 1]; /* where we chdir'ed to */ 151static char objdir[MAXPATHLEN + 1]; /* where we chdir'ed to */
152char curdir[MAXPATHLEN + 1]; /* Startup directory */ 152char curdir[MAXPATHLEN + 1]; /* Startup directory */
153char *progname; /* the program name */ 153char *progname; /* the program name */
154char *makeDependfile; 154char *makeDependfile;
155pid_t myPid; 155pid_t myPid;
156int makelevel; 156int makelevel;
157 157
158Boolean forceJobs = FALSE; 158Boolean forceJobs = FALSE;
159 159
160extern SearchPath *parseIncPath; 160extern SearchPath *parseIncPath;
161 161
162/* 162/*
163 * For compatibility with the POSIX version of MAKEFLAGS that includes 163 * For compatibility with the POSIX version of MAKEFLAGS that includes
164 * all the options with out -, convert flags to -f -l -a -g -s. 164 * all the options with out -, convert flags to -f -l -a -g -s.
165 */ 165 */
166static char * 166static char *
167explode(const char *flags) 167explode(const char *flags)
168{ 168{
169 size_t len; 169 size_t len;
170 char *nf, *st; 170 char *nf, *st;
171 const char *f; 171 const char *f;
172 172
173 if (flags == NULL) 173 if (flags == NULL)
174 return NULL; 174 return NULL;
175 175
176 for (f = flags; *f; f++) 176 for (f = flags; *f; f++)
177 if (!ch_isalpha(*f)) 177 if (!ch_isalpha(*f))
178 break; 178 break;
179 179
180 if (*f) 180 if (*f)
181 return bmake_strdup(flags); 181 return bmake_strdup(flags);
182 182
183 len = strlen(flags); 183 len = strlen(flags);
184 st = nf = bmake_malloc(len * 3 + 1); 184 st = nf = bmake_malloc(len * 3 + 1);
185 while (*flags) { 185 while (*flags) {
186 *nf++ = '-'; 186 *nf++ = '-';
187 *nf++ = *flags++; 187 *nf++ = *flags++;
188 *nf++ = ' '; 188 *nf++ = ' ';
189 } 189 }
190 *nf = '\0'; 190 *nf = '\0';
191 return st; 191 return st;
192} 192}
193 193
194static void 194static void
195parse_debug_option_F(const char *modules) 195parse_debug_option_F(const char *modules)
196{ 196{
197 const char *mode; 197 const char *mode;
198 size_t len; 198 size_t len;
199 char *fname; 199 char *fname;
200 200
201 if (opts.debug_file != stdout && opts.debug_file != stderr) 201 if (opts.debug_file != stdout && opts.debug_file != stderr)
202 fclose(opts.debug_file); 202 fclose(opts.debug_file);
203 203
204 if (*modules == '+') { 204 if (*modules == '+') {
205 modules++; 205 modules++;
206 mode = "a"; 206 mode = "a";
207 } else 207 } else
208 mode = "w"; 208 mode = "w";
209 209
210 if (strcmp(modules, "stdout") == 0) { 210 if (strcmp(modules, "stdout") == 0) {
211 opts.debug_file = stdout; 211 opts.debug_file = stdout;
212 return; 212 return;
213 } 213 }
214 if (strcmp(modules, "stderr") == 0) { 214 if (strcmp(modules, "stderr") == 0) {
215 opts.debug_file = stderr; 215 opts.debug_file = stderr;
216 return; 216 return;
217 } 217 }
218 218
219 len = strlen(modules); 219 len = strlen(modules);
220 fname = bmake_malloc(len + 20); 220 fname = bmake_malloc(len + 20);
221 memcpy(fname, modules, len + 1); 221 memcpy(fname, modules, len + 1);
222 222
223 /* Let the filename be modified by the pid */ 223 /* Let the filename be modified by the pid */
224 if (strcmp(fname + len - 3, ".%d") == 0) 224 if (strcmp(fname + len - 3, ".%d") == 0)
225 snprintf(fname + len - 2, 20, "%d", getpid()); 225 snprintf(fname + len - 2, 20, "%d", getpid());
226 226
227 opts.debug_file = fopen(fname, mode); 227 opts.debug_file = fopen(fname, mode);
228 if (!opts.debug_file) { 228 if (!opts.debug_file) {
229 fprintf(stderr, "Cannot open debug file %s\n", 229 fprintf(stderr, "Cannot open debug file %s\n",
230 fname); 230 fname);
231 usage(); 231 usage();
232 } 232 }
233 free(fname); 233 free(fname);
234} 234}
235 235
236static void 236static void
237parse_debug_options(const char *argvalue) 237parse_debug_options(const char *argvalue)
238{ 238{
239 const char *modules; 239 const char *modules;
240 240
241 for (modules = argvalue; *modules; ++modules) { 241 for (modules = argvalue; *modules; ++modules) {
242 switch (*modules) { 242 switch (*modules) {
243 case '0': /* undocumented, only intended for tests */ 243 case '0': /* undocumented, only intended for tests */
244 opts.debug &= DEBUG_LINT; 244 opts.debug &= DEBUG_LINT;
245 break; 245 break;
246 case 'A': 246 case 'A':
247 opts.debug = ~(0|DEBUG_LINT); 247 opts.debug = ~(0|DEBUG_LINT);
248 break; 248 break;
249 case 'a': 249 case 'a':
250 opts.debug |= DEBUG_ARCH; 250 opts.debug |= DEBUG_ARCH;
251 break; 251 break;
252 case 'C': 252 case 'C':
253 opts.debug |= DEBUG_CWD; 253 opts.debug |= DEBUG_CWD;
254 break; 254 break;
255 case 'c': 255 case 'c':
256 opts.debug |= DEBUG_COND; 256 opts.debug |= DEBUG_COND;
257 break; 257 break;
258 case 'd': 258 case 'd':
259 opts.debug |= DEBUG_DIR; 259 opts.debug |= DEBUG_DIR;
260 break; 260 break;
261 case 'e': 261 case 'e':
262 opts.debug |= DEBUG_ERROR; 262 opts.debug |= DEBUG_ERROR;
263 break; 263 break;
264 case 'f': 264 case 'f':
265 opts.debug |= DEBUG_FOR; 265 opts.debug |= DEBUG_FOR;
266 break; 266 break;
267 case 'g': 267 case 'g':
268 if (modules[1] == '1') { 268 if (modules[1] == '1') {
269 opts.debug |= DEBUG_GRAPH1; 269 opts.debug |= DEBUG_GRAPH1;
270 ++modules; 270 ++modules;
271 } 271 }
272 else if (modules[1] == '2') { 272 else if (modules[1] == '2') {
273 opts.debug |= DEBUG_GRAPH2; 273 opts.debug |= DEBUG_GRAPH2;
274 ++modules; 274 ++modules;
275 } 275 }
276 else if (modules[1] == '3') { 276 else if (modules[1] == '3') {
277 opts.debug |= DEBUG_GRAPH3; 277 opts.debug |= DEBUG_GRAPH3;
278 ++modules; 278 ++modules;
279 } 279 }
280 break; 280 break;
281 case 'h': 281 case 'h':
282 opts.debug |= DEBUG_HASH; 282 opts.debug |= DEBUG_HASH;
283 break; 283 break;
284 case 'j': 284 case 'j':
285 opts.debug |= DEBUG_JOB; 285 opts.debug |= DEBUG_JOB;
286 break; 286 break;
287 case 'L': 287 case 'L':
288 opts.debug |= DEBUG_LINT; 288 opts.debug |= DEBUG_LINT;
289 break; 289 break;
290 case 'l': 290 case 'l':
291 opts.debug |= DEBUG_LOUD; 291 opts.debug |= DEBUG_LOUD;
292 break; 292 break;
293 case 'M': 293 case 'M':
294 opts.debug |= DEBUG_META; 294 opts.debug |= DEBUG_META;
295 break; 295 break;
296 case 'm': 296 case 'm':
297 opts.debug |= DEBUG_MAKE; 297 opts.debug |= DEBUG_MAKE;
298 break; 298 break;
299 case 'n': 299 case 'n':
300 opts.debug |= DEBUG_SCRIPT; 300 opts.debug |= DEBUG_SCRIPT;
301 break; 301 break;
302 case 'p': 302 case 'p':
303 opts.debug |= DEBUG_PARSE; 303 opts.debug |= DEBUG_PARSE;
304 break; 304 break;
305 case 's': 305 case 's':
306 opts.debug |= DEBUG_SUFF; 306 opts.debug |= DEBUG_SUFF;
307 break; 307 break;
308 case 't': 308 case 't':
309 opts.debug |= DEBUG_TARG; 309 opts.debug |= DEBUG_TARG;
310 break; 310 break;
311 case 'V': 311 case 'V':
312 opts.debugVflag = TRUE; 312 opts.debugVflag = TRUE;
313 break; 313 break;
314 case 'v': 314 case 'v':
315 opts.debug |= DEBUG_VAR; 315 opts.debug |= DEBUG_VAR;
316 break; 316 break;
317 case 'x': 317 case 'x':
318 opts.debug |= DEBUG_SHELL; 318 opts.debug |= DEBUG_SHELL;
319 break; 319 break;
320 case 'F': 320 case 'F':
321 parse_debug_option_F(modules + 1); 321 parse_debug_option_F(modules + 1);
322 goto debug_setbuf; 322 goto debug_setbuf;
323 default: 323 default:
324 (void)fprintf(stderr, 324 (void)fprintf(stderr,
325 "%s: illegal argument to d option -- %c\n", 325 "%s: illegal argument to d option -- %c\n",
326 progname, *modules); 326 progname, *modules);
327 usage(); 327 usage();
328 } 328 }
329 } 329 }
330debug_setbuf: 330debug_setbuf:
331 /* 331 /*
332 * Make the debug_file unbuffered, and make 332 * Make the debug_file unbuffered, and make
333 * stdout line buffered (unless debugfile == stdout). 333 * stdout line buffered (unless debugfile == stdout).
334 */ 334 */
335 setvbuf(opts.debug_file, NULL, _IONBF, 0); 335 setvbuf(opts.debug_file, NULL, _IONBF, 0);
336 if (opts.debug_file != stdout) { 336 if (opts.debug_file != stdout) {
337 setvbuf(stdout, NULL, _IOLBF, 0); 337 setvbuf(stdout, NULL, _IOLBF, 0);
338 } 338 }
339} 339}
340 340
341/* 341/*
342 * does path contain any relative components 342 * does path contain any relative components
343 */ 343 */
344static Boolean 344static Boolean
345is_relpath(const char *path) 345is_relpath(const char *path)
346{ 346{
347 const char *cp; 347 const char *cp;
348 348
349 if (path[0] != '/') 349 if (path[0] != '/')
350 return TRUE; 350 return TRUE;
351 cp = path; 351 cp = path;
352 while ((cp = strstr(cp, "/.")) != NULL) { 352 while ((cp = strstr(cp, "/.")) != NULL) {
353 cp += 2; 353 cp += 2;
354 if (cp[0] == '/' || cp[0] == '\0') 354 if (cp[0] == '/' || cp[0] == '\0')
355 return TRUE; 355 return TRUE;
356 else if (cp[0] == '.') { 356 else if (cp[0] == '.') {
357 if (cp[1] == '/' || cp[1] == '\0') 357 if (cp[1] == '/' || cp[1] == '\0')
358 return TRUE; 358 return TRUE;
359 } 359 }
360 } 360 }
361 return FALSE; 361 return FALSE;
362} 362}
363 363
364static void 364static void
365MainParseArgChdir(const char *argvalue) 365MainParseArgChdir(const char *argvalue)
366{ 366{
367 struct stat sa, sb; 367 struct stat sa, sb;
368 368
369 if (chdir(argvalue) == -1) { 369 if (chdir(argvalue) == -1) {
370 (void)fprintf(stderr, "%s: chdir %s: %s\n", 370 (void)fprintf(stderr, "%s: chdir %s: %s\n",
371 progname, argvalue, strerror(errno)); 371 progname, argvalue, strerror(errno));
372 exit(1); 372 exit(1);
373 } 373 }
374 if (getcwd(curdir, MAXPATHLEN) == NULL) { 374 if (getcwd(curdir, MAXPATHLEN) == NULL) {
375 (void)fprintf(stderr, "%s: %s.\n", progname, strerror(errno)); 375 (void)fprintf(stderr, "%s: %s.\n", progname, strerror(errno));
376 exit(2); 376 exit(2);
377 } 377 }
378 if (!is_relpath(argvalue) && 378 if (!is_relpath(argvalue) &&
379 stat(argvalue, &sa) != -1 && 379 stat(argvalue, &sa) != -1 &&
380 stat(curdir, &sb) != -1 && 380 stat(curdir, &sb) != -1 &&
381 sa.st_ino == sb.st_ino && 381 sa.st_ino == sb.st_ino &&
382 sa.st_dev == sb.st_dev) 382 sa.st_dev == sb.st_dev)
383 strncpy(curdir, argvalue, MAXPATHLEN); 383 strncpy(curdir, argvalue, MAXPATHLEN);
384 ignorePWD = TRUE; 384 ignorePWD = TRUE;
385} 385}
386 386
387static void 387static void
388MainParseArgJobsInternal(const char *argvalue) 388MainParseArgJobsInternal(const char *argvalue)
389{ 389{
390 if (sscanf(argvalue, "%d,%d", &jp_0, &jp_1) != 2) { 390 if (sscanf(argvalue, "%d,%d", &jp_0, &jp_1) != 2) {
391 (void)fprintf(stderr, 391 (void)fprintf(stderr,
392 "%s: internal error -- J option malformed (%s)\n", 392 "%s: internal error -- J option malformed (%s)\n",
393 progname, argvalue); 393 progname, argvalue);
394 usage(); 394 usage();
395 } 395 }
396 if ((fcntl(jp_0, F_GETFD, 0) < 0) || 396 if ((fcntl(jp_0, F_GETFD, 0) < 0) ||
397 (fcntl(jp_1, F_GETFD, 0) < 0)) { 397 (fcntl(jp_1, F_GETFD, 0) < 0)) {
398#if 0 398#if 0
399 (void)fprintf(stderr, 399 (void)fprintf(stderr,
400 "%s: ###### warning -- J descriptors were closed!\n", 400 "%s: ###### warning -- J descriptors were closed!\n",
401 progname); 401 progname);
402 exit(2); 402 exit(2);
403#endif 403#endif
404 jp_0 = -1; 404 jp_0 = -1;
405 jp_1 = -1; 405 jp_1 = -1;
406 opts.compatMake = TRUE; 406 opts.compatMake = TRUE;
407 } else { 407 } else {
408 Var_Append(MAKEFLAGS, "-J", VAR_GLOBAL); 408 Var_Append(MAKEFLAGS, "-J", VAR_GLOBAL);
409 Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 409 Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL);
410 } 410 }
411} 411}
412 412
413static void 413static void
414MainParseArgJobs(const char *argvalue) 414MainParseArgJobs(const char *argvalue)
415{ 415{
416 char *p; 416 char *p;
417 417
418 forceJobs = TRUE; 418 forceJobs = TRUE;
419 opts.maxJobs = (int)strtol(argvalue, &p, 0); 419 opts.maxJobs = (int)strtol(argvalue, &p, 0);
420 if (*p != '\0' || opts.maxJobs < 1) { 420 if (*p != '\0' || opts.maxJobs < 1) {
421 (void)fprintf(stderr, 421 (void)fprintf(stderr,
422 "%s: illegal argument to -j -- must be positive integer!\n", 422 "%s: illegal argument to -j -- must be positive integer!\n",
423 progname); 423 progname);
424 exit(1); /* XXX: why not 2? */ 424 exit(1); /* XXX: why not 2? */
425 } 425 }
426 Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL); 426 Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL);
427 Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 427 Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL);
428 Var_Set(".MAKE.JOBS", argvalue, VAR_GLOBAL); 428 Var_Set(".MAKE.JOBS", argvalue, VAR_GLOBAL);
429 maxJobTokens = opts.maxJobs; 429 maxJobTokens = opts.maxJobs;
430} 430}
431 431
432static void 432static void
433MainParseArgSysInc(const char *argvalue) 433MainParseArgSysInc(const char *argvalue)
434{ 434{
435 /* look for magic parent directory search string */ 435 /* look for magic parent directory search string */
436 if (strncmp(".../", argvalue, 4) == 0) { 436 if (strncmp(".../", argvalue, 4) == 0) {
437 char *found_path = Dir_FindHereOrAbove(curdir, argvalue + 4); 437 char *found_path = Dir_FindHereOrAbove(curdir, argvalue + 4);
438 if (found_path == NULL) 438 if (found_path == NULL)
439 return; 439 return;
440 (void)Dir_AddDir(sysIncPath, found_path); 440 (void)Dir_AddDir(sysIncPath, found_path);
441 free(found_path); 441 free(found_path);
442 } else { 442 } else {
443 (void)Dir_AddDir(sysIncPath, argvalue); 443 (void)Dir_AddDir(sysIncPath, argvalue);
444 } 444 }
445 Var_Append(MAKEFLAGS, "-m", VAR_GLOBAL); 445 Var_Append(MAKEFLAGS, "-m", VAR_GLOBAL);
446 Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 446 Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL);
447} 447}
448 448
449static Boolean 449static Boolean
450MainParseArg(char c, const char *argvalue) 450MainParseArg(char c, const char *argvalue)
451{ 451{
452 switch (c) { 452 switch (c) {
453 case '\0': 453 case '\0':
454 break; 454 break;
455 case 'B': 455 case 'B':
456 opts.compatMake = TRUE; 456 opts.compatMake = TRUE;
457 Var_Append(MAKEFLAGS, "-B", VAR_GLOBAL); 457 Var_Append(MAKEFLAGS, "-B", VAR_GLOBAL);
458 Var_Set(MAKE_MODE, "compat", VAR_GLOBAL); 458 Var_Set(MAKE_MODE, "compat", VAR_GLOBAL);
459 break; 459 break;
460 case 'C': 460 case 'C':
461 MainParseArgChdir(argvalue); 461 MainParseArgChdir(argvalue);
462 break; 462 break;
463 case 'D': 463 case 'D':
464 if (argvalue[0] == '\0') return FALSE; 464 if (argvalue[0] == '\0') return FALSE;
465 Var_Set(argvalue, "1", VAR_GLOBAL); 465 Var_Set(argvalue, "1", VAR_GLOBAL);
466 Var_Append(MAKEFLAGS, "-D", VAR_GLOBAL); 466 Var_Append(MAKEFLAGS, "-D", VAR_GLOBAL);
467 Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 467 Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL);
468 break; 468 break;
469 case 'I': 469 case 'I':
470 Parse_AddIncludeDir(argvalue); 470 Parse_AddIncludeDir(argvalue);
471 Var_Append(MAKEFLAGS, "-I", VAR_GLOBAL); 471 Var_Append(MAKEFLAGS, "-I", VAR_GLOBAL);
472 Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 472 Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL);
473 break; 473 break;
474 case 'J': 474 case 'J':
475 MainParseArgJobsInternal(argvalue); 475 MainParseArgJobsInternal(argvalue);
476 break; 476 break;
477 case 'N': 477 case 'N':
478 opts.noExecute = TRUE; 478 opts.noExecute = TRUE;
479 opts.noRecursiveExecute = TRUE; 479 opts.noRecursiveExecute = TRUE;
480 Var_Append(MAKEFLAGS, "-N", VAR_GLOBAL); 480 Var_Append(MAKEFLAGS, "-N", VAR_GLOBAL);
481 break; 481 break;
482 case 'S': 482 case 'S':
483 opts.keepgoing = FALSE; 483 opts.keepgoing = FALSE;
484 Var_Append(MAKEFLAGS, "-S", VAR_GLOBAL); 484 Var_Append(MAKEFLAGS, "-S", VAR_GLOBAL);
485 break; 485 break;
486 case 'T': 486 case 'T':
487 tracefile = bmake_strdup(argvalue); 487 tracefile = bmake_strdup(argvalue);
488 Var_Append(MAKEFLAGS, "-T", VAR_GLOBAL); 488 Var_Append(MAKEFLAGS, "-T", VAR_GLOBAL);
489 Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 489 Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL);
490 break; 490 break;
491 case 'V': 491 case 'V':
492 case 'v': 492 case 'v':
493 opts.printVars = c == 'v' ? EXPAND_VARS : COMPAT_VARS; 493 opts.printVars = c == 'v' ? EXPAND_VARS : COMPAT_VARS;
494 Lst_Append(opts.variables, bmake_strdup(argvalue)); 494 Lst_Append(opts.variables, bmake_strdup(argvalue));
495 /* XXX: Why always -V? */ 495 /* XXX: Why always -V? */
496 Var_Append(MAKEFLAGS, "-V", VAR_GLOBAL); 496 Var_Append(MAKEFLAGS, "-V", VAR_GLOBAL);
497 Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 497 Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL);
498 break; 498 break;
499 case 'W': 499 case 'W':
500 opts.parseWarnFatal = TRUE; 500 opts.parseWarnFatal = TRUE;
501 break; 501 break;
502 case 'X': 502 case 'X':
503 opts.varNoExportEnv = TRUE; 503 opts.varNoExportEnv = TRUE;
504 Var_Append(MAKEFLAGS, "-X", VAR_GLOBAL); 504 Var_Append(MAKEFLAGS, "-X", VAR_GLOBAL);
505 break; 505 break;
506 case 'd': 506 case 'd':
507 /* If '-d-opts' don't pass to children */ 507 /* If '-d-opts' don't pass to children */
508 if (argvalue[0] == '-') 508 if (argvalue[0] == '-')
509 argvalue++; 509 argvalue++;
510 else { 510 else {
511 Var_Append(MAKEFLAGS, "-d", VAR_GLOBAL); 511 Var_Append(MAKEFLAGS, "-d", VAR_GLOBAL);
512 Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 512 Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL);
513 } 513 }
514 parse_debug_options(argvalue); 514 parse_debug_options(argvalue);
515 break; 515 break;
516 case 'e': 516 case 'e':
517 opts.checkEnvFirst = TRUE; 517 opts.checkEnvFirst = TRUE;
518 Var_Append(MAKEFLAGS, "-e", VAR_GLOBAL); 518 Var_Append(MAKEFLAGS, "-e", VAR_GLOBAL);
519 break; 519 break;
520 case 'f': 520 case 'f':
521 Lst_Append(opts.makefiles, bmake_strdup(argvalue)); 521 Lst_Append(opts.makefiles, bmake_strdup(argvalue));
522 break; 522 break;
523 case 'i': 523 case 'i':
524 opts.ignoreErrors = TRUE; 524 opts.ignoreErrors = TRUE;
525 Var_Append(MAKEFLAGS, "-i", VAR_GLOBAL); 525 Var_Append(MAKEFLAGS, "-i", VAR_GLOBAL);
526 break; 526 break;
527 case 'j': 527 case 'j':
528 MainParseArgJobs(argvalue); 528 MainParseArgJobs(argvalue);
529 break; 529 break;
530 case 'k': 530 case 'k':
531 opts.keepgoing = TRUE; 531 opts.keepgoing = TRUE;
532 Var_Append(MAKEFLAGS, "-k", VAR_GLOBAL); 532 Var_Append(MAKEFLAGS, "-k", VAR_GLOBAL);
533 break; 533 break;
534 case 'm': 534 case 'm':
535 MainParseArgSysInc(argvalue); 535 MainParseArgSysInc(argvalue);
536 break; 536 break;
537 case 'n': 537 case 'n':
538 opts.noExecute = TRUE; 538 opts.noExecute = TRUE;
539 Var_Append(MAKEFLAGS, "-n", VAR_GLOBAL); 539 Var_Append(MAKEFLAGS, "-n", VAR_GLOBAL);
540 break; 540 break;
541 case 'q': 541 case 'q':
542 opts.queryFlag = TRUE; 542 opts.queryFlag = TRUE;
543 /* Kind of nonsensical, wot? */ 543 /* Kind of nonsensical, wot? */
544 Var_Append(MAKEFLAGS, "-q", VAR_GLOBAL); 544 Var_Append(MAKEFLAGS, "-q", VAR_GLOBAL);
545 break; 545 break;
546 case 'r': 546 case 'r':
547 opts.noBuiltins = TRUE; 547 opts.noBuiltins = TRUE;
548 Var_Append(MAKEFLAGS, "-r", VAR_GLOBAL); 548 Var_Append(MAKEFLAGS, "-r", VAR_GLOBAL);
549 break; 549 break;
550 case 's': 550 case 's':
551 opts.beSilent = TRUE; 551 opts.beSilent = TRUE;
552 Var_Append(MAKEFLAGS, "-s", VAR_GLOBAL); 552 Var_Append(MAKEFLAGS, "-s", VAR_GLOBAL);
553 break; 553 break;
554 case 't': 554 case 't':
555 opts.touchFlag = TRUE; 555 opts.touchFlag = TRUE;
556 Var_Append(MAKEFLAGS, "-t", VAR_GLOBAL); 556 Var_Append(MAKEFLAGS, "-t", VAR_GLOBAL);
557 break; 557 break;
558 case 'w': 558 case 'w':
559 opts.enterFlag = TRUE; 559 opts.enterFlag = TRUE;
560 Var_Append(MAKEFLAGS, "-w", VAR_GLOBAL); 560 Var_Append(MAKEFLAGS, "-w", VAR_GLOBAL);
561 break; 561 break;
562 default: 562 default:
563 case '?': 563 case '?':
564 usage(); 564 usage();
565 } 565 }
566 return TRUE; 566 return TRUE;
567} 567}
568 568
569/* Parse the given arguments. Called from main() and from 569/* Parse the given arguments. Called from main() and from
570 * Main_ParseArgLine() when the .MAKEFLAGS target is used. 570 * Main_ParseArgLine() when the .MAKEFLAGS target is used.
571 * 571 *
572 * The arguments must be treated as read-only and will be freed after the 572 * The arguments must be treated as read-only and will be freed after the
573 * call. 573 * call.
574 * 574 *
575 * XXX: Deal with command line overriding .MAKEFLAGS in makefile */ 575 * XXX: Deal with command line overriding .MAKEFLAGS in makefile */
576static void 576static void
577MainParseArgs(int argc, char **argv) 577MainParseArgs(int argc, char **argv)
578{ 578{
579 char c; 579 char c;
580 int arginc; 580 int arginc;
581 char *argvalue; 581 char *argvalue;
582 char *optscan; 582 char *optscan;
583 Boolean inOption, dashDash = FALSE; 583 Boolean inOption, dashDash = FALSE;
584 584
585 const char *optspecs = "BC:D:I:J:NST:V:WXd:ef:ij:km:nqrstv:w"; 585 const char *optspecs = "BC:D:I:J:NST:V:WXd:ef:ij:km:nqrstv:w";
586/* Can't actually use getopt(3) because rescanning is not portable */ 586/* Can't actually use getopt(3) because rescanning is not portable */
587 587
588rearg: 588rearg:
589 inOption = FALSE; 589 inOption = FALSE;
590 optscan = NULL; 590 optscan = NULL;
591 while (argc > 1) { 591 while (argc > 1) {
592 const char *optspec; 592 const char *optspec;
593 if (!inOption) 593 if (!inOption)
594 optscan = argv[1]; 594 optscan = argv[1];
595 c = *optscan++; 595 c = *optscan++;
596 arginc = 0; 596 arginc = 0;
597 if (inOption) { 597 if (inOption) {
598 if (c == '\0') { 598 if (c == '\0') {
599 ++argv; 599 ++argv;
600 --argc; 600 --argc;
601 inOption = FALSE; 601 inOption = FALSE;
602 continue; 602 continue;
603 } 603 }
604 } else { 604 } else {
605 if (c != '-' || dashDash) 605 if (c != '-' || dashDash)
606 break; 606 break;
607 inOption = TRUE; 607 inOption = TRUE;
608 c = *optscan++; 608 c = *optscan++;
609 } 609 }
610 /* '-' found at some earlier point */ 610 /* '-' found at some earlier point */
611 optspec = strchr(optspecs, c); 611 optspec = strchr(optspecs, c);
612 if (c != '\0' && optspec != NULL && optspec[1] == ':') { 612 if (c != '\0' && optspec != NULL && optspec[1] == ':') {
613 /* -<something> found, and <something> should have an arg */ 613 /* -<something> found, and <something> should have an arg */
614 inOption = FALSE; 614 inOption = FALSE;
615 arginc = 1; 615 arginc = 1;
616 argvalue = optscan; 616 argvalue = optscan;
617 if (*argvalue == '\0') { 617 if (*argvalue == '\0') {
618 if (argc < 3) 618 if (argc < 3)
619 goto noarg; 619 goto noarg;
620 argvalue = argv[2]; 620 argvalue = argv[2];
621 arginc = 2; 621 arginc = 2;
622 } 622 }
623 } else { 623 } else {
624 argvalue = NULL; 624 argvalue = NULL;
625 } 625 }
626 switch (c) { 626 switch (c) {
627 case '\0': 627 case '\0':
628 arginc = 1; 628 arginc = 1;
629 inOption = FALSE; 629 inOption = FALSE;
630 break; 630 break;
631 case '-': 631 case '-':
632 dashDash = TRUE; 632 dashDash = TRUE;
633 break; 633 break;
634 default: 634 default:
635 if (!MainParseArg(c, argvalue)) 635 if (!MainParseArg(c, argvalue))
636 goto noarg; 636 goto noarg;
637 } 637 }
638 argv += arginc; 638 argv += arginc;
639 argc -= arginc; 639 argc -= arginc;
640 } 640 }
641 641
642 oldVars = TRUE; 642 oldVars = TRUE;
643 643
644 /* 644 /*
645 * See if the rest of the arguments are variable assignments and 645 * See if the rest of the arguments are variable assignments and
646 * perform them if so. Else take them to be targets and stuff them 646 * perform them if so. Else take them to be targets and stuff them
647 * on the end of the "create" list. 647 * on the end of the "create" list.
648 */ 648 */
649 for (; argc > 1; ++argv, --argc) { 649 for (; argc > 1; ++argv, --argc) {
650 VarAssign var; 650 VarAssign var;
651 if (Parse_IsVar(argv[1], &var)) { 651 if (Parse_IsVar(argv[1], &var)) {
652 Parse_DoVar(&var, VAR_CMDLINE); 652 Parse_DoVar(&var, VAR_CMDLINE);
653 } else { 653 } else {
654 if (!*argv[1]) 654 if (!*argv[1])
655 Punt("illegal (null) argument."); 655 Punt("illegal (null) argument.");
656 if (*argv[1] == '-' && !dashDash) 656 if (*argv[1] == '-' && !dashDash)
657 goto rearg; 657 goto rearg;
658 Lst_Append(opts.create, bmake_strdup(argv[1])); 658 Lst_Append(opts.create, bmake_strdup(argv[1]));
659 } 659 }
660 } 660 }
661 661
662 return; 662 return;
663noarg: 663noarg:
664 (void)fprintf(stderr, "%s: option requires an argument -- %c\n", 664 (void)fprintf(stderr, "%s: option requires an argument -- %c\n",
665 progname, c); 665 progname, c);
666 usage(); 666 usage();
667} 667}
668 668
669/* Break a line of arguments into words and parse them. 669/* Break a line of arguments into words and parse them.
670 * 670 *
671 * Used when a .MFLAGS or .MAKEFLAGS target is encountered during parsing and 671 * Used when a .MFLAGS or .MAKEFLAGS target is encountered during parsing and
672 * by main() when reading the MAKEFLAGS environment variable. */ 672 * by main() when reading the MAKEFLAGS environment variable. */
673void 673void
674Main_ParseArgLine(const char *line) 674Main_ParseArgLine(const char *line)
675{ 675{
676 Words words; 676 Words words;
677 void *p1; 677 void *p1;
678 const char *argv0 = Var_Value(".MAKE", VAR_GLOBAL, &p1); 678 const char *argv0 = Var_Value(".MAKE", VAR_GLOBAL, &p1);
679 char *buf; 679 char *buf;
680 680
681 if (line == NULL) 681 if (line == NULL)
682 return; 682 return;
683 for (; *line == ' '; ++line) 683 for (; *line == ' '; ++line)
684 continue; 684 continue;
685 if (!*line) 685 if (!*line)
686 return; 686 return;
687 687
688 buf = str_concat3(argv0, " ", line); 688 buf = str_concat3(argv0, " ", line);
689 free(p1); 689 free(p1);
690 690
691 words = Str_Words(buf, TRUE); 691 words = Str_Words(buf, TRUE);
692 if (words.words == NULL) { 692 if (words.words == NULL) {
693 Error("Unterminated quoted string [%s]", buf); 693 Error("Unterminated quoted string [%s]", buf);
694 free(buf); 694 free(buf);
695 return; 695 return;
696 } 696 }
697 free(buf); 697 free(buf);
698 MainParseArgs((int)words.len, words.words); 698 MainParseArgs((int)words.len, words.words);
699 699
700 Words_Free(words); 700 Words_Free(words);
701} 701}
702 702
703Boolean 703Boolean
704Main_SetObjdir(const char *fmt, ...) 704Main_SetObjdir(const char *fmt, ...)
705{ 705{
706 struct stat sb; 706 struct stat sb;
707 char *path; 707 char *path;
708 char buf[MAXPATHLEN + 1]; 708 char buf[MAXPATHLEN + 1];
709 char buf2[MAXPATHLEN + 1]; 709 char buf2[MAXPATHLEN + 1];
710 Boolean rc = FALSE; 710 Boolean rc = FALSE;
711 va_list ap; 711 va_list ap;
712 712
713 va_start(ap, fmt); 713 va_start(ap, fmt);
714 vsnprintf(path = buf, MAXPATHLEN, fmt, ap); 714 vsnprintf(path = buf, MAXPATHLEN, fmt, ap);
715 va_end(ap); 715 va_end(ap);
716 716
717 if (path[0] != '/') { 717 if (path[0] != '/') {
718 snprintf(buf2, MAXPATHLEN, "%s/%s", curdir, path); 718 snprintf(buf2, MAXPATHLEN, "%s/%s", curdir, path);
719 path = buf2; 719 path = buf2;
720 } 720 }
721 721
722 /* look for the directory and try to chdir there */ 722 /* look for the directory and try to chdir there */
723 if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) { 723 if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) {
724 if (access(path, W_OK) || chdir(path)) { 724 if (chdir(path)) {
725 (void)fprintf(stderr, "make warning: %s: %s.\n", 725 (void)fprintf(stderr, "make warning: %s: %s.\n",
726 path, strerror(errno)); 726 path, strerror(errno));
727 } else { 727 } else {
728 snprintf(objdir, sizeof objdir, "%s", path); 728 snprintf(objdir, sizeof objdir, "%s", path);
729 Var_Set(".OBJDIR", objdir, VAR_GLOBAL); 729 Var_Set(".OBJDIR", objdir, VAR_GLOBAL);
730 setenv("PWD", objdir, 1); 730 setenv("PWD", objdir, 1);
731 Dir_InitDot(); 731 Dir_InitDot();
732 purge_cached_realpaths(); 732 purge_cached_realpaths();
733 rc = TRUE; 733 rc = TRUE;
734 if (opts.enterFlag && strcmp(objdir, curdir) != 0) 734 if (opts.enterFlag && strcmp(objdir, curdir) != 0)
735 enterFlagObj = TRUE; 735 enterFlagObj = TRUE;
736 } 736 }
737 } 737 }
738 738
739 return rc; 739 return rc;
740} 740}
741 741
742static Boolean 742static Boolean
743Main_SetVarObjdir(const char *var, const char *suffix) 743Main_SetVarObjdir(const char *var, const char *suffix)
744{ 744{
745 void *path_freeIt; 745 void *path_freeIt;
746 const char *path = Var_Value(var, VAR_CMDLINE, &path_freeIt); 746 const char *path = Var_Value(var, VAR_CMDLINE, &path_freeIt);
747 const char *xpath; 747 const char *xpath;
748 char *xpath_freeIt; 748 char *xpath_freeIt;
749 749
750 if (path == NULL || path[0] == '\0') { 750 if (path == NULL || path[0] == '\0') {
751 bmake_free(path_freeIt); 751 bmake_free(path_freeIt);
752 return FALSE; 752 return FALSE;
753 } 753 }
754 754
755 /* expand variable substitutions */ 755 /* expand variable substitutions */
756 xpath = path; 756 xpath = path;
757 xpath_freeIt = NULL; 757 xpath_freeIt = NULL;
758 if (strchr(path, '$') != 0) { 758 if (strchr(path, '$') != 0) {
759 (void)Var_Subst(path, VAR_GLOBAL, VARE_WANTRES, &xpath_freeIt); 759 (void)Var_Subst(path, VAR_GLOBAL, VARE_WANTRES, &xpath_freeIt);
760 /* TODO: handle errors */ 760 /* TODO: handle errors */
761 xpath = xpath_freeIt; 761 xpath = xpath_freeIt;
762 } 762 }
763 763
764 (void)Main_SetObjdir("%s%s", xpath, suffix); 764 (void)Main_SetObjdir("%s%s", xpath, suffix);
765 765
766 bmake_free(xpath_freeIt); 766 bmake_free(xpath_freeIt);
767 bmake_free(path_freeIt); 767 bmake_free(path_freeIt);
768 return TRUE; 768 return TRUE;
769} 769}
770 770
771/* Read and parse the makefile. 771/* Read and parse the makefile.
772 * Return TRUE if reading the makefile succeeded. */ 772 * Return TRUE if reading the makefile succeeded. */
773static int 773static int
774ReadMakefileSucceeded(void *fname, void *unused) 774ReadMakefileSucceeded(void *fname, void *unused)
775{ 775{
776 return ReadMakefile(fname) == 0; 776 return ReadMakefile(fname) == 0;
777} 777}
778 778
779int 779int
780str2Lst_Append(StringList *lp, char *str, const char *sep) 780str2Lst_Append(StringList *lp, char *str, const char *sep)
781{ 781{
782 char *cp; 782 char *cp;
783 int n; 783 int n;
784 784
785 if (!sep) 785 if (!sep)
786 sep = " \t"; 786 sep = " \t";
787 787
788 for (n = 0, cp = strtok(str, sep); cp; cp = strtok(NULL, sep)) { 788 for (n = 0, cp = strtok(str, sep); cp; cp = strtok(NULL, sep)) {
789 Lst_Append(lp, cp); 789 Lst_Append(lp, cp);
790 n++; 790 n++;
791 } 791 }
792 return n; 792 return n;
793} 793}
794 794
795#ifdef SIGINFO 795#ifdef SIGINFO
796/*ARGSUSED*/ 796/*ARGSUSED*/
797static void 797static void
798siginfo(int signo MAKE_ATTR_UNUSED) 798siginfo(int signo MAKE_ATTR_UNUSED)
799{ 799{
800 char dir[MAXPATHLEN]; 800 char dir[MAXPATHLEN];
801 char str[2 * MAXPATHLEN]; 801 char str[2 * MAXPATHLEN];
802 int len; 802 int len;
803 if (getcwd(dir, sizeof(dir)) == NULL) 803 if (getcwd(dir, sizeof(dir)) == NULL)
804 return; 804 return;
805 len = snprintf(str, sizeof(str), "%s: Working in: %s\n", progname, dir); 805 len = snprintf(str, sizeof(str), "%s: Working in: %s\n", progname, dir);
806 if (len > 0) 806 if (len > 0)
807 (void)write(STDERR_FILENO, str, (size_t)len); 807 (void)write(STDERR_FILENO, str, (size_t)len);
808} 808}
809#endif 809#endif
810 810
811/* 811/*
812 * Allow makefiles some control over the mode we run in. 812 * Allow makefiles some control over the mode we run in.
813 */ 813 */
814void 814void
815MakeMode(const char *mode) 815MakeMode(const char *mode)
816{ 816{
817 char *mode_freeIt = NULL; 817 char *mode_freeIt = NULL;
818 818
819 if (mode == NULL) { 819 if (mode == NULL) {
820 (void)Var_Subst("${" MAKE_MODE ":tl}", 820 (void)Var_Subst("${" MAKE_MODE ":tl}",
821 VAR_GLOBAL, VARE_WANTRES, &mode_freeIt); 821 VAR_GLOBAL, VARE_WANTRES, &mode_freeIt);
822 /* TODO: handle errors */ 822 /* TODO: handle errors */
823 mode = mode_freeIt; 823 mode = mode_freeIt;
824 } 824 }
825 825
826 if (mode[0] != '\0') { 826 if (mode[0] != '\0') {
827 if (strstr(mode, "compat")) { 827 if (strstr(mode, "compat")) {
828 opts.compatMake = TRUE; 828 opts.compatMake = TRUE;
829 forceJobs = FALSE; 829 forceJobs = FALSE;
830 } 830 }
831#if USE_META 831#if USE_META
832 if (strstr(mode, "meta")) 832 if (strstr(mode, "meta"))
833 meta_mode_init(mode); 833 meta_mode_init(mode);
834#endif 834#endif
835 } 835 }
836 836
837 free(mode_freeIt); 837 free(mode_freeIt);
838} 838}
839 839
840static void 840static void
841PrintVar(const char *varname, Boolean expandVars) 841PrintVar(const char *varname, Boolean expandVars)
842{ 842{
843 if (strchr(varname, '$')) { 843 if (strchr(varname, '$')) {
844 char *evalue; 844 char *evalue;
845 (void)Var_Subst(varname, VAR_GLOBAL, VARE_WANTRES, &evalue); 845 (void)Var_Subst(varname, VAR_GLOBAL, VARE_WANTRES, &evalue);
846 /* TODO: handle errors */ 846 /* TODO: handle errors */
847 printf("%s\n", evalue); 847 printf("%s\n", evalue);
848 bmake_free(evalue); 848 bmake_free(evalue);
849 849
850 } else if (expandVars) { 850 } else if (expandVars) {
851 char *expr = str_concat3("${", varname, "}"); 851 char *expr = str_concat3("${", varname, "}");
852 char *evalue; 852 char *evalue;
853 (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &evalue); 853 (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &evalue);
854 /* TODO: handle errors */ 854 /* TODO: handle errors */
855 free(expr); 855 free(expr);
856 printf("%s\n", evalue); 856 printf("%s\n", evalue);
857 bmake_free(evalue); 857 bmake_free(evalue);
858 858
859 } else { 859 } else {
860 void *freeIt; 860 void *freeIt;
861 const char *value = Var_Value(varname, VAR_GLOBAL, &freeIt); 861 const char *value = Var_Value(varname, VAR_GLOBAL, &freeIt);
862 printf("%s\n", value ? value : ""); 862 printf("%s\n", value ? value : "");
863 bmake_free(freeIt); 863 bmake_free(freeIt);
864 } 864 }
865} 865}
866 866
867static void 867static void
868doPrintVars(void) 868doPrintVars(void)
869{ 869{
870 StringListNode *ln; 870 StringListNode *ln;
871 Boolean expandVars; 871 Boolean expandVars;
872 872
873 if (opts.printVars == EXPAND_VARS) 873 if (opts.printVars == EXPAND_VARS)
874 expandVars = TRUE; 874 expandVars = TRUE;
875 else if (opts.debugVflag) 875 else if (opts.debugVflag)
876 expandVars = FALSE; 876 expandVars = FALSE;
877 else 877 else
878 expandVars = getBoolean(".MAKE.EXPAND_VARIABLES", FALSE); 878 expandVars = getBoolean(".MAKE.EXPAND_VARIABLES", FALSE);
879 879
880 for (ln = opts.variables->first; ln != NULL; ln = ln->next) { 880 for (ln = opts.variables->first; ln != NULL; ln = ln->next) {
881 const char *varname = ln->datum; 881 const char *varname = ln->datum;
882 PrintVar(varname, expandVars); 882 PrintVar(varname, expandVars);
883 } 883 }
884} 884}
885 885
886static Boolean 886static Boolean
887runTargets(void) 887runTargets(void)
888{ 888{
889 GNodeList *targs; /* target nodes to create -- passed to Make_Init */ 889 GNodeList *targs; /* target nodes to create -- passed to Make_Init */
890 Boolean outOfDate; /* FALSE if all targets up to date */ 890 Boolean outOfDate; /* FALSE if all targets up to date */
891 891
892 /* 892 /*
893 * Have now read the entire graph and need to make a list of 893 * Have now read the entire graph and need to make a list of
894 * targets to create. If none was given on the command line, 894 * targets to create. If none was given on the command line,
895 * we consult the parsing module to find the main target(s) 895 * we consult the parsing module to find the main target(s)
896 * to create. 896 * to create.
897 */ 897 */
898 if (Lst_IsEmpty(opts.create)) 898 if (Lst_IsEmpty(opts.create))
899 targs = Parse_MainName(); 899 targs = Parse_MainName();
900 else 900 else
901 targs = Targ_FindList(opts.create); 901 targs = Targ_FindList(opts.create);
902 902
903 if (!opts.compatMake) { 903 if (!opts.compatMake) {
904 /* 904 /*
905 * Initialize job module before traversing the graph 905 * Initialize job module before traversing the graph
906 * now that any .BEGIN and .END targets have been read. 906 * now that any .BEGIN and .END targets have been read.
907 * This is done only if the -q flag wasn't given 907 * This is done only if the -q flag wasn't given
908 * (to prevent the .BEGIN from being executed should 908 * (to prevent the .BEGIN from being executed should
909 * it exist). 909 * it exist).
910 */ 910 */
911 if (!opts.queryFlag) { 911 if (!opts.queryFlag) {
912 Job_Init(); 912 Job_Init();
913 jobsRunning = TRUE; 913 jobsRunning = TRUE;
914 } 914 }
915 915
916 /* Traverse the graph, checking on all the targets */ 916 /* Traverse the graph, checking on all the targets */
917 outOfDate = Make_Run(targs); 917 outOfDate = Make_Run(targs);
918 } else { 918 } else {
919 /* 919 /*
920 * Compat_Init will take care of creating all the 920 * Compat_Init will take care of creating all the
921 * targets as well as initializing the module. 921 * targets as well as initializing the module.
922 */ 922 */
923 Compat_Run(targs); 923 Compat_Run(targs);
924 outOfDate = FALSE; 924 outOfDate = FALSE;
925 } 925 }
926 Lst_Free(targs); 926 Lst_Free(targs);
927 return outOfDate; 927 return outOfDate;
928} 928}
929 929
930/* 930/*
931 * Set up the .TARGETS variable to contain the list of targets to be 931 * Set up the .TARGETS variable to contain the list of targets to be
932 * created. If none specified, make the variable empty -- the parser 932 * created. If none specified, make the variable empty -- the parser
933 * will fill the thing in with the default or .MAIN target. 933 * will fill the thing in with the default or .MAIN target.
934 */ 934 */
935static void 935static void
936InitVarTargets(void) 936InitVarTargets(void)
937{ 937{
938 StringListNode *ln; 938 StringListNode *ln;
939 939
940 if (Lst_IsEmpty(opts.create)) { 940 if (Lst_IsEmpty(opts.create)) {
941 Var_Set(".TARGETS", "", VAR_GLOBAL); 941 Var_Set(".TARGETS", "", VAR_GLOBAL);
942 return; 942 return;
943 } 943 }
944 944
945 for (ln = opts.create->first; ln != NULL; ln = ln->next) { 945 for (ln = opts.create->first; ln != NULL; ln = ln->next) {
946 char *name = ln->datum; 946 char *name = ln->datum;
947 Var_Append(".TARGETS", name, VAR_GLOBAL); 947 Var_Append(".TARGETS", name, VAR_GLOBAL);
948 } 948 }
949} 949}
950 950
951static void 951static void
952InitRandom(void) 952InitRandom(void)
953{ 953{
954 struct timeval tv; 954 struct timeval tv;
955 955
956 gettimeofday(&tv, NULL); 956 gettimeofday(&tv, NULL);
957 srandom((unsigned int)(tv.tv_sec + tv.tv_usec)); 957 srandom((unsigned int)(tv.tv_sec + tv.tv_usec));
958} 958}
959 959
960static const char * 960static const char *
961init_machine(const struct utsname *utsname) 961init_machine(const struct utsname *utsname)
962{ 962{
963 const char *machine = getenv("MACHINE"); 963 const char *machine = getenv("MACHINE");
964 if (machine != NULL) 964 if (machine != NULL)
965 return machine; 965 return machine;
966 966
967#ifdef MAKE_NATIVE 967#ifdef MAKE_NATIVE
968 return utsname->machine; 968 return utsname->machine;
969#else 969#else
970#ifdef MAKE_MACHINE 970#ifdef MAKE_MACHINE
971 return MAKE_MACHINE; 971 return MAKE_MACHINE;
972#else 972#else
973 return "unknown"; 973 return "unknown";
974#endif 974#endif
975#endif 975#endif
976} 976}
977 977
978static const char * 978static const char *
979init_machine_arch(void) 979init_machine_arch(void)
980{ 980{
981 const char *env = getenv("MACHINE_ARCH"); 981 const char *env = getenv("MACHINE_ARCH");
982 if (env != NULL) 982 if (env != NULL)
983 return env; 983 return env;
984 984
985#ifdef MAKE_NATIVE 985#ifdef MAKE_NATIVE
986 { 986 {
987 struct utsname utsname; 987 struct utsname utsname;
988 static char machine_arch_buf[sizeof(utsname.machine)]; 988 static char machine_arch_buf[sizeof(utsname.machine)];
989 const int mib[2] = { CTL_HW, HW_MACHINE_ARCH }; 989 const int mib[2] = { CTL_HW, HW_MACHINE_ARCH };
990 size_t len = sizeof(machine_arch_buf); 990 size_t len = sizeof(machine_arch_buf);
991 991
992 if (sysctl(mib, __arraycount(mib), machine_arch_buf, 992 if (sysctl(mib, __arraycount(mib), machine_arch_buf,
993 &len, NULL, 0) < 0) { 993 &len, NULL, 0) < 0) {
994 (void)fprintf(stderr, "%s: sysctl failed (%s).\n", progname, 994 (void)fprintf(stderr, "%s: sysctl failed (%s).\n", progname,
995 strerror(errno)); 995 strerror(errno));
996 exit(2); 996 exit(2);
997 } 997 }
998 998
999 return machine_arch_buf; 999 return machine_arch_buf;
1000 } 1000 }
1001#else 1001#else
1002#ifndef MACHINE_ARCH 1002#ifndef MACHINE_ARCH
1003#ifdef MAKE_MACHINE_ARCH 1003#ifdef MAKE_MACHINE_ARCH
1004 return MAKE_MACHINE_ARCH; 1004 return MAKE_MACHINE_ARCH;
1005#else 1005#else
1006 return "unknown"; 1006 return "unknown";
1007#endif 1007#endif
1008#else 1008#else
1009 return MACHINE_ARCH; 1009 return MACHINE_ARCH;
1010#endif 1010#endif
1011#endif 1011#endif
1012} 1012}
1013 1013
1014#ifndef NO_PWD_OVERRIDE 1014#ifndef NO_PWD_OVERRIDE
1015/* 1015/*
1016 * All this code is so that we know where we are when we start up 1016 * All this code is so that we know where we are when we start up
1017 * on a different machine with pmake. 1017 * on a different machine with pmake.
1018 * 1018 *
1019 * Overriding getcwd() with $PWD totally breaks MAKEOBJDIRPREFIX 1019 * Overriding getcwd() with $PWD totally breaks MAKEOBJDIRPREFIX
1020 * since the value of curdir can vary depending on how we got 1020 * since the value of curdir can vary depending on how we got
1021 * here. Ie sitting at a shell prompt (shell that provides $PWD) 1021 * here. Ie sitting at a shell prompt (shell that provides $PWD)
1022 * or via subdir.mk in which case its likely a shell which does 1022 * or via subdir.mk in which case its likely a shell which does
1023 * not provide it. 1023 * not provide it.
1024 * 1024 *
1025 * So, to stop it breaking this case only, we ignore PWD if 1025 * So, to stop it breaking this case only, we ignore PWD if
1026 * MAKEOBJDIRPREFIX is set or MAKEOBJDIR contains a variable expression. 1026 * MAKEOBJDIRPREFIX is set or MAKEOBJDIR contains a variable expression.
1027 */ 1027 */
1028static void 1028static void
1029HandlePWD(const struct stat *curdir_st) 1029HandlePWD(const struct stat *curdir_st)
1030{ 1030{
1031 char *pwd; 1031 char *pwd;
1032 void *prefix_freeIt, *makeobjdir_freeIt; 1032 void *prefix_freeIt, *makeobjdir_freeIt;
1033 const char *makeobjdir; 1033 const char *makeobjdir;
1034 struct stat pwd_st; 1034 struct stat pwd_st;
1035 1035
1036 if (ignorePWD || (pwd = getenv("PWD")) == NULL) 1036 if (ignorePWD || (pwd = getenv("PWD")) == NULL)
1037 return; 1037 return;
1038 1038
1039 if (Var_Value("MAKEOBJDIRPREFIX", VAR_CMDLINE, &prefix_freeIt) != NULL) { 1039 if (Var_Value("MAKEOBJDIRPREFIX", VAR_CMDLINE, &prefix_freeIt) != NULL) {
1040 bmake_free(prefix_freeIt); 1040 bmake_free(prefix_freeIt);
1041 return; 1041 return;
1042 } 1042 }
1043 1043
1044 makeobjdir = Var_Value("MAKEOBJDIR", VAR_CMDLINE, &makeobjdir_freeIt); 1044 makeobjdir = Var_Value("MAKEOBJDIR", VAR_CMDLINE, &makeobjdir_freeIt);
1045 if (makeobjdir != NULL && strchr(makeobjdir, '$') != NULL) 1045 if (makeobjdir != NULL && strchr(makeobjdir, '$') != NULL)
1046 goto ignore_pwd; 1046 goto ignore_pwd;
1047 1047
1048 if (stat(pwd, &pwd_st) == 0 && 1048 if (stat(pwd, &pwd_st) == 0 &&
1049 curdir_st->st_ino == pwd_st.st_ino && 1049 curdir_st->st_ino == pwd_st.st_ino &&
1050 curdir_st->st_dev == pwd_st.st_dev) 1050 curdir_st->st_dev == pwd_st.st_dev)
1051 (void)strncpy(curdir, pwd, MAXPATHLEN); 1051 (void)strncpy(curdir, pwd, MAXPATHLEN);
1052 1052
1053ignore_pwd: 1053ignore_pwd:
1054 bmake_free(makeobjdir_freeIt); 1054 bmake_free(makeobjdir_freeIt);
1055} 1055}
1056#endif 1056#endif
1057 1057
1058/* 1058/*
1059 * Find the .OBJDIR. If MAKEOBJDIRPREFIX, or failing that, 1059 * Find the .OBJDIR. If MAKEOBJDIRPREFIX, or failing that,
1060 * MAKEOBJDIR is set in the environment, try only that value 1060 * MAKEOBJDIR is set in the environment, try only that value
1061 * and fall back to .CURDIR if it does not exist. 1061 * and fall back to .CURDIR if it does not exist.
1062 * 1062 *
1063 * Otherwise, try _PATH_OBJDIR.MACHINE-MACHINE_ARCH, _PATH_OBJDIR.MACHINE, 1063 * Otherwise, try _PATH_OBJDIR.MACHINE-MACHINE_ARCH, _PATH_OBJDIR.MACHINE,
1064 * and * finally _PATH_OBJDIRPREFIX`pwd`, in that order. If none 1064 * and * finally _PATH_OBJDIRPREFIX`pwd`, in that order. If none
1065 * of these paths exist, just use .CURDIR. 1065 * of these paths exist, just use .CURDIR.
1066 */ 1066 */
1067static void 1067static void
1068InitObjdir(const char *machine, const char *machine_arch) 1068InitObjdir(const char *machine, const char *machine_arch)
1069{ 1069{
1070 Dir_InitDir(curdir); 1070 Dir_InitDir(curdir);
1071 (void)Main_SetObjdir("%s", curdir); 1071 (void)Main_SetObjdir("%s", curdir);
1072 1072
1073 if (!Main_SetVarObjdir("MAKEOBJDIRPREFIX", curdir) && 1073 if (!Main_SetVarObjdir("MAKEOBJDIRPREFIX", curdir) &&
1074 !Main_SetVarObjdir("MAKEOBJDIR", "") && 1074 !Main_SetVarObjdir("MAKEOBJDIR", "") &&
1075 !Main_SetObjdir("%s.%s-%s", _PATH_OBJDIR, machine, machine_arch) && 1075 !Main_SetObjdir("%s.%s-%s", _PATH_OBJDIR, machine, machine_arch) &&
1076 !Main_SetObjdir("%s.%s", _PATH_OBJDIR, machine) && 1076 !Main_SetObjdir("%s.%s", _PATH_OBJDIR, machine) &&
1077 !Main_SetObjdir("%s", _PATH_OBJDIR)) 1077 !Main_SetObjdir("%s", _PATH_OBJDIR))
1078 (void)Main_SetObjdir("%s%s", _PATH_OBJDIRPREFIX, curdir); 1078 (void)Main_SetObjdir("%s%s", _PATH_OBJDIRPREFIX, curdir);
1079} 1079}
1080 1080
1081/* get rid of resource limit on file descriptors */ 1081/* get rid of resource limit on file descriptors */
1082static void 1082static void
1083UnlimitFiles(void) 1083UnlimitFiles(void)
1084{ 1084{
1085#if defined(MAKE_NATIVE) || (defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)) 1085#if defined(MAKE_NATIVE) || (defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE))
1086 struct rlimit rl; 1086 struct rlimit rl;
1087 if (getrlimit(RLIMIT_NOFILE, &rl) != -1 && 1087 if (getrlimit(RLIMIT_NOFILE, &rl) != -1 &&
1088 rl.rlim_cur != rl.rlim_max) { 1088 rl.rlim_cur != rl.rlim_max) {
1089 rl.rlim_cur = rl.rlim_max; 1089 rl.rlim_cur = rl.rlim_max;
1090 (void)setrlimit(RLIMIT_NOFILE, &rl); 1090 (void)setrlimit(RLIMIT_NOFILE, &rl);
1091 } 1091 }
1092#endif 1092#endif
1093} 1093}
1094 1094
1095static void 1095static void
1096CmdOpts_Init(void) 1096CmdOpts_Init(void)
1097{ 1097{
1098 opts.compatMake = FALSE; /* No compat mode */ 1098 opts.compatMake = FALSE; /* No compat mode */
1099 opts.debug = 0; /* No debug verbosity, please. */ 1099 opts.debug = 0; /* No debug verbosity, please. */
1100 /* opts.debug_file has been initialized earlier */ 1100 /* opts.debug_file has been initialized earlier */
1101 opts.debugVflag = FALSE; 1101 opts.debugVflag = FALSE;
1102 opts.checkEnvFirst = FALSE; 1102 opts.checkEnvFirst = FALSE;
1103 opts.makefiles = Lst_New(); 1103 opts.makefiles = Lst_New();
1104 opts.ignoreErrors = FALSE; /* Pay attention to non-zero returns */ 1104 opts.ignoreErrors = FALSE; /* Pay attention to non-zero returns */
1105 opts.maxJobs = DEFMAXLOCAL; /* Set default local max concurrency */ 1105 opts.maxJobs = DEFMAXLOCAL; /* Set default local max concurrency */
1106 opts.keepgoing = FALSE; /* Stop on error */ 1106 opts.keepgoing = FALSE; /* Stop on error */
1107 opts.noRecursiveExecute = FALSE; /* Execute all .MAKE targets */ 1107 opts.noRecursiveExecute = FALSE; /* Execute all .MAKE targets */
1108 opts.noExecute = FALSE; /* Execute all commands */ 1108 opts.noExecute = FALSE; /* Execute all commands */
1109 opts.queryFlag = FALSE; /* This is not just a check-run */ 1109 opts.queryFlag = FALSE; /* This is not just a check-run */
1110 opts.noBuiltins = FALSE; /* Read the built-in rules */ 1110 opts.noBuiltins = FALSE; /* Read the built-in rules */
1111 opts.beSilent = FALSE; /* Print commands as executed */ 1111 opts.beSilent = FALSE; /* Print commands as executed */
1112 opts.touchFlag = FALSE; /* Actually update targets */ 1112 opts.touchFlag = FALSE; /* Actually update targets */
1113 opts.printVars = 0; 1113 opts.printVars = 0;
1114 opts.variables = Lst_New(); 1114 opts.variables = Lst_New();
1115 opts.parseWarnFatal = FALSE; 1115 opts.parseWarnFatal = FALSE;
1116 opts.enterFlag = FALSE; 1116 opts.enterFlag = FALSE;
1117 opts.varNoExportEnv = FALSE; 1117 opts.varNoExportEnv = FALSE;
1118 opts.create = Lst_New(); 1118 opts.create = Lst_New();
1119} 1119}
1120 1120
1121/* Initialize MAKE and .MAKE to the path of the executable, so that it can be 1121/* Initialize MAKE and .MAKE to the path of the executable, so that it can be
1122 * found by execvp(3) and the shells, even after a chdir. 1122 * found by execvp(3) and the shells, even after a chdir.
1123 * 1123 *
1124 * If it's a relative path and contains a '/', resolve it to an absolute path. 1124 * If it's a relative path and contains a '/', resolve it to an absolute path.
1125 * Otherwise keep it as is, assuming it will be found in the PATH. */ 1125 * Otherwise keep it as is, assuming it will be found in the PATH. */
1126static void 1126static void
1127InitVarMake(const char *argv0) 1127InitVarMake(const char *argv0)
1128{ 1128{
1129 const char *make = argv0; 1129 const char *make = argv0;
1130 1130
1131 if (argv0[0] != '/' && strchr(argv0, '/') != NULL) { 1131 if (argv0[0] != '/' && strchr(argv0, '/') != NULL) {
1132 char pathbuf[MAXPATHLEN]; 1132 char pathbuf[MAXPATHLEN];
1133 const char *abs = cached_realpath(argv0, pathbuf); 1133 const char *abs = cached_realpath(argv0, pathbuf);
1134 struct stat st; 1134 struct stat st;
1135 if (abs != NULL && abs[0] == '/' && stat(make, &st) == 0) 1135 if (abs != NULL && abs[0] == '/' && stat(make, &st) == 0)
1136 make = abs; 1136 make = abs;
1137 } 1137 }
1138 1138
1139 Var_Set("MAKE", make, VAR_GLOBAL); 1139 Var_Set("MAKE", make, VAR_GLOBAL);
1140 Var_Set(".MAKE", make, VAR_GLOBAL); 1140 Var_Set(".MAKE", make, VAR_GLOBAL);
1141} 1141}
1142 1142
1143static void 1143static void
1144InitDefSysIncPath(char *syspath) 1144InitDefSysIncPath(char *syspath)
1145{ 1145{
1146 static char defsyspath[] = _PATH_DEFSYSPATH; 1146 static char defsyspath[] = _PATH_DEFSYSPATH;
1147 char *start, *cp; 1147 char *start, *cp;
1148 1148
1149 /* 1149 /*
1150 * If no user-supplied system path was given (through the -m option) 1150 * If no user-supplied system path was given (through the -m option)
1151 * add the directories from the DEFSYSPATH (more than one may be given 1151 * add the directories from the DEFSYSPATH (more than one may be given
1152 * as dir1:...:dirn) to the system include path. 1152 * as dir1:...:dirn) to the system include path.
1153 */ 1153 */
1154 /* XXX: mismatch: the -m option sets sysIncPath, not syspath */ 1154 /* XXX: mismatch: the -m option sets sysIncPath, not syspath */
1155 if (syspath == NULL || syspath[0] == '\0') 1155 if (syspath == NULL || syspath[0] == '\0')
1156 syspath = defsyspath; 1156 syspath = defsyspath;
1157 else 1157 else
1158 syspath = bmake_strdup(syspath); 1158 syspath = bmake_strdup(syspath);
1159 1159
1160 for (start = syspath; *start != '\0'; start = cp) { 1160 for (start = syspath; *start != '\0'; start = cp) {
1161 for (cp = start; *cp != '\0' && *cp != ':'; cp++) 1161 for (cp = start; *cp != '\0' && *cp != ':'; cp++)
1162 continue; 1162 continue;
1163 if (*cp == ':') { 1163 if (*cp == ':') {
1164 *cp++ = '\0'; 1164 *cp++ = '\0';
1165 } 1165 }
1166 /* look for magic parent directory search string */ 1166 /* look for magic parent directory search string */
1167 if (strncmp(".../", start, 4) != 0) { 1167 if (strncmp(".../", start, 4) != 0) {
1168 (void)Dir_AddDir(defSysIncPath, start); 1168 (void)Dir_AddDir(defSysIncPath, start);
1169 } else { 1169 } else {
1170 char *dir = Dir_FindHereOrAbove(curdir, start + 4); 1170 char *dir = Dir_FindHereOrAbove(curdir, start + 4);
1171 if (dir != NULL) { 1171 if (dir != NULL) {
1172 (void)Dir_AddDir(defSysIncPath, dir); 1172 (void)Dir_AddDir(defSysIncPath, dir);
1173 free(dir); 1173 free(dir);
1174 } 1174 }
1175 } 1175 }
1176 } 1176 }
1177 1177
1178 if (syspath != defsyspath) 1178 if (syspath != defsyspath)
1179 free(syspath); 1179 free(syspath);
1180} 1180}
1181 1181
1182static void 1182static void
1183ReadBuiltinRules(void) 1183ReadBuiltinRules(void)
1184{ 1184{
1185 StringList *sysMkPath = Lst_New(); 1185 StringList *sysMkPath = Lst_New();
1186 Dir_Expand(_PATH_DEFSYSMK, 1186 Dir_Expand(_PATH_DEFSYSMK,
1187 Lst_IsEmpty(sysIncPath) ? defSysIncPath : sysIncPath, 1187 Lst_IsEmpty(sysIncPath) ? defSysIncPath : sysIncPath,
1188 sysMkPath); 1188 sysMkPath);
1189 if (Lst_IsEmpty(sysMkPath)) 1189 if (Lst_IsEmpty(sysMkPath))
1190 Fatal("%s: no system rules (%s).", progname, _PATH_DEFSYSMK); 1190 Fatal("%s: no system rules (%s).", progname, _PATH_DEFSYSMK);
1191 if (!Lst_ForEachUntil(sysMkPath, ReadMakefileSucceeded, NULL)) 1191 if (!Lst_ForEachUntil(sysMkPath, ReadMakefileSucceeded, NULL))
1192 Fatal("%s: cannot open %s.", progname, 1192 Fatal("%s: cannot open %s.", progname,
1193 (char *)sysMkPath->first->datum); 1193 (char *)sysMkPath->first->datum);
1194 /* XXX: sysMkPath is not freed */ 1194 /* XXX: sysMkPath is not freed */
1195} 1195}
1196 1196
1197static void 1197static void
1198InitMaxJobs(void) 1198InitMaxJobs(void)
1199{ 1199{
1200 char *value; 1200 char *value;
1201 int n; 1201 int n;
1202 1202
1203 if (forceJobs || opts.compatMake || 1203 if (forceJobs || opts.compatMake ||
1204 !Var_Exists(".MAKE.JOBS", VAR_GLOBAL)) 1204 !Var_Exists(".MAKE.JOBS", VAR_GLOBAL))
1205 return; 1205 return;
1206 1206
1207 (void)Var_Subst("${.MAKE.JOBS}", VAR_GLOBAL, VARE_WANTRES, &value); 1207 (void)Var_Subst("${.MAKE.JOBS}", VAR_GLOBAL, VARE_WANTRES, &value);
1208 /* TODO: handle errors */ 1208 /* TODO: handle errors */
1209 n = (int)strtol(value, NULL, 0); 1209 n = (int)strtol(value, NULL, 0);
1210 if (n < 1) { 1210 if (n < 1) {
1211 (void)fprintf(stderr, 1211 (void)fprintf(stderr,
1212 "%s: illegal value for .MAKE.JOBS " 1212 "%s: illegal value for .MAKE.JOBS "
1213 "-- must be positive integer!\n", 1213 "-- must be positive integer!\n",
1214 progname); 1214 progname);
1215 exit(1); 1215 exit(1);
1216 } 1216 }
1217 1217
1218 if (n != opts.maxJobs) { 1218 if (n != opts.maxJobs) {
1219 Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL); 1219 Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL);
1220 Var_Append(MAKEFLAGS, value, VAR_GLOBAL); 1220 Var_Append(MAKEFLAGS, value, VAR_GLOBAL);
1221 } 1221 }
1222 1222
1223 opts.maxJobs = n; 1223 opts.maxJobs = n;
1224 maxJobTokens = opts.maxJobs; 1224 maxJobTokens = opts.maxJobs;
1225 forceJobs = TRUE; 1225 forceJobs = TRUE;
1226 free(value); 1226 free(value);
1227} 1227}
1228 1228
1229/* 1229/*
1230 * For compatibility, look at the directories in the VPATH variable 1230 * For compatibility, look at the directories in the VPATH variable
1231 * and add them to the search path, if the variable is defined. The 1231 * and add them to the search path, if the variable is defined. The
1232 * variable's value is in the same format as the PATH environment 1232 * variable's value is in the same format as the PATH environment
1233 * variable, i.e. <directory>:<directory>:<directory>... 1233 * variable, i.e. <directory>:<directory>:<directory>...
1234 */ 1234 */
1235static void 1235static void
1236InitVpath(void) 1236InitVpath(void)
1237{ 1237{
1238 char *vpath, savec, *path; 1238 char *vpath, savec, *path;
1239 if (!Var_Exists("VPATH", VAR_CMDLINE)) 1239 if (!Var_Exists("VPATH", VAR_CMDLINE))
1240 return; 1240 return;
1241 1241
1242 (void)Var_Subst("${VPATH}", VAR_CMDLINE, VARE_WANTRES, &vpath); 1242 (void)Var_Subst("${VPATH}", VAR_CMDLINE, VARE_WANTRES, &vpath);
1243 /* TODO: handle errors */ 1243 /* TODO: handle errors */
1244 path = vpath; 1244 path = vpath;
1245 do { 1245 do {
1246 char *cp; 1246 char *cp;
1247 /* skip to end of directory */ 1247 /* skip to end of directory */
1248 for (cp = path; *cp != ':' && *cp != '\0'; cp++) 1248 for (cp = path; *cp != ':' && *cp != '\0'; cp++)
1249 continue; 1249 continue;
1250 /* Save terminator character so know when to stop */ 1250 /* Save terminator character so know when to stop */
1251 savec = *cp; 1251 savec = *cp;
1252 *cp = '\0'; 1252 *cp = '\0';
1253 /* Add directory to search path */ 1253 /* Add directory to search path */
1254 (void)Dir_AddDir(dirSearchPath, path); 1254 (void)Dir_AddDir(dirSearchPath, path);
1255 *cp = savec; 1255 *cp = savec;
1256 path = cp + 1; 1256 path = cp + 1;
1257 } while (savec == ':'); 1257 } while (savec == ':');
1258 free(vpath); 1258 free(vpath);
1259} 1259}
1260 1260
1261static void 1261static void
1262ReadMakefiles(void) 1262ReadMakefiles(void)
1263{ 1263{
1264 if (opts.makefiles->first != NULL) { 1264 if (opts.makefiles->first != NULL) {
1265 StringListNode *ln; 1265 StringListNode *ln;
1266 1266
1267 for (ln = opts.makefiles->first; ln != NULL; ln = ln->next) { 1267 for (ln = opts.makefiles->first; ln != NULL; ln = ln->next) {
1268 if (ReadMakefile(ln->datum) != 0) 1268 if (ReadMakefile(ln->datum) != 0)
1269 Fatal("%s: cannot open %s.", 1269 Fatal("%s: cannot open %s.",
1270 progname, (char *)ln->datum); 1270 progname, (char *)ln->datum);
1271 } 1271 }
1272 } else { 1272 } else {
1273 char *p1; 1273 char *p1;
1274 (void)Var_Subst("${" MAKEFILE_PREFERENCE "}", 1274 (void)Var_Subst("${" MAKEFILE_PREFERENCE "}",
1275 VAR_CMDLINE, VARE_WANTRES, &p1); 1275 VAR_CMDLINE, VARE_WANTRES, &p1);
1276 /* TODO: handle errors */ 1276 /* TODO: handle errors */
1277 (void)str2Lst_Append(opts.makefiles, p1, NULL); 1277 (void)str2Lst_Append(opts.makefiles, p1, NULL);
1278 (void)Lst_ForEachUntil(opts.makefiles, 1278 (void)Lst_ForEachUntil(opts.makefiles,
1279 ReadMakefileSucceeded, NULL); 1279 ReadMakefileSucceeded, NULL);
1280 free(p1); 1280 free(p1);
1281 } 1281 }
1282} 1282}
1283 1283
1284static void 1284static void
1285CleanUp(void) 1285CleanUp(void)
1286{ 1286{
1287#ifdef CLEANUP 1287#ifdef CLEANUP
1288 Lst_Destroy(opts.variables, free); 1288 Lst_Destroy(opts.variables, free);
1289 Lst_Free(opts.makefiles); /* don't free, may be used in GNodes */ 1289 Lst_Free(opts.makefiles); /* don't free, may be used in GNodes */
1290 Lst_Destroy(opts.create, free); 1290 Lst_Destroy(opts.create, free);
1291#endif 1291#endif
1292 1292
1293 /* print the graph now it's been processed if the user requested it */ 1293 /* print the graph now it's been processed if the user requested it */
1294 if (DEBUG(GRAPH2)) 1294 if (DEBUG(GRAPH2))
1295 Targ_PrintGraph(2); 1295 Targ_PrintGraph(2);
1296 1296
1297 Trace_Log(MAKEEND, 0); 1297 Trace_Log(MAKEEND, 0);
1298 1298
1299 if (enterFlagObj) 1299 if (enterFlagObj)
1300 printf("%s: Leaving directory `%s'\n", progname, objdir); 1300 printf("%s: Leaving directory `%s'\n", progname, objdir);
1301 if (opts.enterFlag) 1301 if (opts.enterFlag)
1302 printf("%s: Leaving directory `%s'\n", progname, curdir); 1302 printf("%s: Leaving directory `%s'\n", progname, curdir);
1303 1303
1304#ifdef USE_META 1304#ifdef USE_META
1305 meta_finish(); 1305 meta_finish();
1306#endif 1306#endif
1307 Suff_End(); 1307 Suff_End();
1308 Targ_End(); 1308 Targ_End();
1309 Arch_End(); 1309 Arch_End();
1310 Var_End(); 1310 Var_End();
1311 Parse_End(); 1311 Parse_End();
1312 Dir_End(); 1312 Dir_End();
1313 Job_End(); 1313 Job_End();
1314 Trace_End(); 1314 Trace_End();
1315} 1315}
1316 1316
1317/*- 1317/*-
1318 * main -- 1318 * main --
1319 * The main function, for obvious reasons. Initializes variables 1319 * The main function, for obvious reasons. Initializes variables
1320 * and a few modules, then parses the arguments give it in the 1320 * and a few modules, then parses the arguments give it in the
1321 * environment and on the command line. Reads the system makefile 1321 * environment and on the command line. Reads the system makefile
1322 * followed by either Makefile, makefile or the file given by the 1322 * followed by either Makefile, makefile or the file given by the
1323 * -f argument. Sets the .MAKEFLAGS PMake variable based on all the 1323 * -f argument. Sets the .MAKEFLAGS PMake variable based on all the
1324 * flags it has received by then uses either the Make or the Compat 1324 * flags it has received by then uses either the Make or the Compat
1325 * module to create the initial list of targets. 1325 * module to create the initial list of targets.
1326 * 1326 *
1327 * Results: 1327 * Results:
1328 * If -q was given, exits -1 if anything was out-of-date. Else it exits 1328 * If -q was given, exits -1 if anything was out-of-date. Else it exits
1329 * 0. 1329 * 0.
1330 * 1330 *
1331 * Side Effects: 1331 * Side Effects:
1332 * The program exits when done. Targets are created. etc. etc. etc. 1332 * The program exits when done. Targets are created. etc. etc. etc.
1333 */ 1333 */
1334int 1334int
1335main(int argc, char **argv) 1335main(int argc, char **argv)
1336{ 1336{
1337 Boolean outOfDate; /* FALSE if all targets up to date */ 1337 Boolean outOfDate; /* FALSE if all targets up to date */
1338 struct stat sa; 1338 struct stat sa;
1339 const char *machine; 1339 const char *machine;
1340 const char *machine_arch; 1340 const char *machine_arch;
1341 char *syspath = getenv("MAKESYSPATH"); 1341 char *syspath = getenv("MAKESYSPATH");
1342 struct utsname utsname; 1342 struct utsname utsname;
1343 1343
1344 /* default to writing debug to stderr */ 1344 /* default to writing debug to stderr */
1345 opts.debug_file = stderr; 1345 opts.debug_file = stderr;
1346 1346
1347#ifdef SIGINFO 1347#ifdef SIGINFO
1348 (void)bmake_signal(SIGINFO, siginfo); 1348 (void)bmake_signal(SIGINFO, siginfo);
1349#endif 1349#endif
1350 1350
1351 InitRandom(); 1351 InitRandom();
1352 1352
1353 if ((progname = strrchr(argv[0], '/')) != NULL) 1353 if ((progname = strrchr(argv[0], '/')) != NULL)
1354 progname++; 1354 progname++;
1355 else 1355 else
1356 progname = argv[0]; 1356 progname = argv[0];
1357 1357
1358 UnlimitFiles(); 1358 UnlimitFiles();
1359 1359
1360 if (uname(&utsname) == -1) { 1360 if (uname(&utsname) == -1) {
1361 (void)fprintf(stderr, "%s: uname failed (%s).\n", progname, 1361 (void)fprintf(stderr, "%s: uname failed (%s).\n", progname,
1362 strerror(errno)); 1362 strerror(errno));
1363 exit(2); 1363 exit(2);
1364 } 1364 }
1365 1365
1366 /* 1366 /*
1367 * Get the name of this type of MACHINE from utsname 1367 * Get the name of this type of MACHINE from utsname
1368 * so we can share an executable for similar machines. 1368 * so we can share an executable for similar machines.
1369 * (i.e. m68k: amiga hp300, mac68k, sun3, ...) 1369 * (i.e. m68k: amiga hp300, mac68k, sun3, ...)
1370 * 1370 *
1371 * Note that both MACHINE and MACHINE_ARCH are decided at 1371 * Note that both MACHINE and MACHINE_ARCH are decided at
1372 * run-time. 1372 * run-time.
1373 */ 1373 */
1374 machine = init_machine(&utsname); 1374 machine = init_machine(&utsname);
1375 machine_arch = init_machine_arch(); 1375 machine_arch = init_machine_arch();
1376 1376
1377 myPid = getpid(); /* remember this for vFork() */ 1377 myPid = getpid(); /* remember this for vFork() */
1378 1378
1379 /* 1379 /*
1380 * Just in case MAKEOBJDIR wants us to do something tricky. 1380 * Just in case MAKEOBJDIR wants us to do something tricky.
1381 */ 1381 */
1382 Var_Init(); /* Initialize the lists of variables for 1382 Var_Init(); /* Initialize the lists of variables for
1383 * parsing arguments */ 1383 * parsing arguments */
1384 Var_Set(".MAKE.OS", utsname.sysname, VAR_GLOBAL); 1384 Var_Set(".MAKE.OS", utsname.sysname, VAR_GLOBAL);
1385 Var_Set("MACHINE", machine, VAR_GLOBAL); 1385 Var_Set("MACHINE", machine, VAR_GLOBAL);
1386 Var_Set("MACHINE_ARCH", machine_arch, VAR_GLOBAL); 1386 Var_Set("MACHINE_ARCH", machine_arch, VAR_GLOBAL);
1387#ifdef MAKE_VERSION 1387#ifdef MAKE_VERSION
1388 Var_Set("MAKE_VERSION", MAKE_VERSION, VAR_GLOBAL); 1388 Var_Set("MAKE_VERSION", MAKE_VERSION, VAR_GLOBAL);
1389#endif 1389#endif
1390 Var_Set(".newline", "\n", VAR_GLOBAL); /* handy for :@ loops */ 1390 Var_Set(".newline", "\n", VAR_GLOBAL); /* handy for :@ loops */
1391 /* 1391 /*
1392 * This is the traditional preference for makefiles. 1392 * This is the traditional preference for makefiles.
1393 */ 1393 */
1394#ifndef MAKEFILE_PREFERENCE_LIST 1394#ifndef MAKEFILE_PREFERENCE_LIST
1395# define MAKEFILE_PREFERENCE_LIST "makefile Makefile" 1395# define MAKEFILE_PREFERENCE_LIST "makefile Makefile"
1396#endif 1396#endif
1397 Var_Set(MAKEFILE_PREFERENCE, MAKEFILE_PREFERENCE_LIST, 1397 Var_Set(MAKEFILE_PREFERENCE, MAKEFILE_PREFERENCE_LIST,
1398 VAR_GLOBAL); 1398 VAR_GLOBAL);
1399 Var_Set(MAKE_DEPENDFILE, ".depend", VAR_GLOBAL); 1399 Var_Set(MAKE_DEPENDFILE, ".depend", VAR_GLOBAL);
1400 1400
1401 CmdOpts_Init(); 1401 CmdOpts_Init();
1402 allPrecious = FALSE; /* Remove targets when interrupted */ 1402 allPrecious = FALSE; /* Remove targets when interrupted */
1403 deleteOnError = FALSE; /* Historical default behavior */ 1403 deleteOnError = FALSE; /* Historical default behavior */
1404 jobsRunning = FALSE; 1404 jobsRunning = FALSE;
1405 1405
1406 maxJobTokens = opts.maxJobs; 1406 maxJobTokens = opts.maxJobs;
1407 ignorePWD = FALSE; 1407 ignorePWD = FALSE;
1408 1408
1409 /* 1409 /*
1410 * Initialize the parsing, directory and variable modules to prepare 1410 * Initialize the parsing, directory and variable modules to prepare
1411 * for the reading of inclusion paths and variable settings on the 1411 * for the reading of inclusion paths and variable settings on the
1412 * command line 1412 * command line
1413 */ 1413 */
1414 1414
1415 /* 1415 /*
1416 * Initialize various variables. 1416 * Initialize various variables.
1417 * MAKE also gets this name, for compatibility 1417 * MAKE also gets this name, for compatibility
1418 * .MAKEFLAGS gets set to the empty string just in case. 1418 * .MAKEFLAGS gets set to the empty string just in case.
1419 * MFLAGS also gets initialized empty, for compatibility. 1419 * MFLAGS also gets initialized empty, for compatibility.
1420 */ 1420 */
1421 Parse_Init(); 1421 Parse_Init();
1422 InitVarMake(argv[0]); 1422 InitVarMake(argv[0]);
1423 Var_Set(MAKEFLAGS, "", VAR_GLOBAL); 1423 Var_Set(MAKEFLAGS, "", VAR_GLOBAL);
1424 Var_Set(MAKEOVERRIDES, "", VAR_GLOBAL); 1424 Var_Set(MAKEOVERRIDES, "", VAR_GLOBAL);
1425 Var_Set("MFLAGS", "", VAR_GLOBAL); 1425 Var_Set("MFLAGS", "", VAR_GLOBAL);
1426 Var_Set(".ALLTARGETS", "", VAR_GLOBAL); 1426 Var_Set(".ALLTARGETS", "", VAR_GLOBAL);
1427 /* some makefiles need to know this */ 1427 /* some makefiles need to know this */
1428 Var_Set(MAKE_LEVEL ".ENV", MAKE_LEVEL_ENV, VAR_CMDLINE); 1428 Var_Set(MAKE_LEVEL ".ENV", MAKE_LEVEL_ENV, VAR_CMDLINE);
1429 1429
1430 /* 1430 /*
1431 * Set some other useful macros 1431 * Set some other useful macros
1432 */ 1432 */
1433 { 1433 {
1434 char tmp[64], *ep; 1434 char tmp[64], *ep;
1435 1435
1436 makelevel = ((ep = getenv(MAKE_LEVEL_ENV)) && *ep) ? atoi(ep) : 0; 1436 makelevel = ((ep = getenv(MAKE_LEVEL_ENV)) && *ep) ? atoi(ep) : 0;
1437 if (makelevel < 0) 1437 if (makelevel < 0)
1438 makelevel = 0; 1438 makelevel = 0;
1439 snprintf(tmp, sizeof(tmp), "%d", makelevel); 1439 snprintf(tmp, sizeof(tmp), "%d", makelevel);
1440 Var_Set(MAKE_LEVEL, tmp, VAR_GLOBAL); 1440 Var_Set(MAKE_LEVEL, tmp, VAR_GLOBAL);
1441 snprintf(tmp, sizeof(tmp), "%u", myPid); 1441 snprintf(tmp, sizeof(tmp), "%u", myPid);
1442 Var_Set(".MAKE.PID", tmp, VAR_GLOBAL); 1442 Var_Set(".MAKE.PID", tmp, VAR_GLOBAL);
1443 snprintf(tmp, sizeof(tmp), "%u", getppid()); 1443 snprintf(tmp, sizeof(tmp), "%u", getppid());
1444 Var_Set(".MAKE.PPID", tmp, VAR_GLOBAL); 1444 Var_Set(".MAKE.PPID", tmp, VAR_GLOBAL);
1445 } 1445 }
1446 if (makelevel > 0) { 1446 if (makelevel > 0) {
1447 char pn[1024]; 1447 char pn[1024];
1448 snprintf(pn, sizeof(pn), "%s[%d]", progname, makelevel); 1448 snprintf(pn, sizeof(pn), "%s[%d]", progname, makelevel);
1449 progname = bmake_strdup(pn); 1449 progname = bmake_strdup(pn);
1450 } 1450 }
1451 1451
1452#ifdef USE_META 1452#ifdef USE_META
1453 meta_init(); 1453 meta_init();
1454#endif 1454#endif
1455 Dir_Init(); 1455 Dir_Init();
1456 1456
1457 /* 1457 /*
1458 * First snag any flags out of the MAKE environment variable. 1458 * First snag any flags out of the MAKE environment variable.
1459 * (Note this is *not* MAKEFLAGS since /bin/make uses that and it's 1459 * (Note this is *not* MAKEFLAGS since /bin/make uses that and it's
1460 * in a different format). 1460 * in a different format).
1461 */ 1461 */
1462#ifdef POSIX 1462#ifdef POSIX
1463 { 1463 {
1464 char *p1 = explode(getenv("MAKEFLAGS")); 1464 char *p1 = explode(getenv("MAKEFLAGS"));
1465 Main_ParseArgLine(p1); 1465 Main_ParseArgLine(p1);
1466 free(p1); 1466 free(p1);
1467 } 1467 }
1468#else 1468#else
1469 Main_ParseArgLine(getenv("MAKE")); 1469 Main_ParseArgLine(getenv("MAKE"));
1470#endif 1470#endif
1471 1471
1472 /* 1472 /*
1473 * Find where we are (now). 1473 * Find where we are (now).
1474 * We take care of PWD for the automounter below... 1474 * We take care of PWD for the automounter below...
1475 */ 1475 */
1476 if (getcwd(curdir, MAXPATHLEN) == NULL) { 1476 if (getcwd(curdir, MAXPATHLEN) == NULL) {
1477 (void)fprintf(stderr, "%s: getcwd: %s.\n", 1477 (void)fprintf(stderr, "%s: getcwd: %s.\n",
1478 progname, strerror(errno)); 1478 progname, strerror(errno));
1479 exit(2); 1479 exit(2);
1480 } 1480 }
1481 1481
1482 MainParseArgs(argc, argv); 1482 MainParseArgs(argc, argv);
1483 1483
1484 if (opts.enterFlag) 1484 if (opts.enterFlag)
1485 printf("%s: Entering directory `%s'\n", progname, curdir); 1485 printf("%s: Entering directory `%s'\n", progname, curdir);
1486 1486
1487 /* 1487 /*
1488 * Verify that cwd is sane. 1488 * Verify that cwd is sane.
1489 */ 1489 */
1490 if (stat(curdir, &sa) == -1) { 1490 if (stat(curdir, &sa) == -1) {
1491 (void)fprintf(stderr, "%s: %s: %s.\n", 1491 (void)fprintf(stderr, "%s: %s: %s.\n",
1492 progname, curdir, strerror(errno)); 1492 progname, curdir, strerror(errno));
1493 exit(2); 1493 exit(2);
1494 } 1494 }
1495 1495
1496#ifndef NO_PWD_OVERRIDE 1496#ifndef NO_PWD_OVERRIDE
1497 HandlePWD(&sa); 1497 HandlePWD(&sa);
1498#endif 1498#endif
1499 Var_Set(".CURDIR", curdir, VAR_GLOBAL); 1499 Var_Set(".CURDIR", curdir, VAR_GLOBAL);
1500 1500
1501 InitObjdir(machine, machine_arch); 1501 InitObjdir(machine, machine_arch);
1502 1502
1503 /* 1503 /*
1504 * Initialize archive, target and suffix modules in preparation for 1504 * Initialize archive, target and suffix modules in preparation for
1505 * parsing the makefile(s) 1505 * parsing the makefile(s)
1506 */ 1506 */
1507 Arch_Init(); 1507 Arch_Init();
1508 Targ_Init(); 1508 Targ_Init();
1509 Suff_Init(); 1509 Suff_Init();
1510 Trace_Init(tracefile); 1510 Trace_Init(tracefile);
1511 1511
1512 DEFAULT = NULL; 1512 DEFAULT = NULL;
1513 (void)time(&now); 1513 (void)time(&now);
1514 1514
1515 Trace_Log(MAKESTART, NULL); 1515 Trace_Log(MAKESTART, NULL);
1516 1516
1517 InitVarTargets(); 1517 InitVarTargets();
1518 1518
1519 InitDefSysIncPath(syspath); 1519 InitDefSysIncPath(syspath);
1520 1520
1521 /* 1521 /*
1522 * Read in the built-in rules first, followed by the specified 1522 * Read in the built-in rules first, followed by the specified
1523 * makefiles, or the default makefile and Makefile, in that order, 1523 * makefiles, or the default makefile and Makefile, in that order,
1524 * if no makefiles were given on the command line. 1524 * if no makefiles were given on the command line.
1525 */ 1525 */
1526 if (!opts.noBuiltins) 1526 if (!opts.noBuiltins)
1527 ReadBuiltinRules(); 1527 ReadBuiltinRules();
1528 ReadMakefiles(); 1528 ReadMakefiles();
1529  1529
1530 /* In particular suppress .depend for '-r -V .OBJDIR -f /dev/null' */ 1530 /* In particular suppress .depend for '-r -V .OBJDIR -f /dev/null' */
1531 if (!opts.noBuiltins || !opts.printVars) { 1531 if (!opts.noBuiltins || !opts.printVars) {
1532 /* ignore /dev/null and anything starting with "no" */ 1532 /* ignore /dev/null and anything starting with "no" */
1533 (void)Var_Subst("${.MAKE.DEPENDFILE:N/dev/null:Nno*:T}", 1533 (void)Var_Subst("${.MAKE.DEPENDFILE:N/dev/null:Nno*:T}",
1534 VAR_CMDLINE, VARE_WANTRES, &makeDependfile); 1534 VAR_CMDLINE, VARE_WANTRES, &makeDependfile);
1535 if (makeDependfile[0] != '\0') { 1535 if (makeDependfile[0] != '\0') {
1536 /* TODO: handle errors */ 1536 /* TODO: handle errors */
1537 doing_depend = TRUE; 1537 doing_depend = TRUE;
1538 (void)ReadMakefile(makeDependfile); 1538 (void)ReadMakefile(makeDependfile);
1539 doing_depend = FALSE; 1539 doing_depend = FALSE;
1540 } 1540 }
1541 } 1541 }
1542 1542
1543 if (enterFlagObj) 1543 if (enterFlagObj)
1544 printf("%s: Entering directory `%s'\n", progname, objdir); 1544 printf("%s: Entering directory `%s'\n", progname, objdir);
1545 1545
1546 MakeMode(NULL); 1546 MakeMode(NULL);
1547 1547
1548 { 1548 {
1549 void *freeIt; 1549 void *freeIt;
1550 Var_Append("MFLAGS", Var_Value(MAKEFLAGS, VAR_GLOBAL, &freeIt), 1550 Var_Append("MFLAGS", Var_Value(MAKEFLAGS, VAR_GLOBAL, &freeIt),
1551 VAR_GLOBAL); 1551 VAR_GLOBAL);
1552 bmake_free(freeIt); 1552 bmake_free(freeIt);
1553 1553
1554 } 1554 }
1555 1555
1556 InitMaxJobs(); 1556 InitMaxJobs();
1557 1557
1558 /* 1558 /*
1559 * Be compatible if user did not specify -j and did not explicitly 1559 * Be compatible if user did not specify -j and did not explicitly
1560 * turned compatibility on 1560 * turned compatibility on
1561 */ 1561 */
1562 if (!opts.compatMake && !forceJobs) { 1562 if (!opts.compatMake && !forceJobs) {
1563 opts.compatMake = TRUE; 1563 opts.compatMake = TRUE;
1564 } 1564 }
1565 1565
1566 if (!opts.compatMake) 1566 if (!opts.compatMake)
1567 Job_ServerStart(maxJobTokens, jp_0, jp_1); 1567 Job_ServerStart(maxJobTokens, jp_0, jp_1);
1568 DEBUG5(JOB, "job_pipe %d %d, maxjobs %d, tokens %d, compat %d\n", 1568 DEBUG5(JOB, "job_pipe %d %d, maxjobs %d, tokens %d, compat %d\n",
1569 jp_0, jp_1, opts.maxJobs, maxJobTokens, opts.compatMake ? 1 : 0); 1569 jp_0, jp_1, opts.maxJobs, maxJobTokens, opts.compatMake ? 1 : 0);
1570 1570
1571 if (!opts.printVars) 1571 if (!opts.printVars)
1572 Main_ExportMAKEFLAGS(TRUE); /* initial export */ 1572 Main_ExportMAKEFLAGS(TRUE); /* initial export */
1573 1573
1574 InitVpath(); 1574 InitVpath();
1575 1575
1576 /* 1576 /*
1577 * Now that all search paths have been read for suffixes et al, it's 1577 * Now that all search paths have been read for suffixes et al, it's
1578 * time to add the default search path to their lists... 1578 * time to add the default search path to their lists...
1579 */ 1579 */
1580 Suff_DoPaths(); 1580 Suff_DoPaths();
1581 1581
1582 /* 1582 /*
1583 * Propagate attributes through :: dependency lists. 1583 * Propagate attributes through :: dependency lists.
1584 */ 1584 */
1585 Targ_Propagate(); 1585 Targ_Propagate();
1586 1586
1587 /* print the initial graph, if the user requested it */ 1587 /* print the initial graph, if the user requested it */
1588 if (DEBUG(GRAPH1)) 1588 if (DEBUG(GRAPH1))
1589 Targ_PrintGraph(1); 1589 Targ_PrintGraph(1);
1590 1590
1591 /* print the values of any variables requested by the user */ 1591 /* print the values of any variables requested by the user */
1592 if (opts.printVars) { 1592 if (opts.printVars) {
1593 doPrintVars(); 1593 doPrintVars();
1594 outOfDate = FALSE; 1594 outOfDate = FALSE;
1595 } else { 1595 } else {
1596 outOfDate = runTargets(); 1596 outOfDate = runTargets();
1597 } 1597 }
1598 1598
1599 CleanUp(); 1599 CleanUp();
1600 1600
1601 return outOfDate ? 1 : 0; 1601 return outOfDate ? 1 : 0;
1602} 1602}
1603 1603
1604/* Open and parse the given makefile, with all its side effects. 1604/* Open and parse the given makefile, with all its side effects.
1605 * 1605 *
1606 * Results: 1606 * Results:
1607 * 0 if ok. -1 if couldn't open file. 1607 * 0 if ok. -1 if couldn't open file.
1608 */ 1608 */
1609static int 1609static int
1610ReadMakefile(const char *fname) 1610ReadMakefile(const char *fname)
1611{ 1611{
1612 int fd; 1612 int fd;
1613 char *name, *path = NULL; 1613 char *name, *path = NULL;
1614 1614
1615 if (!strcmp(fname, "-")) { 1615 if (!strcmp(fname, "-")) {
1616 Parse_File(NULL /*stdin*/, -1); 1616 Parse_File(NULL /*stdin*/, -1);
1617 Var_Set("MAKEFILE", "", VAR_INTERNAL); 1617 Var_Set("MAKEFILE", "", VAR_INTERNAL);
1618 } else { 1618 } else {
1619 /* if we've chdir'd, rebuild the path name */ 1619 /* if we've chdir'd, rebuild the path name */
1620 if (strcmp(curdir, objdir) && *fname != '/') { 1620 if (strcmp(curdir, objdir) && *fname != '/') {
1621 path = str_concat3(curdir, "/", fname); 1621 path = str_concat3(curdir, "/", fname);
1622 fd = open(path, O_RDONLY); 1622 fd = open(path, O_RDONLY);
1623 if (fd != -1) { 1623 if (fd != -1) {
1624 fname = path; 1624 fname = path;
1625 goto found; 1625 goto found;
1626 } 1626 }
1627 free(path); 1627 free(path);
1628 1628
1629 /* If curdir failed, try objdir (ala .depend) */ 1629 /* If curdir failed, try objdir (ala .depend) */
1630 path = str_concat3(objdir, "/", fname); 1630 path = str_concat3(objdir, "/", fname);
1631 fd = open(path, O_RDONLY); 1631 fd = open(path, O_RDONLY);
1632 if (fd != -1) { 1632 if (fd != -1) {
1633 fname = path; 1633 fname = path;
1634 goto found; 1634 goto found;
1635 } 1635 }
1636 } else { 1636 } else {
1637 fd = open(fname, O_RDONLY); 1637 fd = open(fname, O_RDONLY);
1638 if (fd != -1) 1638 if (fd != -1)
1639 goto found; 1639 goto found;
1640 } 1640 }
1641 /* look in -I and system include directories. */ 1641 /* look in -I and system include directories. */
1642 name = Dir_FindFile(fname, parseIncPath); 1642 name = Dir_FindFile(fname, parseIncPath);
1643 if (!name) { 1643 if (!name) {
1644 SearchPath *sysInc = Lst_IsEmpty(sysIncPath) 1644 SearchPath *sysInc = Lst_IsEmpty(sysIncPath)
1645 ? defSysIncPath : sysIncPath; 1645 ? defSysIncPath : sysIncPath;
1646 name = Dir_FindFile(fname, sysInc); 1646 name = Dir_FindFile(fname, sysInc);
1647 } 1647 }
1648 if (!name || (fd = open(name, O_RDONLY)) == -1) { 1648 if (!name || (fd = open(name, O_RDONLY)) == -1) {
1649 free(name); 1649 free(name);
1650 free(path); 1650 free(path);
1651 return -1; 1651 return -1;
1652 } 1652 }
1653 fname = name; 1653 fname = name;
1654 /* 1654 /*
1655 * set the MAKEFILE variable desired by System V fans -- the 1655 * set the MAKEFILE variable desired by System V fans -- the
1656 * placement of the setting here means it gets set to the last 1656 * placement of the setting here means it gets set to the last
1657 * makefile specified, as it is set by SysV make. 1657 * makefile specified, as it is set by SysV make.
1658 */ 1658 */
1659found: 1659found:
1660 if (!doing_depend) 1660 if (!doing_depend)
1661 Var_Set("MAKEFILE", fname, VAR_INTERNAL); 1661 Var_Set("MAKEFILE", fname, VAR_INTERNAL);
1662 Parse_File(fname, fd); 1662 Parse_File(fname, fd);
1663 } 1663 }
1664 free(path); 1664 free(path);
1665 return 0; 1665 return 0;
1666} 1666}
1667 1667
1668 1668
1669 1669
1670/*- 1670/*-
1671 * Cmd_Exec -- 1671 * Cmd_Exec --
1672 * Execute the command in cmd, and return the output of that command 1672 * Execute the command in cmd, and return the output of that command
1673 * in a string. In the output, newlines are replaced with spaces. 1673 * in a string. In the output, newlines are replaced with spaces.
1674 * 1674 *
1675 * Results: 1675 * Results:
1676 * A string containing the output of the command, or the empty string. 1676 * A string containing the output of the command, or the empty string.
1677 * *errfmt returns a format string describing the command failure, 1677 * *errfmt returns a format string describing the command failure,
1678 * if any, using a single %s conversion specification. 1678 * if any, using a single %s conversion specification.
1679 * 1679 *
1680 * Side Effects: 1680 * Side Effects:
1681 * The string must be freed by the caller. 1681 * The string must be freed by the caller.
1682 */ 1682 */
1683char * 1683char *
1684Cmd_Exec(const char *cmd, const char **errfmt) 1684Cmd_Exec(const char *cmd, const char **errfmt)
1685{ 1685{
1686 const char *args[4]; /* Args for invoking the shell */ 1686 const char *args[4]; /* Args for invoking the shell */
1687 int fds[2]; /* Pipe streams */ 1687 int fds[2]; /* Pipe streams */
1688 int cpid; /* Child PID */ 1688 int cpid; /* Child PID */
1689 int pid; /* PID from wait() */ 1689 int pid; /* PID from wait() */
1690 int status; /* command exit status */ 1690 int status; /* command exit status */
1691 Buffer buf; /* buffer to store the result */ 1691 Buffer buf; /* buffer to store the result */
1692 ssize_t bytes_read; 1692 ssize_t bytes_read;
1693 char *res; /* result */ 1693 char *res; /* result */
1694 size_t res_len; 1694 size_t res_len;
1695 char *cp; 1695 char *cp;
1696 int savederr; /* saved errno */ 1696 int savederr; /* saved errno */
1697 1697
1698 *errfmt = NULL; 1698 *errfmt = NULL;
1699 1699
1700 if (!shellName) 1700 if (!shellName)
1701 Shell_Init(); 1701 Shell_Init();
1702 /* 1702 /*
1703 * Set up arguments for shell 1703 * Set up arguments for shell
1704 */ 1704 */
1705 args[0] = shellName; 1705 args[0] = shellName;
1706 args[1] = "-c"; 1706 args[1] = "-c";
1707 args[2] = cmd; 1707 args[2] = cmd;
1708 args[3] = NULL; 1708 args[3] = NULL;
1709 1709
1710 /* 1710 /*
1711 * Open a pipe for fetching its output 1711 * Open a pipe for fetching its output
1712 */ 1712 */
1713 if (pipe(fds) == -1) { 1713 if (pipe(fds) == -1) {
1714 *errfmt = "Couldn't create pipe for \"%s\""; 1714 *errfmt = "Couldn't create pipe for \"%s\"";
1715 goto bad; 1715 goto bad;
1716 } 1716 }
1717 1717
1718 /* 1718 /*
1719 * Fork 1719 * Fork
1720 */ 1720 */
1721 switch (cpid = vFork()) { 1721 switch (cpid = vFork()) {
1722 case 0: 1722 case 0:
1723 /* 1723 /*