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