Home | History | Annotate | Line # | Download | only in config
mkmakefile.c revision 1.1
      1 /*	$NetBSD: mkmakefile.c,v 1.1 2005/06/05 18:19:53 thorpej 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 
     64 static int emitdefs(FILE *);
     65 static int emitfiles(FILE *, int, int);
     66 
     67 static int emitobjs(FILE *);
     68 static int emitcfiles(FILE *);
     69 static int emitsfiles(FILE *);
     70 static int emitrules(FILE *);
     71 static int emitload(FILE *);
     72 static int emitincludes(FILE *);
     73 static int emitappmkoptions(FILE *);
     74 
     75 int
     76 mkmakefile(void)
     77 {
     78 	FILE *ifp, *ofp;
     79 	int lineno;
     80 	int (*fn)(FILE *);
     81 	char *ifname;
     82 	char line[BUFSIZ], buf[200];
     83 
     84 	/* Try a makefile for the port first.
     85 	 */
     86 	(void)snprintf(buf, sizeof(buf), "arch/%s/conf/Makefile.%s",
     87 	    machine, machine);
     88 	ifname = sourcepath(buf);
     89 	if ((ifp = fopen(ifname, "r")) == NULL) {
     90 		/* Try a makefile for the architecture second.
     91 		 */
     92 		(void)snprintf(buf, sizeof(buf), "arch/%s/conf/Makefile.%s",
     93 		    machinearch, machinearch);
     94 		ifname = sourcepath(buf);
     95 	}
     96 	if ((ifp = fopen(ifname, "r")) == NULL) {
     97 		(void)fprintf(stderr, "config: cannot read %s: %s\n",
     98 		    ifname, strerror(errno));
     99 		free(ifname);
    100 		return (1);
    101 	}
    102 	if ((ofp = fopen("Makefile.tmp", "w")) == NULL) {
    103 		(void)fprintf(stderr, "config: cannot write Makefile: %s\n",
    104 		    strerror(errno));
    105 		free(ifname);
    106 		return (1);
    107 	}
    108 	if (emitdefs(ofp) != 0)
    109 		goto wrerror;
    110 	lineno = 0;
    111 	while (fgets(line, sizeof(line), ifp) != NULL) {
    112 		lineno++;
    113 		if (line[0] != '%') {
    114 			if (fputs(line, ofp) < 0)
    115 				goto wrerror;
    116 			continue;
    117 		}
    118 		if (strcmp(line, "%OBJS\n") == 0)
    119 			fn = emitobjs;
    120 		else if (strcmp(line, "%CFILES\n") == 0)
    121 			fn = emitcfiles;
    122 		else if (strcmp(line, "%SFILES\n") == 0)
    123 			fn = emitsfiles;
    124 		else if (strcmp(line, "%RULES\n") == 0)
    125 			fn = emitrules;
    126 		else if (strcmp(line, "%LOAD\n") == 0)
    127 			fn = emitload;
    128 		else if (strcmp(line, "%INCLUDES\n") == 0)
    129 			fn = emitincludes;
    130 		else if (strcmp(line, "%MAKEOPTIONSAPPEND\n") == 0)
    131 			fn = emitappmkoptions;
    132 		else {
    133 			xerror(ifname, lineno,
    134 			    "unknown %% construct ignored: %s", line);
    135 			continue;
    136 		}
    137 		if ((*fn)(ofp))
    138 			goto wrerror;
    139 	}
    140 	if (ferror(ifp)) {
    141 		(void)fprintf(stderr,
    142 		    "config: error reading %s (at line %d): %s\n",
    143 		    ifname, lineno, strerror(errno));
    144 		goto bad;
    145 		/* (void)unlink("Makefile.tmp"); */
    146 		free(ifname);
    147 		return (1);
    148 	}
    149 	if (fclose(ofp)) {
    150 		ofp = NULL;
    151 		goto wrerror;
    152 	}
    153 	(void)fclose(ifp);
    154 	if (moveifchanged("Makefile.tmp", "Makefile") != 0) {
    155 		(void)fprintf(stderr,
    156 		    "config: error renaming Makefile: %s\n",
    157 		    strerror(errno));
    158 		goto bad;
    159 	}
    160 	free(ifname);
    161 	return (0);
    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 	/* (void)unlink("Makefile.tmp"); */
    169 	free(ifname);
    170 	return (1);
    171 }
    172 
    173 /*
    174  * Return (possibly in a static buffer) the name of the `source' for a
    175  * file.  If we have `options source', or if the file is marked `always
    176  * source', this is always the path from the `file' line; otherwise we
    177  * get the .o from the obj-directory.
    178  */
    179 static const char *
    180 srcpath(struct files *fi)
    181 {
    182 #if 1
    183 	/* Always have source, don't support object dirs for kernel builds. */
    184 	return (fi->fi_path);
    185 #else
    186 	static char buf[MAXPATHLEN];
    187 
    188 	if (have_source || (fi->fi_flags & FI_ALWAYSSRC) != 0)
    189 		return (fi->fi_path);
    190 	if (objpath == NULL) {
    191 		error("obj-directory not set");
    192 		return (NULL);
    193 	}
    194 	(void)snprintf(buf, sizeof buf, "%s/%s.o", objpath, fi->fi_base);
    195 	return (buf);
    196 #endif
    197 }
    198 
    199 static const char *
    200 prefix_prologue(const char *path)
    201 {
    202 
    203 	if (*path == '/')
    204 		return ("");
    205 	else
    206 		return ("$S/");
    207 }
    208 
    209 static int
    210 emitdefs(FILE *fp)
    211 {
    212 	struct nvlist *nv;
    213 	char *sp;
    214 
    215 	if (fprintf(fp, "KERNEL_BUILD=%s\n", conffile) < 0)
    216 		return (1);
    217 	if (fputs("IDENT=", fp) < 0)
    218 		return (1);
    219 	sp = "";
    220 	for (nv = options; nv != NULL; nv = nv->nv_next) {
    221 
    222 		/* skip any options output to a header file */
    223 		if (DEFINED_OPTION(nv->nv_name))
    224 			continue;
    225 		if (fprintf(fp, "%s-D%s", sp, nv->nv_name) < 0)
    226 		    return 1;
    227 		if (nv->nv_str)
    228 		    if (fprintf(fp, "=\"%s\"", nv->nv_str) < 0)
    229 			return 1;
    230 		sp = " ";
    231 	}
    232 	if (putc('\n', fp) < 0)
    233 		return (1);
    234 	if (fprintf(fp, "PARAM=-DMAXUSERS=%d\n", maxusers) < 0)
    235 		return (1);
    236 	if (fprintf(fp, "MACHINE=%s\n", machine) < 0)
    237 		return (1);
    238 	if (*srcdir == '/' || *srcdir == '.') {
    239 		if (fprintf(fp, "S=\t%s\n", srcdir) < 0)
    240 			return (1);
    241 	} else {
    242 		/*
    243 		 * libkern and libcompat "Makefile.inc"s want relative S
    244 		 * specification to begin with '.'.
    245 		 */
    246 		if (fprintf(fp, "S=\t./%s\n", srcdir) < 0)
    247 			return (1);
    248 	}
    249 	for (nv = mkoptions; nv != NULL; nv = nv->nv_next)
    250 		if (fprintf(fp, "%s=%s\n", nv->nv_name, nv->nv_str) < 0)
    251 			return (1);
    252 	return (0);
    253 }
    254 
    255 static int
    256 emitobjs(FILE *fp)
    257 {
    258 	struct files *fi;
    259 	struct objects *oi;
    260 	int lpos, len, sp;
    261 
    262 	if (fputs("OBJS=", fp) < 0)
    263 		return (1);
    264 	sp = '\t';
    265 	lpos = 7;
    266 	TAILQ_FOREACH(fi, &allfiles, fi_next) {
    267 		if ((fi->fi_flags & FI_SEL) == 0)
    268 			continue;
    269 		len = strlen(fi->fi_base) + 2;
    270 		if (lpos + len > 72) {
    271 			if (fputs(" \\\n", fp) < 0)
    272 				return (1);
    273 			sp = '\t';
    274 			lpos = 7;
    275 		}
    276 		if (fprintf(fp, "%c%s.o", sp, fi->fi_base) < 0)
    277 			return (1);
    278 		lpos += len + 1;
    279 		sp = ' ';
    280 	}
    281 	TAILQ_FOREACH(oi, &allobjects, oi_next) {
    282 		if ((oi->oi_flags & OI_SEL) == 0)
    283 			continue;
    284 		len = strlen(oi->oi_path);
    285 		if (*oi->oi_path != '/') {
    286 			len += 3;	/* "$S/" */
    287 			if (oi->oi_prefix != NULL)
    288 				len += strlen(oi->oi_prefix) + 1;
    289 		}
    290 		if (lpos + len > 72) {
    291 			if (fputs(" \\\n", fp) < 0)
    292 				return (1);
    293 			sp = '\t';
    294 			lpos = 7;
    295 		}
    296 		if (*oi->oi_path == '/') {
    297 			if (fprintf(fp, "%c%s", sp, oi->oi_path) < 0)
    298 				return (1);
    299 		} else {
    300 			if (oi->oi_prefix != NULL) {
    301 				if (fprintf(fp, "%c%s%s/%s", sp,
    302 				    prefix_prologue(oi->oi_prefix),
    303 				    oi->oi_prefix, oi->oi_path) < 0)
    304 					return (1);
    305 			} else {
    306 				if (fprintf(fp, "%c$S/%s", sp, oi->oi_path) < 0)
    307 					return (1);
    308 			}
    309 		}
    310 		lpos += len + 1;
    311 		sp = ' ';
    312 	}
    313 	if (putc('\n', fp) < 0)
    314 		return (1);
    315 	return (0);
    316 }
    317 
    318 static int
    319 emitcfiles(FILE *fp)
    320 {
    321 
    322 	return (emitfiles(fp, 'c', 0));
    323 }
    324 
    325 static int
    326 emitsfiles(FILE *fp)
    327 {
    328 
    329 	return (emitfiles(fp, 's', 1));
    330 }
    331 
    332 static int
    333 emitfiles(FILE *fp, int suffix, int upper_suffix)
    334 {
    335 	struct files *fi;
    336 	struct config *cf;
    337 	int lpos, len, sp;
    338 	const char *fpath;
    339 	char swapname[100];
    340 
    341 	if (fprintf(fp, "%cFILES=", toupper(suffix)) < 0)
    342 		return (1);
    343 	sp = '\t';
    344 	lpos = 7;
    345 	TAILQ_FOREACH(fi, &allfiles, fi_next) {
    346 		if ((fi->fi_flags & FI_SEL) == 0)
    347 			continue;
    348 		if ((fpath = srcpath(fi)) == NULL)
    349                         return (1);
    350 		len = strlen(fpath);
    351 		if (! ((fpath[len - 1] == suffix) ||
    352 		    (upper_suffix && fpath[len - 1] == toupper(suffix))))
    353 			continue;
    354 		if (*fpath != '/') {
    355 			len += 3;	/* "$S/" */
    356 			if (fi->fi_prefix != NULL)
    357 				len += strlen(fi->fi_prefix) + 1;
    358 		}
    359 		if (lpos + len > 72) {
    360 			if (fputs(" \\\n", fp) < 0)
    361 				return (1);
    362 			sp = '\t';
    363 			lpos = 7;
    364 		}
    365 		if (*fi->fi_path == '/') {
    366 			if (fprintf(fp, "%c%s", sp, fi->fi_path) < 0)
    367 				return (1);
    368 		} else {
    369 			if (fi->fi_prefix != NULL) {
    370 				if (fprintf(fp, "%c%s%s/%s", sp,
    371 				    prefix_prologue(fi->fi_prefix),
    372 				    fi->fi_prefix, fi->fi_path) < 0)
    373 					return (1);
    374 			} else {
    375 				if (fprintf(fp, "%c$S/%s", sp, fi->fi_path) < 0)
    376 					return (1);
    377 			}
    378 		}
    379 		lpos += len + 1;
    380 		sp = ' ';
    381 	}
    382 	/*
    383 	 * The allfiles list does not include the configuration-specific
    384 	 * C source files.  These files should be eliminated someday, but
    385 	 * for now, we have to add them to ${CFILES} (and only ${CFILES}).
    386 	 */
    387 	if (suffix == 'c') {
    388 		TAILQ_FOREACH(cf, &allcf, cf_next) {
    389 			(void)snprintf(swapname, sizeof(swapname), "swap%s.c",
    390 			    cf->cf_name);
    391 			len = strlen(swapname);
    392 			if (lpos + len > 72) {
    393 				if (fputs(" \\\n", fp) < 0)
    394 					return (1);
    395 				sp = '\t';
    396 				lpos = 7;
    397 			}
    398 			if (fprintf(fp, "%c%s", sp, swapname) < 0)
    399 				return (1);
    400 			lpos += len + 1;
    401 			sp = ' ';
    402 		}
    403 	}
    404 	if (putc('\n', fp) < 0)
    405 		return (1);
    406 	return (0);
    407 }
    408 
    409 /*
    410  * Emit the make-rules.
    411  */
    412 static int
    413 emitrules(FILE *fp)
    414 {
    415 	struct files *fi;
    416 	const char *cp, *fpath;
    417 	int ch;
    418 	char buf[200];
    419 
    420 	TAILQ_FOREACH(fi, &allfiles, fi_next) {
    421 		if ((fi->fi_flags & FI_SEL) == 0)
    422 			continue;
    423 		if ((fpath = srcpath(fi)) == NULL)
    424 			return (1);
    425 		if (*fpath == '/') {
    426 			if (fprintf(fp, "%s.o: %s\n", fi->fi_base, fpath) < 0)
    427 				return (1);
    428 		} else {
    429 			if (fi->fi_prefix != NULL) {
    430 				if (fprintf(fp, "%s.o: %s%s/%s\n", fi->fi_base,
    431 				    prefix_prologue(fi->fi_prefix),
    432 				    fi->fi_prefix, fpath) < 0)
    433 					return (1);
    434 			} else {
    435 				if (fprintf(fp, "%s.o: $S/%s\n", fi->fi_base,
    436 				    fpath) < 0)
    437 					return (1);
    438 			}
    439 		}
    440 		if ((cp = fi->fi_mkrule) == NULL) {
    441 			cp = "NORMAL";
    442 			ch = fpath[strlen(fpath) - 1];
    443 			if (islower(ch))
    444 				ch = toupper(ch);
    445 			(void)snprintf(buf, sizeof(buf), "${%s_%c}", cp, ch);
    446 			cp = buf;
    447 		}
    448 		if (fprintf(fp, "\t%s\n\n", cp) < 0)
    449 			return (1);
    450 	}
    451 	return (0);
    452 }
    453 
    454 /*
    455  * Emit the load commands.
    456  *
    457  * This function is not to be called `spurt'.
    458  */
    459 static int
    460 emitload(FILE *fp)
    461 {
    462 	struct config *cf;
    463 	const char *nm, *swname;
    464 
    465 	if (fputs(".MAIN: all\nall:", fp) < 0)
    466 		return (1);
    467 	TAILQ_FOREACH(cf, &allcf, cf_next) {
    468 		if (fprintf(fp, " %s", cf->cf_name) < 0)
    469 			return (1);
    470 	}
    471 	if (fputs("\n\n", fp) < 0)
    472 		return (1);
    473 	TAILQ_FOREACH(cf, &allcf, cf_next) {
    474 		nm = cf->cf_name;
    475 		swname =
    476 		    cf->cf_root != NULL ? cf->cf_name : "generic";
    477 		if (fprintf(fp, "KERNELS+=%s\n", nm) < 0)
    478 			return (1);
    479 		if (fprintf(fp, "SWAP_OBJ%s=swap%s.o\n", nm, swname) < 0)
    480 			return (1);
    481 		if (fprintf(fp, "%s: ${SYSTEM_DEP} swap%s.o vers.o", nm,
    482 		    swname) < 0)
    483 			return (1);
    484 		if (fprintf(fp, "\n\
    485 \t${SYSTEM_LD_HEAD}\n\
    486 \t${SYSTEM_LD} swap%s.o\n\
    487 \t${SYSTEM_LD_TAIL}\n\
    488 \n\
    489 swap%s.o: ", swname, swname) < 0)
    490 			return (1);
    491 		if (cf->cf_root != NULL) {
    492 			if (fprintf(fp, "swap%s.c\n", nm) < 0)
    493 				return (1);
    494 		} else {
    495 			if (fprintf(fp, "$S/arch/%s/%s/swapgeneric.c\n",
    496 			    machine, machine) < 0)
    497 				return (1);
    498 		}
    499 		if (fputs("\t${NORMAL_C}\n\n", fp) < 0)
    500 			return (1);
    501 	}
    502 	return (0);
    503 }
    504 
    505 /*
    506  * Emit include headers (for any prefixes encountered)
    507  */
    508 static int
    509 emitincludes(FILE *fp)
    510 {
    511 	struct prefix *pf;
    512 
    513 	SLIST_FOREACH(pf, &allprefixes, pf_next) {
    514 		if (fprintf(fp, "EXTRA_INCLUDES+=\t-I%s%s\n",
    515 		    prefix_prologue(pf->pf_prefix), pf->pf_prefix) < 0)
    516 			return (1);
    517 	}
    518 
    519 	return (0);
    520 }
    521 
    522 static int
    523 print_condmkopts(const char *name, void *value, void *arg)
    524 {
    525 	struct nvlist *nv;
    526 	FILE *fp = arg;
    527 
    528 	if (ht_lookup(selecttab, name) == 0)
    529 		return (0);
    530 
    531 	for (nv = value; nv != NULL; nv = nv->nv_next)
    532 		if (fprintf(fp, "%s+=%s\n", nv->nv_name, nv->nv_str) < 0)
    533 			return (1);
    534 
    535 	return (0);
    536 }
    537 
    538 /*
    539  * Emit appending makeoptions.
    540  */
    541 static int
    542 emitappmkoptions(FILE *fp)
    543 {
    544 	struct nvlist *nv;
    545 
    546 	for (nv = appmkoptions; nv != NULL; nv = nv->nv_next)
    547 		if (fprintf(fp, "%s+=%s\n", nv->nv_name, nv->nv_str) < 0)
    548 			return (1);
    549 
    550 	return (ht_enumerate(condmkopttab, print_condmkopts, fp));
    551 }
    552