xref: /plan9/sys/src/ape/cmd/make/main.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 # include "defs.h"
2 /*
3 command make to update programs.
4 Posix Flags:
5 	'e'  use environment macros after rather than before makefiles
6 	'f'  the next argument is the name of the description file;
7 	     "makefile" is the default
8 	'i'  ignore error codes from the shell
9 	'k'  continue to update other targets that don't depend
10 	     on target if error occurs making a target
11 	'n'  don't issue, just print, commands
12 	'p'  print out a version of the input graph
13 	'q'  don't do anything, but check if object is up to date;
14 	     returns exit code 0 if up to date, 1 if not
15 	'r'  clear the builtin suffix list and don't use built-in rules
16 	's'  silent mode--don't print out commands
17 	'S'  stop after any command fails (default; opposite of -k)
18 	't'  touch (update time of) files but don't issue command
19 
20 Nonposix Flags:
21 	'd'  print out debugging comments
22 	'N'  use % patterns instead of old suffix rules
23 	'Pn' set process limit to n
24 	'z'  always use shell, never issue commands directly
25 
26 */
27 
28 nameblkp mainname	= NULL;
29 nameblkp firstname	= NULL;
30 lineblkp sufflist	= NULL;
31 struct varblock *firstvar	= NULL;
32 struct pattern *firstpat	= NULL;
33 struct dirhd *firstod		= NULL;
34 wildp firstwild			= NULL;
35 wildp lastwild			= NULL;
36 nameblkp *hashtab;
37 int nhashed;
38 int hashsize;
39 int hashthresh;
40 
41 int proclimit	= PROCLIMIT;
42 int nproc	= 0;
43 int proclive	= 0;
44 struct process procstack[MAXPROC];
45 
46 int sigivalue	= 0;
47 int sigqvalue	= 0;
48 
49 int dbgflag	= NO;
50 int prtrflag	= NO;
51 int silflag	= NO;
52 int noexflag	= NO;
53 int keepgoing	= NO;
54 int noruleflag	= NO;
55 int touchflag	= NO;
56 int questflag	= NO;
57 int oldflag	= YES;
58 int ndocoms	= NO;
59 int ignerr	= NO;    /* default is to stop on error */
60 int forceshell	= NO;
61 int okdel	= YES;
62 int envlast	= NO;
63 int inarglist	= NO;
64 char **envpp	= NULL;
65 
66 extern char *dfltmacro[];
67 extern char *dfltpat[];
68 extern char *dfltsuff[];
69 extern char **environ;
70 char **linesptr;
71 
72 char *prompt	= "";
73 int nopdir	= 0;
74 char funny[128];
75 
76 static void	loadenv(void);
77 static int	isprecious(char *);
78 static int	rddescf(char *);
79 static void	rdarray(char **);
80 static void	printdesc(int);
81 
82 void
main(int argc,char ** argv)83 main(int argc, char **argv)
84 {
85 nameblkp p;
86 int i, j;
87 int descset, nfargs;
88 int nowait = NO;
89 time_t tjunk;
90 char c, *s, *mkflagp;
91 static char makeflags[30] = "-";
92 static char onechar[2] = "X";
93 
94 descset = 0;
95 mkflagp = makeflags+1;
96 
97 funny['\0'] = (META | TERMINAL);
98 for(s = "=|^();&<>*?[]:$`'\"\\\n" ; *s ; ++s)
99 	funny[*s] |= META;
100 for(s = "\n\t :;&>|" ; *s ; ++s)
101 	funny[*s] |= TERMINAL;
102 
103 
104 newhash(HASHSIZE);
105 
106 inarglist = YES;
107 for(i=1; i<argc; ++i)
108 	if(argv[i]!=0 && argv[i][0]!='-' && eqsign(argv[i]))
109 		argv[i] = 0;
110 
111 setvar("$", "$", NO);
112 inarglist = NO;
113 
114 for(i=1; i<argc; ++i)
115     if(argv[i]!=0 && argv[i][0]=='-')
116 	{
117 	for(j=1 ; (c=argv[i][j])!='\0' ; ++j)  switch(c)
118 		{
119 		case 'd':
120 			++dbgflag;
121 			*mkflagp++ = 'd';
122 			break;
123 
124 		case 'e':
125 			envlast = YES;
126 			*mkflagp++ = 'e';
127 			break;
128 
129 		case 'f':
130 			if(i >= argc-1)
131 			  fatal("No description argument after -f flag");
132 			if( ! rddescf(argv[i+1]) )
133 				fatal1("Cannot open %s", argv[i+1]);
134 			argv[i+1] = 0;
135 			++descset;
136 			break;
137 
138 		case 'i':
139 			ignerr = YES;
140 			*mkflagp++ = 'i';
141 			break;
142 
143 		case 'k':
144 			keepgoing = YES;
145 			*mkflagp++ = 'k';
146 			break;
147 
148 		case 'n':
149 			noexflag = YES;
150 			*mkflagp++ = 'n';
151 			break;
152 
153 		case 'N':
154 			oldflag = NO;
155 			*mkflagp++ = 'N';
156 			break;
157 
158 		case 'p':
159 			prtrflag = YES;
160 			break;
161 
162 		case 'P':
163 			if(isdigit(argv[i][j+1]))
164 				{
165 				proclimit = argv[i][++j] - '0';
166 				if(proclimit < 1)
167 					proclimit = 1;
168 				}
169 			else
170 				fatal("illegal proclimit parameter");
171 			*mkflagp++ = 'P';
172 			*mkflagp++ = argv[i][j];
173 			break;
174 
175 		case 'q':
176 			questflag = YES;
177 			*mkflagp++ = 'q';
178 			break;
179 
180 		case 'r':
181 			noruleflag = YES;
182 			*mkflagp++ = 'r';
183 			break;
184 
185 		case 's':
186 			silflag = YES;
187 			*mkflagp++ = 's';
188 			break;
189 
190 		case 'S':
191 			keepgoing = NO;
192 			*mkflagp++ = 'S';
193 			break;
194 
195 		case 't':
196 			touchflag = YES;
197 			*mkflagp++ = 't';
198 			break;
199 
200 		case 'z':
201 			forceshell = YES;
202 			*mkflagp++ = 'z';
203 			break;
204 
205 		default:
206 			onechar[0] = c;	/* to make lint happy */
207 			fatal1("Unknown flag argument %s", onechar);
208 		}
209 
210 	argv[i] = NULL;
211 	}
212 
213 if(mkflagp > makeflags+1)
214 	setvar("MAKEFLAGS", makeflags, NO);
215 
216 if( !descset )
217 if(	!rddescf("makefile") &&
218 	!rddescf("Makefile") &&
219 	(exists(s = "s.makefile") || exists(s = "s.Makefile")) )
220 		{
221 		char junk[20];
222 		concat("get ", s, junk);
223 		(void) dosys(junk, NO, NO, junk);
224 		rddescf(s+2);
225 		unlink(s+2);
226 		}
227 
228 
229 if(envlast)
230 	loadenv();
231 if(!noruleflag && !oldflag)
232 	rdarray(dfltpat);
233 
234 if(prtrflag) printdesc(NO);
235 
236 if( srchname(".IGNORE") )
237 	ignerr = YES;
238 if( srchname(".SILENT") )
239 	silflag = YES;
240 if( srchname(".OLDFLAG") )
241 	oldflag = YES;
242 if( p=srchname(".SUFFIXES") )
243 	sufflist = p->linep;
244 if( !sufflist && !firstwild)
245 	fprintf(stderr,"No suffix or %% pattern list.\n");
246 /*
247 if(sufflist && !oldflag)
248 	fprintf(stderr, "Suffix lists are old-fashioned. Use %% patterns\n);
249 */
250 
251 	sigivalue = (int) signal(SIGINT, SIG_IGN);
252 	sigqvalue = (int) signal(SIGQUIT, SIG_IGN);
253 	enbint(intrupt);
254 
255 nfargs = 0;
256 
257 for(i=1; i<argc; ++i)
258 	if(s = argv[i])
259 		{
260 		if((p=srchname(s)) == NULL)
261 			p = makename(s);
262 		++nfargs;
263 		if(i+1<argc && argv[i+1] != 0 && equal(argv[i+1], "&") )
264 			{
265 			++i;
266 			nowait = YES;
267 			}
268 		else
269 			nowait = NO;
270 		doname(p, 0, &tjunk, nowait);
271 		if(dbgflag) printdesc(YES);
272 		}
273 
274 /*
275 If no file arguments have been encountered, make the first
276 name encountered that doesn't start with a dot
277 */
278 
279 if(nfargs == 0)
280 	if(mainname == 0)
281 		fatal("No arguments or description file");
282 	else	{
283 		doname(mainname, 0, &tjunk, NO);
284 		if(dbgflag) printdesc(YES);
285 		}
286 
287 if(!nowait)
288 	waitstack(0);
289 exit(0);
290 }
291 
292 
293 void
intrupt(int sig)294 intrupt(int sig)
295 {
296 char *p;
297 
298 if(okdel && !noexflag && !touchflag &&
299 	(p = varptr("@")->varval) && exists(p)>0 && !isprecious(p) )
300 		{
301 		fprintf(stderr, "\n***  %s removed.", p);
302 		remove(p);
303 		}
304 
305 fprintf(stderr, "\n");
306 exit(2);
307 }
308 
309 
310 
311 static int
isprecious(char * p)312 isprecious(char *p)
313 {
314 lineblkp lp;
315 depblkp dp;
316 nameblkp np;
317 
318 if(np = srchname(".PRECIOUS"))
319 	for(lp = np->linep ; lp ; lp = lp->nxtlineblock)
320 		for(dp = lp->depp ; dp ; dp = dp->nxtdepblock)
321 			if(equal(p, dp->depname->namep))
322 				return YES;
323 
324 return NO;
325 }
326 
327 
328 void
enbint(void (* k)(int))329 enbint(void (*k)(int))
330 {
331 if(sigivalue == 0)
332 	signal(SIGINT,k);
333 if(sigqvalue == 0)
334 	signal(SIGQUIT,k);
335 }
336 
337 static int
rddescf(char * descfile)338 rddescf(char *descfile)
339 {
340 static int firstrd = YES;
341 
342 /* read and parse description */
343 
344 if(firstrd)
345 	{
346 	firstrd = NO;
347 	if( !noruleflag )
348 		{
349 		rdarray(dfltmacro);
350 		if(oldflag)
351 			rdarray(dfltsuff);
352 		}
353 	if(!envlast)
354 		loadenv();
355 
356 	}
357 
358 return  parse(descfile);
359 }
360 
361 static void
rdarray(char ** s)362 rdarray(char **s)
363 {
364 linesptr = s;
365 parse(CHNULL);
366 }
367 
368 static void
loadenv(void)369 loadenv(void)
370 {
371 for(envpp = environ ; *envpp ; ++envpp)
372 	eqsign(*envpp);
373 envpp = NULL;
374 }
375 
376 static void
printdesc(int prntflag)377 printdesc(int prntflag)
378 {
379 nameblkp p;
380 depblkp dp;
381 struct varblock *vp;
382 struct dirhd *od;
383 struct shblock *sp;
384 lineblkp lp;
385 
386 if(prntflag)
387 	{
388 	printf("Open directories:\n");
389 	for (od = firstod; od; od = od->nxtdirhd)
390 		printf("\t%s\n", od->dirn);
391 	}
392 
393 if(firstvar != 0) printf("Macros:\n");
394 for(vp = firstvar; vp ; vp = vp->nxtvarblock)
395 	printf("\t%s = %s\n" , vp->varname , vp->varval ? vp->varval : "(null)");
396 
397 for(p = firstname; p; p = p->nxtnameblock)
398 	{
399 	printf("\n\n%s",p->namep);
400 	if(p->linep != 0) printf(":");
401 	if(prntflag) printf("  done=%d",p->done);
402 	if(p==mainname) printf("  (MAIN NAME)");
403 	for(lp = p->linep ; lp ; lp = lp->nxtlineblock)
404 		{
405 		if( dp = lp->depp )
406 			{
407 			printf("\n depends on:");
408 			for(; dp ; dp = dp->nxtdepblock)
409 				if(dp->depname != 0)
410 					printf(" %s ", dp->depname->namep);
411 			}
412 
413 		if(sp = lp->shp)
414 			{
415 			printf("\n commands:\n");
416 			for( ; sp ; sp = sp->nxtshblock)
417 				printf("\t%s\n", sp->shbp);
418 			}
419 		}
420 	}
421 printf("\n");
422 fflush(stdout);
423 }
424