mkmakefile.c revision 1.4 1 /* $NetBSD: mkmakefile.c,v 1.4 2006/03/19 16:27:13 cube Exp $ */
2
3 /*
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This software was developed by the Computer Systems Engineering group
8 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
9 * contributed to Berkeley.
10 *
11 * All advertising materials mentioning features or use of this software
12 * must display the following acknowledgement:
13 * This product includes software developed by the University of
14 * California, Lawrence Berkeley Laboratories.
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 * 1. Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution.
24 * 3. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 *
40 * from: @(#)mkmakefile.c 8.1 (Berkeley) 6/6/93
41 */
42
43 #if HAVE_NBTOOL_CONFIG_H
44 #include "nbtool_config.h"
45 #endif
46
47 #include <sys/param.h>
48 #include <ctype.h>
49 #include <errno.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include "defs.h"
54 #include "sem.h"
55
56 /*
57 * Make the Makefile.
58 */
59
60 static const char *srcpath(struct files *);
61
62 static const char *prefix_prologue(const char *);
63 static const char *filetype_prologue(struct filetype *);
64
65
66 static int emitdefs(FILE *);
67 static int emitfiles(FILE *, int, int);
68
69 static int emitobjs(FILE *);
70 static int emitcfiles(FILE *);
71 static int emitsfiles(FILE *);
72 static int emitrules(FILE *);
73 static int emitload(FILE *);
74 static int emitincludes(FILE *);
75 static int emitappmkoptions(FILE *);
76
77 int
78 mkmakefile(void)
79 {
80 FILE *ifp, *ofp;
81 int lineno;
82 int (*fn)(FILE *);
83 char *ifname;
84 char line[BUFSIZ], buf[200];
85
86 /* Try a makefile for the port first.
87 */
88 (void)snprintf(buf, sizeof(buf), "arch/%s/conf/Makefile.%s",
89 machine, machine);
90 ifname = sourcepath(buf);
91 if ((ifp = fopen(ifname, "r")) == NULL) {
92 /* Try a makefile for the architecture second.
93 */
94 (void)snprintf(buf, sizeof(buf), "arch/%s/conf/Makefile.%s",
95 machinearch, machinearch);
96 free(ifname);
97 ifname = sourcepath(buf);
98 ifp = fopen(ifname, "r");
99 }
100 if (ifp == NULL) {
101 (void)fprintf(stderr, "config: cannot read %s: %s\n",
102 ifname, strerror(errno));
103 goto bad2;
104 }
105 if ((ofp = fopen("Makefile.tmp", "w")) == NULL) {
106 (void)fprintf(stderr, "config: cannot write Makefile: %s\n",
107 strerror(errno));
108 goto bad1;
109 }
110 if (emitdefs(ofp) != 0)
111 goto wrerror;
112 lineno = 0;
113 while (fgets(line, sizeof(line), ifp) != NULL) {
114 lineno++;
115 if (line[0] != '%') {
116 if (fputs(line, ofp) < 0)
117 goto wrerror;
118 continue;
119 }
120 if (strcmp(line, "%OBJS\n") == 0)
121 fn = emitobjs;
122 else if (strcmp(line, "%CFILES\n") == 0)
123 fn = emitcfiles;
124 else if (strcmp(line, "%SFILES\n") == 0)
125 fn = emitsfiles;
126 else if (strcmp(line, "%RULES\n") == 0)
127 fn = emitrules;
128 else if (strcmp(line, "%LOAD\n") == 0)
129 fn = emitload;
130 else if (strcmp(line, "%INCLUDES\n") == 0)
131 fn = emitincludes;
132 else if (strcmp(line, "%MAKEOPTIONSAPPEND\n") == 0)
133 fn = emitappmkoptions;
134 else {
135 xerror(ifname, lineno,
136 "unknown %% construct ignored: %s", line);
137 continue;
138 }
139 if ((*fn)(ofp))
140 goto wrerror;
141 }
142 if (ferror(ifp)) {
143 (void)fprintf(stderr,
144 "config: error reading %s (at line %d): %s\n",
145 ifname, lineno, strerror(errno));
146 goto bad;
147 }
148 if (fclose(ofp)) {
149 ofp = NULL;
150 goto wrerror;
151 }
152 (void)fclose(ifp);
153 if (moveifchanged("Makefile.tmp", "Makefile") != 0) {
154 (void)fprintf(stderr,
155 "config: error renaming Makefile: %s\n",
156 strerror(errno));
157 goto bad2;
158 }
159 free(ifname);
160 return (0);
161
162 wrerror:
163 (void)fprintf(stderr, "config: error writing Makefile: %s\n",
164 strerror(errno));
165 bad:
166 if (ofp != NULL)
167 (void)fclose(ofp);
168 bad1:
169 (void)fclose(ifp);
170 /* (void)unlink("Makefile.tmp"); */
171 bad2:
172 free(ifname);
173 return (1);
174 }
175
176 /*
177 * Return (possibly in a static buffer) the name of the `source' for a
178 * file. If we have `options source', or if the file is marked `always
179 * source', this is always the path from the `file' line; otherwise we
180 * get the .o from the obj-directory.
181 */
182 static const char *
183 srcpath(struct files *fi)
184 {
185 #if 1
186 /* Always have source, don't support object dirs for kernel builds. */
187 return (fi->fi_path);
188 #else
189 static char buf[MAXPATHLEN];
190
191 if (have_source || (fi->fi_flags & FI_ALWAYSSRC) != 0)
192 return (fi->fi_path);
193 if (objpath == NULL) {
194 error("obj-directory not set");
195 return (NULL);
196 }
197 (void)snprintf(buf, sizeof buf, "%s/%s.o", objpath, fi->fi_base);
198 return (buf);
199 #endif
200 }
201
202 static const char *
203 filetype_prologue(struct filetype *fit)
204 {
205 if (fit->fit_flags & FIT_NOPROLOGUE || *fit->fit_path == '/')
206 return ("");
207 else
208 return ("$S/");
209 }
210
211 static const char *
212 prefix_prologue(const char *path)
213 {
214 if (*path == '/')
215 return ("");
216 else
217 return ("$S/");
218 }
219
220 static int
221 emitdefs(FILE *fp)
222 {
223 struct nvlist *nv;
224 char *sp;
225
226 if (fprintf(fp, "KERNEL_BUILD=%s\n", conffile) < 0)
227 return (1);
228 if (fputs("IDENT=", fp) < 0)
229 return (1);
230 sp = "";
231 for (nv = options; nv != NULL; nv = nv->nv_next) {
232
233 /* skip any options output to a header file */
234 if (DEFINED_OPTION(nv->nv_name))
235 continue;
236 if (fprintf(fp, "%s-D%s", sp, nv->nv_name) < 0)
237 return 1;
238 if (nv->nv_str)
239 if (fprintf(fp, "=\"%s\"", nv->nv_str) < 0)
240 return 1;
241 sp = " ";
242 }
243 if (putc('\n', fp) < 0)
244 return (1);
245 if (fprintf(fp, "PARAM=-DMAXUSERS=%d\n", maxusers) < 0)
246 return (1);
247 if (fprintf(fp, "MACHINE=%s\n", machine) < 0)
248 return (1);
249 if (*srcdir == '/' || *srcdir == '.') {
250 if (fprintf(fp, "S=\t%s\n", srcdir) < 0)
251 return (1);
252 } else {
253 /*
254 * libkern and libcompat "Makefile.inc"s want relative S
255 * specification to begin with '.'.
256 */
257 if (fprintf(fp, "S=\t./%s\n", srcdir) < 0)
258 return (1);
259 }
260 for (nv = mkoptions; nv != NULL; nv = nv->nv_next)
261 if (fprintf(fp, "%s=%s\n", nv->nv_name, nv->nv_str) < 0)
262 return (1);
263 return (0);
264 }
265
266 static int
267 emitobjs(FILE *fp)
268 {
269 struct files *fi;
270 struct objects *oi;
271 int lpos, len, sp;
272
273 if (fputs("OBJS=", fp) < 0)
274 return (1);
275 sp = '\t';
276 lpos = 7;
277 TAILQ_FOREACH(fi, &allfiles, fi_next) {
278 if ((fi->fi_flags & FI_SEL) == 0)
279 continue;
280 len = strlen(fi->fi_base) + 2;
281 if (lpos + len > 72) {
282 if (fputs(" \\\n", fp) < 0)
283 return (1);
284 sp = '\t';
285 lpos = 7;
286 }
287 if (fprintf(fp, "%c%s.o", sp, fi->fi_base) < 0)
288 return (1);
289 lpos += len + 1;
290 sp = ' ';
291 }
292 TAILQ_FOREACH(oi, &allobjects, oi_next) {
293 if ((oi->oi_flags & OI_SEL) == 0)
294 continue;
295 len = strlen(oi->oi_path);
296 if (*oi->oi_path != '/')
297 {
298 /* e.g. "$S/" */
299 if (oi->oi_prefix != NULL)
300 len += strlen(prefix_prologue(oi->oi_path)) +
301 strlen(oi->oi_prefix) + 1;
302 else
303 len += strlen(filetype_prologue(&oi->oi_fit));
304 }
305 if (lpos + len > 72) {
306 if (fputs(" \\\n", fp) < 0)
307 return (1);
308 sp = '\t';
309 lpos = 7;
310 }
311 if (*oi->oi_path == '/') {
312 if (fprintf(fp, "%c%s", sp, oi->oi_path) < 0)
313 return (1);
314 } else {
315 if (oi->oi_prefix != NULL) {
316 if (fprintf(fp, "%c%s%s/%s", sp,
317 prefix_prologue(oi->oi_path),
318 oi->oi_prefix, oi->oi_path) < 0)
319 return (1);
320 } else {
321 if (fprintf(fp, "%c%s%s", sp,
322 filetype_prologue(&oi->oi_fit),
323 oi->oi_path) < 0)
324 return (1);
325 }
326 }
327 lpos += len + 1;
328 sp = ' ';
329 }
330 if (putc('\n', fp) < 0)
331 return (1);
332 return (0);
333 }
334
335 static int
336 emitcfiles(FILE *fp)
337 {
338
339 return (emitfiles(fp, 'c', 0));
340 }
341
342 static int
343 emitsfiles(FILE *fp)
344 {
345
346 return (emitfiles(fp, 's', 1));
347 }
348
349 static int
350 emitfiles(FILE *fp, int suffix, int upper_suffix)
351 {
352 struct files *fi;
353 int lpos, len, sp;
354 const char *fpath;
355 struct config *cf;
356 char swapname[100];
357
358 if (fprintf(fp, "%cFILES=", toupper(suffix)) < 0)
359 return (1);
360 sp = '\t';
361 lpos = 7;
362 TAILQ_FOREACH(fi, &allfiles, fi_next) {
363 if ((fi->fi_flags & FI_SEL) == 0)
364 continue;
365 if ((fpath = srcpath(fi)) == NULL)
366 return (1);
367 len = strlen(fpath);
368 if (! ((fpath[len - 1] == suffix) ||
369 (upper_suffix && fpath[len - 1] == toupper(suffix))))
370 continue;
371 if (*fpath != '/')
372 {
373 /* "$S/" */
374 if (fi->fi_prefix != NULL)
375 len += strlen(prefix_prologue(fi->fi_prefix)) +
376 strlen(fi->fi_prefix) + 1;
377 else
378 len += strlen(filetype_prologue(&fi->fi_fit));
379 }
380 if (lpos + len > 72) {
381 if (fputs(" \\\n", fp) < 0)
382 return (1);
383 sp = '\t';
384 lpos = 7;
385 }
386 if (*fi->fi_path == '/') {
387 if (fprintf(fp, "%c%s", sp, fpath) < 0)
388 return (1);
389 } else {
390 if (fi->fi_prefix != NULL) {
391 if (fprintf(fp, "%c%s%s/%s", sp,
392 prefix_prologue(fi->fi_prefix),
393 fi->fi_prefix, fpath) < 0)
394 return (1);
395 } else {
396 if (fprintf(fp, "%c%s%s", sp,
397 filetype_prologue(&fi->fi_fit),
398 fpath) < 0)
399 return (1);
400 }
401 }
402 lpos += len + 1;
403 sp = ' ';
404 }
405 /*
406 * The allfiles list does not include the configuration-specific
407 * C source files. These files should be eliminated someday, but
408 * for now, we have to add them to ${CFILES} (and only ${CFILES}).
409 */
410 if (suffix == 'c') {
411 TAILQ_FOREACH(cf, &allcf, cf_next) {
412 (void)snprintf(swapname, sizeof(swapname), "swap%s.c",
413 cf->cf_name);
414 len = strlen(swapname);
415 if (lpos + len > 72) {
416 if (fputs(" \\\n", fp) < 0)
417 return (1);
418 sp = '\t';
419 lpos = 7;
420 }
421 if (fprintf(fp, "%c%s", sp, swapname) < 0)
422 return (1);
423 lpos += len + 1;
424 sp = ' ';
425 }
426 }
427 if (putc('\n', fp) < 0)
428 return (1);
429 return (0);
430 }
431
432 /*
433 * Emit the make-rules.
434 */
435 static int
436 emitrules(FILE *fp)
437 {
438 struct files *fi;
439 const char *cp, *fpath;
440 int ch;
441 char buf[200];
442
443 TAILQ_FOREACH(fi, &allfiles, fi_next) {
444 if ((fi->fi_flags & FI_SEL) == 0)
445 continue;
446 if ((fpath = srcpath(fi)) == NULL)
447 return (1);
448 if (*fpath == '/') {
449 if (fprintf(fp, "%s.o: %s\n", fi->fi_base, fpath) < 0)
450 return (1);
451 } else {
452 if (fi->fi_prefix != NULL) {
453 if (fprintf(fp, "%s.o: %s%s/%s\n", fi->fi_base,
454 prefix_prologue(fi->fi_prefix),
455 fi->fi_prefix, fpath) < 0)
456 return (1);
457 } else {
458 if (fprintf(fp, "%s.o: %s%s\n",
459 fi->fi_base,
460 filetype_prologue(&fi->fi_fit),
461 fpath) < 0)
462 return (1);
463 }
464 }
465 if ((cp = fi->fi_mkrule) == NULL) {
466 cp = "NORMAL";
467 ch = fpath[strlen(fpath) - 1];
468 if (islower(ch))
469 ch = toupper(ch);
470 (void)snprintf(buf, sizeof(buf), "${%s_%c}", cp, ch);
471 cp = buf;
472 }
473 if (fprintf(fp, "\t%s\n\n", cp) < 0)
474 return (1);
475 }
476 return (0);
477 }
478
479 /*
480 * Emit the load commands.
481 *
482 * This function is not to be called `spurt'.
483 */
484 static int
485 emitload(FILE *fp)
486 {
487 struct config *cf;
488 const char *nm, *swname;
489
490 if (fputs(".MAIN: all\nall:", fp) < 0)
491 return (1);
492 TAILQ_FOREACH(cf, &allcf, cf_next) {
493 if (fprintf(fp, " %s", cf->cf_name) < 0)
494 return (1);
495 }
496 if (fputs("\n\n", fp) < 0)
497 return (1);
498 TAILQ_FOREACH(cf, &allcf, cf_next) {
499 nm = cf->cf_name;
500 swname =
501 cf->cf_root != NULL ? cf->cf_name : "generic";
502 if (fprintf(fp, "KERNELS+=%s\n", nm) < 0)
503 return (1);
504 if (fprintf(fp, "%s: ${SYSTEM_DEP} swap${.TARGET}.o vers.o", nm) < 0)
505 return (1);
506 if (fprintf(fp, "\n\
507 \t${SYSTEM_LD_HEAD}\n\
508 \t${SYSTEM_LD} swap${.TARGET}.o\n\
509 \t${SYSTEM_LD_TAIL}\n\
510 \n\
511 swap%s.o: swap%s.c\n\
512 \t${NORMAL_C}\n\n", swname, swname) < 0)
513 return (1);
514 }
515 return (0);
516 }
517
518 /*
519 * Emit include headers (for any prefixes encountered)
520 */
521 static int
522 emitincludes(FILE *fp)
523 {
524 struct prefix *pf;
525
526 SLIST_FOREACH(pf, &allprefixes, pf_next) {
527 if (fprintf(fp, "EXTRA_INCLUDES+=\t-I%s%s\n",
528 prefix_prologue(pf->pf_prefix), pf->pf_prefix) < 0)
529 return (1);
530 }
531
532 return (0);
533 }
534
535 static int
536 print_condmkopts(const char *name, void *value, void *arg)
537 {
538 struct nvlist *nv;
539 FILE *fp = arg;
540
541 if (ht_lookup(selecttab, name) == 0)
542 return (0);
543
544 for (nv = value; nv != NULL; nv = nv->nv_next)
545 if (fprintf(fp, "%s+=%s\n", nv->nv_name, nv->nv_str) < 0)
546 return (1);
547
548 return (0);
549 }
550
551 /*
552 * Emit appending makeoptions.
553 */
554 static int
555 emitappmkoptions(FILE *fp)
556 {
557 struct nvlist *nv;
558
559 for (nv = appmkoptions; nv != NULL; nv = nv->nv_next)
560 if (fprintf(fp, "%s+=%s\n", nv->nv_name, nv->nv_str) < 0)
561 return (1);
562
563 return (ht_enumerate(condmkopttab, print_condmkopts, fp));
564 }
565