1 /* $NetBSD: mkmakefile.c,v 1.68 2015/09/04 10:16:35 uebayasi 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/cdefs.h> 48 __RCSID("$NetBSD: mkmakefile.c,v 1.68 2015/09/04 10:16:35 uebayasi Exp $"); 49 50 #include <sys/param.h> 51 #include <ctype.h> 52 #include <errno.h> 53 #include <stdio.h> 54 #include <stdlib.h> 55 #include <string.h> 56 #include <err.h> 57 #include <util.h> 58 #include "defs.h" 59 #include "sem.h" 60 61 /* 62 * Make the Makefile. 63 */ 64 65 static void emitdefs(FILE *); 66 static void emitallfiles(FILE *); 67 68 static void emitofiles(FILE *); 69 static void emitallkobjs(FILE *); 70 static int emitallkobjscb(const char *, void *, void *); 71 static void emitattrkobjs(FILE *); 72 static int emitattrkobjscb(const char *, void *, void *); 73 static void emitkobjs(FILE *); 74 static void emitcfiles(FILE *); 75 static void emitsfiles(FILE *); 76 static void emitrules(FILE *); 77 static void emitload(FILE *); 78 static void emitincludes(FILE *); 79 static void emitappmkoptions(FILE *); 80 static void emitsubs(FILE *, const char *, const char *, int); 81 static int selectopt(const char *, void *); 82 83 int has_build_kernel; 84 85 int 86 mkmakefile(void) 87 { 88 FILE *ifp, *ofp; 89 int lineno; 90 void (*fn)(FILE *); 91 char line[BUFSIZ], ifname[200]; 92 93 /* 94 * Check if conf/Makefile.kern.inc defines "build_kernel". 95 * 96 * (This is usually done by checking "version" in sys/conf/files; 97 * unfortunately the "build_kernel" change done around 2014 Aug didn't 98 * bump that version. Thus this hack.) 99 */ 100 (void)snprintf(ifname, sizeof(ifname), "%s/conf/Makefile.kern.inc", 101 srcdir); 102 if ((ifp = fopen(ifname, "r")) == NULL) { 103 warn("cannot read %s", ifname); 104 goto bad2; 105 } 106 while (fgets(line, sizeof(line), ifp) != NULL) { 107 if (strncmp(line, "build_kernel:", 13) == 0) { 108 has_build_kernel = 1; 109 break; 110 } 111 } 112 (void)fclose(ifp); 113 114 /* 115 * Try a makefile for the port first. 116 */ 117 (void)snprintf(ifname, sizeof(ifname), "%s/arch/%s/conf/Makefile.%s", 118 srcdir, machine, machine); 119 if ((ifp = fopen(ifname, "r")) == NULL) { 120 /* 121 * Try a makefile for the architecture second. 122 */ 123 (void)snprintf(ifname, sizeof(ifname), 124 "%s/arch/%s/conf/Makefile.%s", 125 srcdir, machinearch, machinearch); 126 ifp = fopen(ifname, "r"); 127 } 128 if (ifp == NULL) { 129 warn("cannot read %s", ifname); 130 goto bad2; 131 } 132 133 if ((ofp = fopen("Makefile.tmp", "w")) == NULL) { 134 warn("cannot write Makefile"); 135 goto bad1; 136 } 137 138 emitdefs(ofp); 139 140 lineno = 0; 141 while (fgets(line, sizeof(line), ifp) != NULL) { 142 lineno++; 143 if ((version < 20090214 && line[0] != '%') || line[0] == '#') { 144 fputs(line, ofp); 145 continue; 146 } 147 if (strcmp(line, "%OBJS\n") == 0) 148 fn = Mflag ? emitkobjs : emitofiles; 149 else if (strcmp(line, "%CFILES\n") == 0) 150 fn = emitcfiles; 151 else if (strcmp(line, "%SFILES\n") == 0) 152 fn = emitsfiles; 153 else if (strcmp(line, "%RULES\n") == 0) 154 fn = emitrules; 155 else if (strcmp(line, "%LOAD\n") == 0) 156 fn = emitload; 157 else if (strcmp(line, "%INCLUDES\n") == 0) 158 fn = emitincludes; 159 else if (strcmp(line, "%MAKEOPTIONSAPPEND\n") == 0) 160 fn = emitappmkoptions; 161 else if (strncmp(line, "%VERSION ", sizeof("%VERSION ")-1) == 0) { 162 int newvers; 163 if (sscanf(line, "%%VERSION %d\n", &newvers) != 1) { 164 cfgxerror(ifname, lineno, "syntax error for " 165 "%%VERSION"); 166 } else 167 setversion(newvers); 168 continue; 169 } else { 170 if (version < 20090214) 171 cfgxerror(ifname, lineno, 172 "unknown %% construct ignored: %s", line); 173 else 174 emitsubs(ofp, line, ifname, lineno); 175 continue; 176 } 177 (*fn)(ofp); 178 } 179 180 fflush(ofp); 181 if (ferror(ofp)) 182 goto wrerror; 183 184 if (ferror(ifp)) { 185 warn("error reading %s (at line %d)", ifname, lineno); 186 goto bad; 187 } 188 189 if (fclose(ofp)) { 190 ofp = NULL; 191 goto wrerror; 192 } 193 (void)fclose(ifp); 194 195 if (moveifchanged("Makefile.tmp", "Makefile") != 0) { 196 warn("error renaming Makefile"); 197 goto bad2; 198 } 199 return (0); 200 201 wrerror: 202 warn("error writing Makefile"); 203 bad: 204 if (ofp != NULL) 205 (void)fclose(ofp); 206 bad1: 207 (void)fclose(ifp); 208 /* (void)unlink("Makefile.tmp"); */ 209 bad2: 210 return (1); 211 } 212 213 static void 214 emitsubs(FILE *fp, const char *line, const char *file, int lineno) 215 { 216 char *nextpct; 217 const char *optname; 218 struct nvlist *option; 219 220 while (*line != '\0') { 221 if (*line != '%') { 222 fputc(*line++, fp); 223 continue; 224 } 225 226 line++; 227 nextpct = strchr(line, '%'); 228 if (nextpct == NULL) { 229 cfgxerror(file, lineno, "unbalanced %% or " 230 "unknown construct"); 231 return; 232 } 233 *nextpct = '\0'; 234 235 if (*line == '\0') 236 fputc('%', fp); 237 else { 238 optname = intern(line); 239 if (!DEFINED_OPTION(optname)) { 240 cfgxerror(file, lineno, "unknown option %s", 241 optname); 242 return; 243 } 244 245 if ((option = ht_lookup(opttab, optname)) == NULL) 246 option = ht_lookup(fsopttab, optname); 247 if (option != NULL) 248 fputs(option->nv_str ? option->nv_str : "1", 249 fp); 250 /* 251 * Otherwise it's not a selected option and we don't 252 * output anything. 253 */ 254 } 255 256 line = nextpct + 1; 257 } 258 } 259 260 static void 261 emitdefs(FILE *fp) 262 { 263 struct nvlist *nv; 264 265 fprintf(fp, "KERNEL_BUILD=%s\n", conffile); 266 fputs("IDENT= \\\n", fp); 267 for (nv = options; nv != NULL; nv = nv->nv_next) { 268 269 /* Skip any options output to a header file */ 270 if (DEFINED_OPTION(nv->nv_name)) 271 continue; 272 const char *s = nv->nv_str; 273 fprintf(fp, "\t-D%s%s%s%s \\\n", nv->nv_name, 274 s ? "=\"" : "", 275 s ? s : "", 276 s ? "\"" : ""); 277 } 278 putc('\n', fp); 279 fprintf(fp, "MACHINE=%s\n", machine); 280 281 const char *subdir = ""; 282 if (*srcdir != '/' && *srcdir != '.') { 283 /* 284 * libkern and libcompat "Makefile.inc"s want relative S 285 * specification to begin with '.'. 286 */ 287 subdir = "./"; 288 } 289 fprintf(fp, "S=\t%s%s\n", subdir, srcdir); 290 if (Sflag) { 291 fprintf(fp, ".PATH: $S\n"); 292 fprintf(fp, "___USE_SUFFIX_RULES___=1\n"); 293 } 294 for (nv = mkoptions; nv != NULL; nv = nv->nv_next) 295 fprintf(fp, "%s=%s\n", nv->nv_name, nv->nv_str); 296 } 297 298 static void 299 emitfile(FILE *fp, struct files *fi) 300 { 301 const char *defprologue = "$S/"; 302 const char *prologue, *prefix, *sep; 303 304 if (Sflag) 305 defprologue = ""; 306 prologue = prefix = sep = ""; 307 if (*fi->fi_path != '/') { 308 prologue = defprologue; 309 if (fi->fi_prefix != NULL) { 310 if (*fi->fi_prefix == '/') 311 prologue = ""; 312 prefix = fi->fi_prefix; 313 sep = "/"; 314 } 315 } 316 fprintf(fp, "%s%s%s%s", prologue, prefix, sep, fi->fi_path); 317 } 318 319 static void 320 emitfilerel(FILE *fp, struct files *fi) 321 { 322 const char *prefix, *sep; 323 324 prefix = sep = ""; 325 if (*fi->fi_path != '/') { 326 if (fi->fi_prefix != NULL) { 327 prefix = fi->fi_prefix; 328 sep = "/"; 329 } 330 } 331 fprintf(fp, "%s%s%s", prefix, sep, fi->fi_path); 332 } 333 334 static void 335 emitofiles(FILE *fp) 336 { 337 338 emitallfiles(fp); 339 fprintf(fp, "#%%OFILES\n"); 340 } 341 342 static void 343 emitkobjs(FILE *fp) 344 { 345 emitallkobjs(fp); 346 emitattrkobjs(fp); 347 } 348 349 static int emitallkobjsweighcb(const char *name, void *v, void *arg); 350 static void weighattr(struct attr *a); 351 static int attrcmp(const void *l, const void *r); 352 353 struct attr **attrbuf; 354 size_t attridx; 355 356 static void 357 emitallkobjs(FILE *fp) 358 { 359 size_t i; 360 361 attrbuf = emalloc(nattrs * sizeof(*attrbuf)); 362 363 ht_enumerate(attrtab, emitallkobjsweighcb, NULL); 364 ht_enumerate(attrtab, emitallkobjscb, NULL); 365 qsort(attrbuf, attridx, sizeof(struct attr *), attrcmp); 366 367 fputs("OBJS= \\\n", fp); 368 for (i = 0; i < attridx; i++) 369 fprintf(fp, "\t%s.ko \\\n", attrbuf[i]->a_name); 370 putc('\n', fp); 371 372 free(attrbuf); 373 } 374 375 static int 376 emitallkobjscb(const char *name, void *v, void *arg) 377 { 378 struct attr *a = v; 379 380 if (ht_lookup(selecttab, name) == NULL) 381 return 0; 382 if (TAILQ_EMPTY(&a->a_files)) 383 return 0; 384 attrbuf[attridx++] = a; 385 /* XXX nattrs tracking is not exact yet */ 386 if (attridx == nattrs) { 387 nattrs *= 2; 388 attrbuf = erealloc(attrbuf, nattrs * sizeof(*attrbuf)); 389 } 390 return 0; 391 } 392 393 static int 394 emitallkobjsweighcb(const char *name, void *v, void *arg) 395 { 396 struct attr *a = v; 397 398 weighattr(a); 399 return 0; 400 } 401 402 static void 403 weighattr(struct attr *a) 404 { 405 struct attrlist *al; 406 407 for (al = a->a_deps; al != NULL; al = al->al_next) { 408 weighattr(al->al_this); 409 } 410 a->a_weight++; 411 } 412 413 static int 414 attrcmp(const void *l, const void *r) 415 { 416 const struct attr * const *a = l, * const *b = r; 417 const int wa = (*a)->a_weight, wb = (*b)->a_weight; 418 return (wa > wb) ? -1 : (wa < wb) ? 1 : 0; 419 } 420 421 static void 422 emitattrkobjs(FILE *fp) 423 { 424 extern struct hashtab *attrtab; 425 426 ht_enumerate(attrtab, emitattrkobjscb, fp); 427 } 428 429 static int 430 emitattrkobjscb(const char *name, void *v, void *arg) 431 { 432 struct attr *a = v; 433 struct files *fi; 434 FILE *fp = arg; 435 436 if (ht_lookup(selecttab, name) == NULL) 437 return 0; 438 if (TAILQ_EMPTY(&a->a_files)) 439 return 0; 440 fputc('\n', fp); 441 fprintf(fp, "# %s (%d)\n", name, a->a_weight); 442 fprintf(fp, "OBJS.%s= \\\n", name); 443 TAILQ_FOREACH(fi, &a->a_files, fi_anext) { 444 fprintf(fp, "\t%s.o \\\n", fi->fi_base); 445 } 446 fputc('\n', fp); 447 fprintf(fp, "%s.ko: ${OBJS.%s}\n", name, name); 448 fprintf(fp, "\t${LINK_O}\n"); 449 return 0; 450 } 451 452 static void 453 emitcfiles(FILE *fp) 454 { 455 456 emitallfiles(fp); 457 fprintf(fp, "#%%CFILES\n"); 458 } 459 460 static void 461 emitsfiles(FILE *fp) 462 { 463 464 emitallfiles(fp); 465 fprintf(fp, "#%%SFILES\n"); 466 } 467 468 static void 469 emitallfiles(FILE *fp) 470 { 471 struct files *fi; 472 static int called; 473 int i; 474 int found = 0; 475 476 if (called++ != 0) 477 return; 478 for (i = 0; i < (int)nselfiles; i++) { 479 fi = selfiles[i]; 480 if (found++ == 0) 481 fprintf(fp, "ALLFILES= \\\n"); 482 putc('\t', fp); 483 emitfilerel(fp, fi); 484 fputs(" \\\n", fp); 485 } 486 fputc('\n', fp); 487 } 488 489 /* 490 * Emit the make-rules. 491 */ 492 static void 493 emitrules(FILE *fp) 494 { 495 struct files *fi; 496 int i; 497 int found = 0; 498 499 for (i = 0; i < (int)nselfiles; i++) { 500 fi = selfiles[i]; 501 if (fi->fi_mkrule == NULL) 502 continue; 503 fprintf(fp, "%s.o: ", fi->fi_base); 504 emitfile(fp, fi); 505 putc('\n', fp); 506 fprintf(fp, "\t%s\n\n", fi->fi_mkrule); 507 found++; 508 } 509 if (found == 0) 510 fprintf(fp, "#%%RULES\n"); 511 } 512 513 /* 514 * Emit the load commands. 515 * 516 * This function is not to be called `spurt'. 517 */ 518 static void 519 emitload(FILE *fp) 520 { 521 struct config *cf; 522 int found = 0; 523 524 /* 525 * Generate the backward-compatible "build_kernel" rule if 526 * sys/conf/Makefile.kern.inc doesn't define any (pre-2014 Aug). 527 */ 528 if (has_build_kernel == 0) { 529 fprintf(fp, "build_kernel: .USE\n" 530 "\t${SYSTEM_LD_HEAD}\n" 531 "\t${SYSTEM_LD}%s\n" 532 "\t${SYSTEM_LD_TAIL}\n" 533 "\n", 534 Sflag ? "" : " swap${.TARGET}.o"); 535 } 536 /* 537 * Generate per-kernel rules. 538 */ 539 TAILQ_FOREACH(cf, &allcf, cf_next) { 540 char swapobj[100]; 541 542 if (Sflag) { 543 swapobj[0] = '\0'; 544 } else { 545 (void)snprintf(swapobj, sizeof(swapobj), " swap%s.o", 546 cf->cf_name); 547 } 548 fprintf(fp, "KERNELS+=%s\n", cf->cf_name); 549 found = 1; 550 } 551 if (found == 0) 552 fprintf(fp, "#%%LOAD\n"); 553 } 554 555 /* 556 * Emit include headers (for any prefixes encountered) 557 */ 558 static void 559 emitincludes(FILE *fp) 560 { 561 struct prefix *pf; 562 563 SLIST_FOREACH(pf, &allprefixes, pf_next) { 564 const char *prologue = (*pf->pf_prefix == '/') ? "" : "$S/"; 565 566 fprintf(fp, "EXTRA_INCLUDES+=\t-I%s%s\n", 567 prologue, pf->pf_prefix); 568 } 569 } 570 571 /* 572 * Emit appending makeoptions. 573 */ 574 static void 575 emitappmkoptions(FILE *fp) 576 { 577 struct nvlist *nv; 578 struct condexpr *cond; 579 580 for (nv = appmkoptions; nv != NULL; nv = nv->nv_next) 581 fprintf(fp, "%s+=%s\n", nv->nv_name, nv->nv_str); 582 583 for (nv = condmkoptions; nv != NULL; nv = nv->nv_next) { 584 cond = nv->nv_ptr; 585 if (expr_eval(cond, selectopt, NULL)) 586 fprintf(fp, "%s+=%s\n", nv->nv_name, nv->nv_str); 587 condexpr_destroy(cond); 588 nv->nv_ptr = NULL; 589 } 590 } 591 592 static int 593 /*ARGSUSED*/ 594 selectopt(const char *name, void *context) 595 { 596 597 return (ht_lookup(selecttab, strtolower(name)) != NULL); 598 } 599