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