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