mkmakefile.c revision 73199
1/*
2 * Copyright (c) 1993, 19801990
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35#if 0
36static char sccsid[] = "@(#)mkmakefile.c	8.1 (Berkeley) 6/6/93";
37#endif
38static const char rcsid[] =
39  "$FreeBSD: head/usr.sbin/config/mkmakefile.c 73199 2001-02-28 02:30:30Z peter $";
40#endif /* not lint */
41
42/*
43 * Build the makefile for the system, from
44 * the information in the files files and the
45 * additional files for the machine being compiled to.
46 */
47
48#include <ctype.h>
49#include <err.h>
50#include <stdio.h>
51#include <string.h>
52#include <sys/param.h>
53#include "y.tab.h"
54#include "config.h"
55#include "configvers.h"
56
57#define next_word(fp, wd) \
58	{ char *word = get_word(fp); \
59	  if (word == (char *)EOF) \
60		return; \
61	  else \
62		wd = word; \
63	}
64#define next_quoted_word(fp, wd) \
65	{ char *word = get_quoted_word(fp); \
66	  if (word == (char *)EOF) \
67		return; \
68	  else \
69		wd = word; \
70	}
71
72static struct file_list *fcur;
73
74static char *tail(char *);
75static void do_clean(FILE *);
76static void do_rules(FILE *);
77static void do_xxfiles(char *, FILE *);
78static void do_objs(FILE *);
79static void do_before_depend(FILE *);
80static int opteq(const char *, const char *);
81static void read_files(void);
82
83/*
84 * Lookup a file, by name.
85 */
86static struct file_list *
87fl_lookup(char *file)
88{
89	struct file_list *fp;
90
91	for (fp = ftab ; fp != 0; fp = fp->f_next) {
92		if (eq(fp->f_fn, file))
93			return (fp);
94	}
95	return (0);
96}
97
98/*
99 * Make a new file list entry
100 */
101static struct file_list *
102new_fent(void)
103{
104	struct file_list *fp;
105
106	fp = (struct file_list *) malloc(sizeof *fp);
107	bzero(fp, sizeof *fp);
108	if (fcur == 0)
109		fcur = ftab = fp;
110	else
111		fcur->f_next = fp;
112	fcur = fp;
113	return (fp);
114}
115
116/*
117 * Build the makefile from the skeleton
118 */
119void
120makefile(void)
121{
122	FILE *ifp, *ofp;
123	char line[BUFSIZ];
124	struct opt *op;
125	int versreq;
126	char *s;
127
128	read_files();
129	snprintf(line, sizeof(line), "../../conf/Makefile.%s", machinename);
130	ifp = fopen(line, "r");
131	if (ifp == 0) {
132		snprintf(line, sizeof(line), "Makefile.%s", machinename);
133		ifp = fopen(line, "r");
134	}
135	if (ifp == 0)
136		err(1, "%s", line);
137	ofp = fopen(path("Makefile.new"), "w");
138	if (ofp == 0)
139		err(1, "%s", path("Makefile.new"));
140	fprintf(ofp, "KERN_IDENT=%s\n", raisestr(ident));
141	fprintf(ofp, "IDENT=");
142	if (profiling)
143		fprintf(ofp, " -DGPROF");
144
145	if (cputype == 0) {
146		printf("cpu type must be specified\n");
147		exit(1);
148	}
149	fprintf(ofp, "\n");
150	for (op = mkopt; op; op = op->op_next)
151		fprintf(ofp, "%s=%s\n", op->op_name, op->op_value);
152	if (debugging)
153		fprintf(ofp, "DEBUG=-g\n");
154	if (profiling) {
155		fprintf(ofp, "PROF=-pg\n");
156		fprintf(ofp, "PROFLEVEL=%d\n", profiling);
157	}
158	if (*srcdir != '\0')
159		fprintf(ofp,"S=%s\n", srcdir);
160	while (fgets(line, BUFSIZ, ifp) != 0) {
161		if (*line != '%') {
162			fprintf(ofp, "%s", line);
163			continue;
164		}
165		if (eq(line, "%BEFORE_DEPEND\n"))
166			do_before_depend(ofp);
167		else if (eq(line, "%OBJS\n"))
168			do_objs(ofp);
169		else if (strncmp(line, "%FILES.", 7) == 0)
170			do_xxfiles(line, ofp);
171		else if (eq(line, "%RULES\n"))
172			do_rules(ofp);
173		else if (eq(line, "%CLEAN\n"))
174			do_clean(ofp);
175		else if (strncmp(line, "%VERSREQ=", sizeof("%VERSREQ=") - 1) == 0) {
176			versreq = atoi(line + sizeof("%VERSREQ=") - 1);
177			if (versreq != CONFIGVERS) {
178				fprintf(stderr, "ERROR: version of config(8) does not match kernel!\n");
179				fprintf(stderr, "config version = %d, ", CONFIGVERS);
180				fprintf(stderr, "version required = %d\n\n", versreq);
181				fprintf(stderr, "Make sure that /usr/src/usr.sbin/config is in sync\n");
182				fprintf(stderr, "with your /usr/src/sys and install a new config binary\n");
183				fprintf(stderr, "before trying this again.\n\n");
184				fprintf(stderr, "If running the new config fails check your config\n");
185				fprintf(stderr, "file against the GENERIC or LINT config files for\n");
186				fprintf(stderr, "changes in config syntax, or option/device naming\n");
187				fprintf(stderr, "conventions\n\n");
188				exit(1);
189			}
190		} else
191			fprintf(stderr,
192			    "Unknown %% construct in generic makefile: %s",
193			    line);
194	}
195	(void) fclose(ifp);
196	(void) fclose(ofp);
197	moveifchanged(path("Makefile.new"), path("Makefile"));
198
199	if (hints) {
200		ifp = fopen(hints, "r");
201		if (ifp == NULL)
202			err(1, "%s", hints);
203	} else {
204		ifp = NULL;
205	}
206	ofp = fopen(path("hints.c.new"), "w");
207	if (ofp == NULL)
208		err(1, "%s", path("hints.c.new"));
209	if (hintmode == 0) {
210		snprintf(line, sizeof(line), "%s.hints", PREFIX);
211		ifp = fopen(line, "r");
212		if (ifp)
213			hintmode = 2;
214	}
215	fprintf(ofp, "int hintmode = %d;\n", hintmode);
216	fprintf(ofp, "char static_hints[] = {\n");
217	if (ifp) {
218		while (fgets(line, BUFSIZ, ifp) != 0) {
219			/* zap trailing CR and/or LF */
220			while ((s = rindex(line, '\n')) != NULL)
221				*s = '\0';
222			while ((s = rindex(line, '\r')) != NULL)
223				*s = '\0';
224			/* remove # comments */
225			s = index(line, '#');
226			if (s)
227				*s = '\0';
228			/* remove any whitespace and " characters */
229			s = line;
230			while (*s) {
231				if (*s == ' ' || *s == '\t' || *s == '"') {
232					while (*s) {
233						s[0] = s[1];
234						s++;
235					}
236					/* start over */
237					s = line;
238					continue;
239				}
240				s++;
241			}
242			/* anything left? */
243			if (*line == '\0')
244				continue;
245			fprintf(ofp, "\"%s\\0\"\n", line);
246		}
247	}
248	fprintf(ofp, "\"\\0\"\n};\n");
249	if (ifp)
250		fclose(ifp);
251	fclose(ofp);
252	moveifchanged(path("hints.c.new"), path("hints.c"));
253}
254
255/*
256 * Read in the information about files used in making the system.
257 * Store it in the ftab linked list.
258 */
259static void
260read_files(void)
261{
262	FILE *fp;
263	struct file_list *tp, *pf;
264	struct device *dp;
265	struct opt *op;
266	char *wd, *this, *needs, *compilewith, *depends, *clean, *warning;
267	char fname[MAXPATHLEN];
268	int nreqs, first = 1, configdep, isdup, std, filetype,
269	    imp_rule, no_obj, needcount, before_depend, mandatory;
270
271	ftab = 0;
272	if (ident == NULL) {
273		printf("no ident line specified\n");
274		exit(1);
275	}
276	(void) snprintf(fname, sizeof(fname), "../../conf/files");
277openit:
278	fp = fopen(fname, "r");
279	if (fp == 0)
280		err(1, "%s", fname);
281next:
282	/*
283	 * filename    [ standard | mandatory | optional | count ]
284	 *	[ config-dependent ]
285	 *	[ dev* | profiling-routine ] [ no-obj ]
286	 *	[ compile-with "compile rule" [no-implicit-rule] ]
287	 *      [ dependency "dependency-list"] [ before-depend ]
288	 *	[ clean "file-list"] [ warning "text warning" ]
289	 */
290	wd = get_word(fp);
291	if (wd == (char *)EOF) {
292		(void) fclose(fp);
293		if (first == 1) {
294			first++;
295			(void) snprintf(fname, sizeof(fname),
296			    "../../conf/files.%s", machinename);
297			fp = fopen(fname, "r");
298			if (fp != 0)
299				goto next;
300			(void) snprintf(fname, sizeof(fname),
301			    "files.%s", machinename);
302			goto openit;
303		}
304		return;
305	}
306	if (wd == 0)
307		goto next;
308	if (wd[0] == '#')
309	{
310		while (((wd = get_word(fp)) != (char *)EOF) && wd)
311			;
312		goto next;
313	}
314	this = ns(wd);
315	next_word(fp, wd);
316	if (wd == 0) {
317		printf("%s: No type for %s.\n",
318		    fname, this);
319		exit(1);
320	}
321	if ((pf = fl_lookup(this)) && (pf->f_type != INVISIBLE || pf->f_flags))
322		isdup = ISDUP;
323	else
324		isdup = 0;
325	tp = 0;
326	nreqs = 0;
327	compilewith = 0;
328	depends = 0;
329	clean = 0;
330	warning = 0;
331	configdep = 0;
332	needs = 0;
333	std = mandatory = 0;
334	imp_rule = 0;
335	no_obj = 0;
336	needcount = 0;
337	before_depend = 0;
338	filetype = NORMAL;
339	if (eq(wd, "standard")) {
340		std = 1;
341	/*
342	 * If an entry is marked "mandatory", config will abort if it's
343	 * not called by a configuration line in the config file.  Apart
344	 * from this, the device is handled like one marked "optional".
345	 */
346	} else if (eq(wd, "mandatory")) {
347		mandatory = 1;
348	} else if (eq(wd, "count")) {
349		needcount = 1;
350	} else if (!eq(wd, "optional")) {
351		printf("%s: %s must be count, optional, mandatory or standard\n",
352		       fname, this);
353		exit(1);
354	}
355nextparam:
356	next_word(fp, wd);
357	if (wd == 0)
358		goto doneparam;
359	if (eq(wd, "config-dependent")) {
360		configdep++;
361		goto nextparam;
362	}
363	if (eq(wd, "no-obj")) {
364		no_obj++;
365		goto nextparam;
366	}
367	if (eq(wd, "no-implicit-rule")) {
368		if (compilewith == 0) {
369			printf("%s: alternate rule required when "
370			       "\"no-implicit-rule\" is specified.\n",
371			       fname);
372		}
373		imp_rule++;
374		goto nextparam;
375	}
376	if (eq(wd, "before-depend")) {
377		before_depend++;
378		goto nextparam;
379	}
380	if (eq(wd, "dependency")) {
381		next_quoted_word(fp, wd);
382		if (wd == 0) {
383			printf("%s: %s missing compile command string.\n",
384			       fname, this);
385			exit(1);
386		}
387		depends = ns(wd);
388		goto nextparam;
389	}
390	if (eq(wd, "clean")) {
391		next_quoted_word(fp, wd);
392		if (wd == 0) {
393			printf("%s: %s missing clean file list.\n",
394			       fname, this);
395			exit(1);
396		}
397		clean = ns(wd);
398		goto nextparam;
399	}
400	if (eq(wd, "compile-with")) {
401		next_quoted_word(fp, wd);
402		if (wd == 0) {
403			printf("%s: %s missing compile command string.\n",
404			       fname, this);
405			exit(1);
406		}
407		compilewith = ns(wd);
408		goto nextparam;
409	}
410	if (eq(wd, "warning")) {
411		next_quoted_word(fp, wd);
412		if (wd == 0) {
413			printf("%s: %s missing warning text string.\n",
414				fname, this);
415			exit(1);
416		}
417		warning = ns(wd);
418		goto nextparam;
419	}
420	nreqs++;
421	if (eq(wd, "local")) {
422		filetype = LOCAL;
423		goto nextparam;
424	}
425	if (eq(wd, "no-depend")) {
426		filetype = NODEPEND;
427		goto nextparam;
428	}
429	if (eq(wd, "profiling-routine")) {
430		filetype = PROFILING;
431		goto nextparam;
432	}
433	if (needs == 0 && nreqs == 1)
434		needs = ns(wd);
435	if (isdup)
436		goto invis;
437	for (dp = dtab; dp != 0; dp = dp->d_next)
438		if (eq(dp->d_name, wd)) {
439			if (std && dp->d_count <= 0)
440				dp->d_count = 1;
441			goto nextparam;
442		}
443	if (mandatory) {
444		printf("%s: mandatory device \"%s\" not found\n",
445		       fname, wd);
446		exit(1);
447	}
448	if (std) {
449		printf("standard entry %s has a device keyword - %s!\n",
450		       this, wd);
451		exit(1);
452	}
453	for (op = opt; op != 0; op = op->op_next)
454		if (op->op_value == 0 && opteq(op->op_name, wd)) {
455			if (nreqs == 1) {
456				free(needs);
457				needs = 0;
458			}
459			goto nextparam;
460		}
461invis:
462	while ((wd = get_word(fp)) != 0)
463		;
464	if (tp == 0)
465		tp = new_fent();
466	tp->f_fn = this;
467	tp->f_type = INVISIBLE;
468	tp->f_needs = needs;
469	tp->f_flags |= isdup;
470	if (needcount)
471		tp->f_flags |= NEED_COUNT;
472	tp->f_compilewith = compilewith;
473	tp->f_depends = depends;
474	tp->f_clean = clean;
475	tp->f_warn = warning;
476	goto next;
477
478doneparam:
479	if (std == 0 && nreqs == 0) {
480		printf("%s: what is %s optional on?\n",
481		    fname, this);
482		exit(1);
483	}
484
485	if (wd) {
486		printf("%s: syntax error describing %s\n",
487		    fname, this);
488		exit(1);
489	}
490	if (filetype == PROFILING && profiling == 0)
491		goto next;
492	if (tp == 0)
493		tp = new_fent();
494	tp->f_fn = this;
495	tp->f_type = filetype;
496	tp->f_flags &= ~ISDUP;
497	if (configdep)
498		tp->f_flags |= CONFIGDEP;
499	if (imp_rule)
500		tp->f_flags |= NO_IMPLCT_RULE;
501	if (no_obj)
502		tp->f_flags |= NO_OBJ;
503	if (before_depend)
504		tp->f_flags |= BEFORE_DEPEND;
505	if (imp_rule)
506		tp->f_flags |= NO_IMPLCT_RULE;
507	if (no_obj)
508		tp->f_flags |= NO_OBJ;
509	if (needcount)
510		tp->f_flags |= NEED_COUNT;
511	tp->f_needs = needs;
512	tp->f_compilewith = compilewith;
513	tp->f_depends = depends;
514	tp->f_clean = clean;
515	tp->f_warn = warning;
516	if (pf && pf->f_type == INVISIBLE)
517		pf->f_flags |= ISDUP;		/* mark as duplicate */
518	goto next;
519}
520
521static int
522opteq(const char *cp, const char *dp)
523{
524	char c, d;
525
526	for (; ; cp++, dp++) {
527		if (*cp != *dp) {
528			c = isupper(*cp) ? tolower(*cp) : *cp;
529			d = isupper(*dp) ? tolower(*dp) : *dp;
530			if (c != d)
531				return (0);
532		}
533		if (*cp == 0)
534			return (1);
535	}
536}
537
538static void
539do_before_depend(FILE *fp)
540{
541	struct file_list *tp;
542	int lpos, len;
543
544	fputs("BEFORE_DEPEND=", fp);
545	lpos = 15;
546	for (tp = ftab; tp; tp = tp->f_next)
547		if (tp->f_flags & BEFORE_DEPEND) {
548			len = strlen(tp->f_fn);
549			if ((len = 3 + len) + lpos > 72) {
550				lpos = 8;
551				fputs("\\\n\t", fp);
552			}
553			if (tp->f_flags & NO_IMPLCT_RULE)
554				fprintf(fp, "%s ", tp->f_fn);
555			else
556				fprintf(fp, "$S/%s ", tp->f_fn);
557			lpos += len + 1;
558		}
559	if (lpos != 8)
560		putc('\n', fp);
561}
562
563static void
564do_objs(FILE *fp)
565{
566	struct file_list *tp;
567	int lpos, len;
568	char *cp, och, *sp;
569
570	fprintf(fp, "OBJS=");
571	lpos = 6;
572	for (tp = ftab; tp != 0; tp = tp->f_next) {
573		if (tp->f_type == INVISIBLE || tp->f_flags & NO_OBJ)
574			continue;
575		sp = tail(tp->f_fn);
576		cp = sp + (len = strlen(sp)) - 1;
577		och = *cp;
578		*cp = 'o';
579		if (len + lpos > 72) {
580			lpos = 8;
581			fprintf(fp, "\\\n\t");
582		}
583		fprintf(fp, "%s ", sp);
584		lpos += len + 1;
585		*cp = och;
586	}
587	if (lpos != 8)
588		putc('\n', fp);
589}
590
591static void
592do_xxfiles(char *tag, FILE *fp)
593{
594	struct file_list *tp;
595	int lpos, len, slen;
596	char *suff, *SUFF;
597
598	if (tag[strlen(tag) - 1] == '\n')
599		tag[strlen(tag) - 1] = '\0';
600
601	suff = ns(tag + 7);
602	SUFF = ns(suff);
603	raisestr(SUFF);
604	slen = strlen(suff);
605
606	fprintf(fp, "%sFILES=", SUFF);
607	lpos = 8;
608	for (tp = ftab; tp; tp = tp->f_next)
609		if (tp->f_type != INVISIBLE && tp->f_type != NODEPEND) {
610			len = strlen(tp->f_fn);
611			if (tp->f_fn[len - slen - 1] != '.')
612				continue;
613			if (strcasecmp(&tp->f_fn[len - slen], suff) != 0)
614				continue;
615			if ((len = 3 + len) + lpos > 72) {
616				lpos = 8;
617				fputs("\\\n\t", fp);
618			}
619			if (tp->f_type != LOCAL)
620				fprintf(fp, "$S/%s ", tp->f_fn);
621			else
622				fprintf(fp, "%s ", tp->f_fn);
623			lpos += len + 1;
624		}
625	if (lpos != 8)
626		putc('\n', fp);
627}
628
629static char *
630tail(char *fn)
631{
632	char *cp;
633
634	cp = rindex(fn, '/');
635	if (cp == 0)
636		return (fn);
637	return (cp+1);
638}
639
640/*
641 * Create the makerules for each file
642 * which is part of the system.
643 */
644static void
645do_rules(FILE *f)
646{
647	char *cp, *np, och, *tp;
648	struct file_list *ftp;
649	char *compilewith;
650
651	for (ftp = ftab; ftp != 0; ftp = ftp->f_next) {
652		if (ftp->f_type == INVISIBLE)
653			continue;
654		if (ftp->f_warn)
655			printf("WARNING: %s\n", ftp->f_warn);
656		cp = (np = ftp->f_fn) + strlen(ftp->f_fn) - 1;
657		och = *cp;
658		if (ftp->f_flags & NO_IMPLCT_RULE) {
659			if (ftp->f_depends)
660				fprintf(f, "%s: %s\n", np, ftp->f_depends);
661			else
662				fprintf(f, "%s: \n", np);
663		}
664		else {
665			*cp = '\0';
666			if (och == 'o') {
667				fprintf(f, "%so:\n\t-cp $S/%so .\n\n",
668					tail(np), np);
669				continue;
670			}
671			if (ftp->f_depends)
672				fprintf(f, "%so: $S/%s%c %s\n", tail(np),
673					np, och, ftp->f_depends);
674			else
675				fprintf(f, "%so: $S/%s%c\n", tail(np),
676					np, och);
677		}
678		tp = tail(np);
679		compilewith = ftp->f_compilewith;
680		if (compilewith == 0) {
681			const char *ftype = NULL;
682			static char cmd[128];
683
684			switch (ftp->f_type) {
685
686			case NORMAL:
687				ftype = "NORMAL";
688				break;
689
690			case PROFILING:
691				if (!profiling)
692					continue;
693				ftype = "PROFILE";
694				break;
695
696			default:
697				printf("config: don't know rules for %s\n", np);
698				break;
699			}
700			(void)snprintf(cmd, sizeof(cmd), "${%s_%c%s}", ftype, toupper(och),
701				      ftp->f_flags & CONFIGDEP? "_C" : "");
702			compilewith = cmd;
703		}
704		*cp = och;
705		fprintf(f, "\t%s\n\n", compilewith);
706	}
707}
708
709static void
710do_clean(FILE *fp)
711{
712	struct file_list *tp;
713	int lpos, len;
714
715	fputs("CLEAN=", fp);
716	lpos = 7;
717	for (tp = ftab; tp; tp = tp->f_next)
718		if (tp->f_clean) {
719			len = strlen(tp->f_clean);
720			if (len + lpos > 72) {
721				lpos = 8;
722				fputs("\\\n\t", fp);
723			}
724			fprintf(fp, "%s ", tp->f_clean);
725			lpos += len + 1;
726		}
727	if (lpos != 8)
728		putc('\n', fp);
729}
730
731char *
732raisestr(char *str)
733{
734	char *cp = str;
735
736	while (*str) {
737		if (islower(*str))
738			*str = toupper(*str);
739		str++;
740	}
741	return (cp);
742}
743