xref: /original-bsd/usr.sbin/config/mkmakefile.c (revision 43bfbc1c)
1 /*
2  * Copyright (c) 1980 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 static char sccsid[] = "@(#)mkmakefile.c	5.8 (Berkeley) 05/03/86";
9 #endif not lint
10 
11 /*
12  * Build the makefile for the system, from
13  * the information in the files files and the
14  * additional files for the machine being compiled to.
15  */
16 
17 #include <stdio.h>
18 #include <ctype.h>
19 #include "y.tab.h"
20 #include "config.h"
21 
22 #define next_word(fp, wd) \
23 	{ register char *word = get_word(fp); \
24 	  if (word == (char *)EOF) \
25 		return; \
26 	  else \
27 		wd = word; \
28 	}
29 
30 static	struct file_list *fcur;
31 char *tail();
32 
33 /*
34  * Lookup a file, by name.
35  */
36 struct file_list *
37 fl_lookup(file)
38 	register char *file;
39 {
40 	register struct file_list *fp;
41 
42 	for (fp = ftab ; fp != 0; fp = fp->f_next) {
43 		if (eq(fp->f_fn, file))
44 			return (fp);
45 	}
46 	return (0);
47 }
48 
49 /*
50  * Lookup a file, by final component name.
51  */
52 struct file_list *
53 fltail_lookup(file)
54 	register char *file;
55 {
56 	register struct file_list *fp;
57 
58 	for (fp = ftab ; fp != 0; fp = fp->f_next) {
59 		if (eq(tail(fp->f_fn), tail(file)))
60 			return (fp);
61 	}
62 	return (0);
63 }
64 
65 /*
66  * Make a new file list entry
67  */
68 struct file_list *
69 new_fent()
70 {
71 	register struct file_list *fp;
72 
73 	fp = (struct file_list *) malloc(sizeof *fp);
74 	fp->f_needs = 0;
75 	fp->f_next = 0;
76 	fp->f_flags = 0;
77 	fp->f_type = 0;
78 	if (fcur == 0)
79 		fcur = ftab = fp;
80 	else
81 		fcur->f_next = fp;
82 	fcur = fp;
83 	return (fp);
84 }
85 
86 char	*COPTS;
87 static	struct users {
88 	int	u_default;
89 	int	u_min;
90 	int	u_max;
91 } users[] = {
92 	{ 24, 8, 1024 },		/* MACHINE_VAX */
93 };
94 #define	NUSERS	(sizeof (users) / sizeof (users[0]))
95 
96 /*
97  * Build the makefile from the skeleton
98  */
99 makefile()
100 {
101 	FILE *ifp, *ofp;
102 	char line[BUFSIZ];
103 	struct opt *op;
104 	struct users *up;
105 
106 	read_files();
107 	strcpy(line, "../conf/Makefile.");
108 	(void) strcat(line, machinename);
109 	ifp = fopen(line, "r");
110 	if (ifp == 0) {
111 		perror(line);
112 		exit(1);
113 	}
114 	ofp = fopen(path("Makefile"), "w");
115 	if (ofp == 0) {
116 		perror(path("Makefile"));
117 		exit(1);
118 	}
119 	fprintf(ofp, "IDENT=-D%s", raise(ident));
120 	if (profiling)
121 		fprintf(ofp, " -DGPROF");
122 	if (cputype == 0) {
123 		printf("cpu type must be specified\n");
124 		exit(1);
125 	}
126 	{ struct cputype *cp;
127 	  for (cp = cputype; cp; cp = cp->cpu_next)
128 		fprintf(ofp, " -D%s", cp->cpu_name);
129 	}
130 	for (op = opt; op; op = op->op_next)
131 		if (op->op_value)
132 			fprintf(ofp, " -D%s=\"%s\"", op->op_name, op->op_value);
133 		else
134 			fprintf(ofp, " -D%s", op->op_name);
135 	fprintf(ofp, "\n");
136 	if (hadtz == 0)
137 		printf("timezone not specified; gmt assumed\n");
138 	if ((unsigned)machine > NUSERS) {
139 		printf("maxusers config info isn't present, using vax\n");
140 		up = &users[MACHINE_VAX-1];
141 	} else
142 		up = &users[machine-1];
143 	if (maxusers == 0) {
144 		printf("maxusers not specified; %d assumed\n", up->u_default);
145 		maxusers = up->u_default;
146 	} else if (maxusers < up->u_min) {
147 		printf("minimum of %d maxusers assumed\n", up->u_min);
148 		maxusers = up->u_min;
149 	} else if (maxusers > up->u_max)
150 		printf("warning: maxusers > %d (%d)\n", up->u_max, maxusers);
151 	fprintf(ofp, "PARAM=-DTIMEZONE=%d -DDST=%d -DMAXUSERS=%d\n",
152 	    timezone, dst, maxusers);
153 	for (op = mkopt; op; op = op->op_next)
154 		fprintf(ofp, "%s=%s\n", op->op_name, op->op_value);
155 	while (fgets(line, BUFSIZ, ifp) != 0) {
156 		if (*line == '%')
157 			goto percent;
158 		if (profiling && strncmp(line, "COPTS=", 6) == 0) {
159 			register char *cp;
160 
161 			fprintf(ofp,
162 			    "GPROF.EX=/usr/src/lib/libc/%s/csu/gmon.ex\n",
163 			    machinename);
164 			cp = index(line, '\n');
165 			if (cp)
166 				*cp = 0;
167 			cp = line + 6;
168 			while (*cp && (*cp == ' ' || *cp == '\t'))
169 				cp++;
170 			COPTS = malloc((unsigned)(strlen(cp) + 1));
171 			if (COPTS == 0) {
172 				printf("config: out of memory\n");
173 				exit(1);
174 			}
175 			strcpy(COPTS, cp);
176 			fprintf(ofp, "%s -pg\n", line);
177 			continue;
178 		}
179 		fprintf(ofp, "%s", line);
180 		continue;
181 	percent:
182 		if (eq(line, "%OBJS\n"))
183 			do_objs(ofp);
184 		else if (eq(line, "%CFILES\n"))
185 			do_cfiles(ofp);
186 		else if (eq(line, "%RULES\n"))
187 			do_rules(ofp);
188 		else if (eq(line, "%LOAD\n"))
189 			do_load(ofp);
190 		else
191 			fprintf(stderr,
192 			    "Unknown %% construct in generic makefile: %s",
193 			    line);
194 	}
195 	(void) fclose(ifp);
196 	(void) fclose(ofp);
197 }
198 
199 /*
200  * Read in the information about files used in making the system.
201  * Store it in the ftab linked list.
202  */
203 read_files()
204 {
205 	FILE *fp;
206 	register struct file_list *tp, *pf;
207 	register struct device *dp;
208 	register struct opt *op;
209 	char *wd, *this, *needs, *devorprof;
210 	char fname[32];
211 	int nreqs, first = 1, configdep, isdup;
212 
213 	ftab = 0;
214 	(void) strcpy(fname, "files");
215 openit:
216 	fp = fopen(fname, "r");
217 	if (fp == 0) {
218 		perror(fname);
219 		exit(1);
220 	}
221 next:
222 	/*
223 	 * filename	[ standard | optional ] [ config-dependent ]
224 	 *	[ dev* | profiling-routine ] [ device-driver]
225 	 */
226 	wd = get_word(fp);
227 	if (wd == (char *)EOF) {
228 		(void) fclose(fp);
229 		if (first == 1) {
230 			(void) sprintf(fname, "files.%s", machinename);
231 			first++;
232 			goto openit;
233 		}
234 		if (first == 2) {
235 			(void) sprintf(fname, "files.%s", raise(ident));
236 			first++;
237 			fp = fopen(fname, "r");
238 			if (fp != 0)
239 				goto next;
240 		}
241 		return;
242 	}
243 	if (wd == 0)
244 		goto next;
245 	this = ns(wd);
246 	next_word(fp, wd);
247 	if (wd == 0) {
248 		printf("%s: No type for %s.\n",
249 		    fname, this);
250 		exit(1);
251 	}
252 	if ((pf = fl_lookup(this)) && (pf->f_type != INVISIBLE || pf->f_flags))
253 		isdup = 1;
254 	else
255 		isdup = 0;
256 	tp = 0;
257 	if (first == 3 && (tp = fltail_lookup(this)) != 0)
258 		printf("%s: Local file %s overrides %s.\n",
259 		    fname, this, tp->f_fn);
260 	nreqs = 0;
261 	devorprof = "";
262 	configdep = 0;
263 	needs = 0;
264 	if (eq(wd, "standard"))
265 		goto checkdev;
266 	if (!eq(wd, "optional")) {
267 		printf("%s: %s must be optional or standard\n", fname, this);
268 		exit(1);
269 	}
270 nextopt:
271 	next_word(fp, wd);
272 	if (wd == 0)
273 		goto doneopt;
274 	if (eq(wd, "config-dependent")) {
275 		configdep++;
276 		goto nextopt;
277 	}
278 	devorprof = wd;
279 	if (eq(wd, "device-driver") || eq(wd, "profiling-routine")) {
280 		next_word(fp, wd);
281 		goto save;
282 	}
283 	nreqs++;
284 	if (needs == 0 && nreqs == 1)
285 		needs = ns(wd);
286 	if (isdup)
287 		goto invis;
288 	for (dp = dtab; dp != 0; dp = dp->d_next)
289 		if (eq(dp->d_name, wd))
290 			goto nextopt;
291 	for (op = opt; op != 0; op = op->op_next)
292 		if (op->op_value == 0 && opteq(op->op_name, wd)) {
293 			if (nreqs == 1) {
294 				free(needs);
295 				needs = 0;
296 			}
297 			goto nextopt;
298 		}
299 invis:
300 	while ((wd = get_word(fp)) != 0)
301 		;
302 	if (tp == 0)
303 		tp = new_fent();
304 	tp->f_fn = this;
305 	tp->f_type = INVISIBLE;
306 	tp->f_needs = needs;
307 	tp->f_flags = isdup;
308 	goto next;
309 
310 doneopt:
311 	if (nreqs == 0) {
312 		printf("%s: what is %s optional on?\n",
313 		    fname, this);
314 		exit(1);
315 	}
316 
317 checkdev:
318 	if (wd) {
319 		next_word(fp, wd);
320 		if (wd) {
321 			if (eq(wd, "config-dependent")) {
322 				configdep++;
323 				goto checkdev;
324 			}
325 			devorprof = wd;
326 			next_word(fp, wd);
327 		}
328 	}
329 
330 save:
331 	if (wd) {
332 		printf("%s: syntax error describing %s\n",
333 		    fname, this);
334 		exit(1);
335 	}
336 	if (eq(devorprof, "profiling-routine") && profiling == 0)
337 		goto next;
338 	if (tp == 0)
339 		tp = new_fent();
340 	tp->f_fn = this;
341 	if (eq(devorprof, "device-driver"))
342 		tp->f_type = DRIVER;
343 	else if (eq(devorprof, "profiling-routine"))
344 		tp->f_type = PROFILING;
345 	else
346 		tp->f_type = NORMAL;
347 	tp->f_flags = 0;
348 	if (configdep)
349 		tp->f_flags |= CONFIGDEP;
350 	tp->f_needs = needs;
351 	if (pf && pf->f_type == INVISIBLE)
352 		pf->f_flags = 1;		/* mark as duplicate */
353 	goto next;
354 }
355 
356 opteq(cp, dp)
357 	char *cp, *dp;
358 {
359 	char c, d;
360 
361 	for (; ; cp++, dp++) {
362 		if (*cp != *dp) {
363 			c = isupper(*cp) ? tolower(*cp) : *cp;
364 			d = isupper(*dp) ? tolower(*dp) : *dp;
365 			if (c != d)
366 				return (0);
367 		}
368 		if (*cp == 0)
369 			return (1);
370 	}
371 }
372 
373 do_objs(fp)
374 	FILE *fp;
375 {
376 	register struct file_list *tp, *fl;
377 	register int lpos, len;
378 	register char *cp, och, *sp;
379 	char swapname[32];
380 
381 	fprintf(fp, "OBJS=");
382 	lpos = 6;
383 	for (tp = ftab; tp != 0; tp = tp->f_next) {
384 		if (tp->f_type == INVISIBLE)
385 			continue;
386 		sp = tail(tp->f_fn);
387 		for (fl = conf_list; fl; fl = fl->f_next) {
388 			if (fl->f_type != SWAPSPEC)
389 				continue;
390 			sprintf(swapname, "swap%s.c", fl->f_fn);
391 			if (eq(sp, swapname))
392 				goto cont;
393 		}
394 		cp = sp + (len = strlen(sp)) - 1;
395 		och = *cp;
396 		*cp = 'o';
397 		if (len + lpos > 72) {
398 			lpos = 8;
399 			fprintf(fp, "\\\n\t");
400 		}
401 		fprintf(fp, "%s ", sp);
402 		lpos += len + 1;
403 		*cp = och;
404 cont:
405 		;
406 	}
407 	if (lpos != 8)
408 		putc('\n', fp);
409 }
410 
411 do_cfiles(fp)
412 	FILE *fp;
413 {
414 	register struct file_list *tp;
415 	register int lpos, len;
416 
417 	fprintf(fp, "CFILES=");
418 	lpos = 8;
419 	for (tp = ftab; tp != 0; tp = tp->f_next) {
420 		if (tp->f_type == INVISIBLE)
421 			continue;
422 		if (tp->f_fn[strlen(tp->f_fn)-1] != 'c')
423 			continue;
424 		if ((len = 3 + strlen(tp->f_fn)) + lpos > 72) {
425 			lpos = 8;
426 			fprintf(fp, "\\\n\t");
427 		}
428 		fprintf(fp, "../%s ", tp->f_fn);
429 		lpos += len + 1;
430 	}
431 	if (lpos != 8)
432 		putc('\n', fp);
433 }
434 
435 char *
436 tail(fn)
437 	char *fn;
438 {
439 	register char *cp;
440 
441 	cp = rindex(fn, '/');
442 	if (cp == 0)
443 		return (fn);
444 	return (cp+1);
445 }
446 
447 /*
448  * Create the makerules for each file
449  * which is part of the system.
450  * Devices are processed with the special c2 option -i
451  * which avoids any problem areas with i/o addressing
452  * (e.g. for the VAX); assembler files are processed by as.
453  */
454 do_rules(f)
455 	FILE *f;
456 {
457 	register char *cp, *np, och, *tp;
458 	register struct file_list *ftp;
459 	char *extras;
460 
461 for (ftp = ftab; ftp != 0; ftp = ftp->f_next) {
462 	if (ftp->f_type == INVISIBLE)
463 		continue;
464 	cp = (np = ftp->f_fn) + strlen(ftp->f_fn) - 1;
465 	och = *cp;
466 	*cp = '\0';
467 	if (och == 'o') {
468 		fprintf(f, "%so:\n\t-cp ../%so .\n", tail(np), np);
469 		continue;
470 	}
471 	fprintf(f, "%so: ../%s%c\n", tail(np), np, och);
472 	tp = tail(np);
473 	if (och == 's') {
474 		fprintf(f, "\t-ln -s ../%ss %sc\n", np, tp);
475 		fprintf(f, "\t${CC} -E ${COPTS} %sc | ${AS} -o %so\n",
476 			tp, tp);
477 		fprintf(f, "\trm -f %sc\n\n", tp);
478 		continue;
479 	}
480 	if (ftp->f_flags & CONFIGDEP)
481 		extras = "${PARAM} ";
482 	else
483 		extras = "";
484 	switch (ftp->f_type) {
485 
486 	case NORMAL:
487 		switch (machine) {
488 
489 		case MACHINE_VAX:
490 			fprintf(f, "\t${CC} -c -S ${COPTS} %s../%sc\n",
491 				extras, np);
492 			fprintf(f, "\t${C2} %ss | ${INLINE} | ${AS} -o %so\n",
493 			    tp, tp);
494 			fprintf(f, "\trm -f %ss\n\n", tp);
495 			break;
496 		}
497 		break;
498 
499 	case DRIVER:
500 		switch (machine) {
501 
502 		case MACHINE_VAX:
503 			fprintf(f, "\t${CC} -c -S ${COPTS} %s../%sc\n",
504 				extras, np);
505 			fprintf(f,"\t${C2} -i %ss | ${INLINE} | ${AS} -o %so\n",
506 			    tp, tp);
507 			fprintf(f, "\trm -f %ss\n\n", tp);
508 			break;
509 		}
510 		break;
511 
512 	case PROFILING:
513 		if (!profiling)
514 			continue;
515 		if (COPTS == 0) {
516 			fprintf(stderr,
517 			    "config: COPTS undefined in generic makefile");
518 			COPTS = "";
519 		}
520 		switch (machine) {
521 
522 		case MACHINE_VAX:
523 			fprintf(f, "\t${CC} -c -S %s %s../%sc\n",
524 				COPTS, extras, np);
525 			fprintf(f, "\tex - %ss < ${GPROF.EX}\n", tp);
526 			fprintf(f, "\t${INLINE} %ss | ${AS} -o %so\n", tp, tp);
527 			fprintf(f, "\trm -f %ss\n\n", tp);
528 			break;
529 		}
530 		break;
531 
532 	default:
533 		printf("Don't know rules for %s\n", np);
534 		break;
535 	}
536 	*cp = och;
537 }
538 }
539 
540 /*
541  * Create the load strings
542  */
543 do_load(f)
544 	register FILE *f;
545 {
546 	register struct file_list *fl;
547 	int first = 1;
548 	struct file_list *do_systemspec();
549 
550 	fl = conf_list;
551 	while (fl) {
552 		if (fl->f_type != SYSTEMSPEC) {
553 			fl = fl->f_next;
554 			continue;
555 		}
556 		fl = do_systemspec(f, fl, first);
557 		if (first)
558 			first = 0;
559 	}
560 	fprintf(f, "all:");
561 	for (fl = conf_list; fl != 0; fl = fl->f_next)
562 		if (fl->f_type == SYSTEMSPEC)
563 			fprintf(f, " %s", fl->f_needs);
564 	fprintf(f, "\n");
565 }
566 
567 struct file_list *
568 do_systemspec(f, fl, first)
569 	FILE *f;
570 	register struct file_list *fl;
571 	int first;
572 {
573 
574 	fprintf(f, "%s: Makefile", fl->f_needs);
575 	if (machine == MACHINE_VAX)
576 		fprintf(f, " ${INLINECMD}", machinename);
577 	fprintf(f, " locore.o ${OBJS} param.o ioconf.o swap%s.o\n", fl->f_fn);
578 	fprintf(f, "\t@echo loading %s\n\t@rm -f %s\n",
579 	    fl->f_needs, fl->f_needs);
580 	if (first) {
581 		fprintf(f, "\t@sh ../conf/newvers.sh\n");
582 		fprintf(f, "\t@${CC} $(CFLAGS) -c vers.c\n");
583 	}
584 	switch (machine) {
585 
586 	case MACHINE_VAX:
587 		fprintf(f, "\t@${LD} -n -o %s -e start -x -T 80000000 ",
588 			fl->f_needs);
589 		break;
590 	}
591 	fprintf(f, "locore.o ${OBJS} vers.o ioconf.o param.o ");
592 	fprintf(f, "swap%s.o\n", fl->f_fn);
593 	fprintf(f, "\t@echo rearranging symbols\n");
594 	fprintf(f, "\t@-symorder ../%s/symbols.sort %s\n",
595 	    machinename, fl->f_needs);
596 	fprintf(f, "\t@size %s\n", fl->f_needs);
597 	fprintf(f, "\t@chmod 755 %s\n\n", fl->f_needs);
598 	do_swapspec(f, fl->f_fn);
599 	for (fl = fl->f_next; fl->f_type == SWAPSPEC; fl = fl->f_next)
600 		;
601 	return (fl);
602 }
603 
604 do_swapspec(f, name)
605 	FILE *f;
606 	register char *name;
607 {
608 
609 	if (!eq(name, "generic")) {
610 		fprintf(f, "swap%s.o: swap%s.c\n", name, name);
611 		fprintf(f, "\t${CC} -c -O ${COPTS} swap%s.c\n\n", name);
612 		return;
613 	}
614 	fprintf(f, "swapgeneric.o: ../%s/swapgeneric.c\n", machinename);
615 	switch (machine) {
616 
617 	case MACHINE_VAX:
618 		fprintf(f, "\t${CC} -c -S ${COPTS} ");
619 		fprintf(f, "../%s/swapgeneric.c\n", machinename);
620 		fprintf(f, "\t${C2} swapgeneric.s | ${INLINE}");
621 		fprintf(f, " | ${AS} -o swapgeneric.o\n");
622 		fprintf(f, "\trm -f swapgeneric.s\n\n");
623 		break;
624 	}
625 }
626 
627 char *
628 raise(str)
629 	register char *str;
630 {
631 	register char *cp = str;
632 
633 	while (*str) {
634 		if (islower(*str))
635 			*str = toupper(*str);
636 		str++;
637 	}
638 	return (cp);
639 }
640