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