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