1 /* $OpenBSD: mkmakefile.c,v 1.41 2015/01/16 06:40:16 deraadt Exp $ */ 2 /* $NetBSD: mkmakefile.c,v 1.34 1997/02/02 21:12:36 thorpej Exp $ */ 3 4 /* 5 * Copyright (c) 1992, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This software was developed by the Computer Systems Engineering group 9 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 10 * contributed to Berkeley. 11 * 12 * All advertising materials mentioning features or use of this software 13 * must display the following acknowledgement: 14 * This product includes software developed by the University of 15 * California, Lawrence Berkeley Laboratories. 16 * 17 * Redistribution and use in source and binary forms, with or without 18 * modification, are permitted provided that the following conditions 19 * are met: 20 * 1. Redistributions of source code must retain the above copyright 21 * notice, this list of conditions and the following disclaimer. 22 * 2. Redistributions in binary form must reproduce the above copyright 23 * notice, this list of conditions and the following disclaimer in the 24 * documentation and/or other materials provided with the distribution. 25 * 3. Neither the name of the University nor the names of its contributors 26 * may be used to endorse or promote products derived from this software 27 * without specific prior written permission. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 39 * SUCH DAMAGE. 40 * 41 * from: @(#)mkmakefile.c 8.1 (Berkeley) 6/6/93 42 */ 43 44 #include <ctype.h> 45 #include <err.h> 46 #include <errno.h> 47 #include <stdio.h> 48 #include <stdlib.h> 49 #include <string.h> 50 51 #include "config.h" 52 #include "sem.h" 53 54 /* 55 * Make the Makefile. 56 */ 57 58 static const char *srcpath(struct files *); 59 60 static int emitdefs(FILE *); 61 static int emitreconfig(FILE *); 62 static int emitfiles(FILE *, int); 63 64 static int emitobjs(FILE *); 65 static int emitcfiles(FILE *); 66 static int emitsfiles(FILE *); 67 static int emitrules(FILE *); 68 static int emitload(FILE *); 69 70 int 71 mkmakefile(void) 72 { 73 FILE *ifp, *ofp; 74 int lineno; 75 int (*fn)(FILE *); 76 char *ifname; 77 char line[BUFSIZ], buf[200]; 78 79 (void)snprintf(buf, sizeof buf, "arch/%s/conf/Makefile.%s", 80 machine, machine); 81 ifname = sourcepath(buf); 82 if ((ifp = fopen(ifname, "r")) == NULL) { 83 (void)fprintf(stderr, "config: cannot read %s: %s\n", 84 ifname, strerror(errno)); 85 free(ifname); 86 return (1); 87 } 88 if ((ofp = fopen("Makefile", "w")) == NULL) { 89 (void)fprintf(stderr, "config: cannot write Makefile: %s\n", 90 strerror(errno)); 91 free(ifname); 92 (void)fclose(ifp); 93 return (1); 94 } 95 if (emitdefs(ofp) != 0) 96 goto wrerror; 97 lineno = 0; 98 while (fgets(line, sizeof(line), ifp) != NULL) { 99 lineno++; 100 if (line[0] != '%') { 101 if (fputs(line, ofp) < 0) 102 goto wrerror; 103 continue; 104 } 105 if (strcmp(line, "%OBJS\n") == 0) 106 fn = emitobjs; 107 else if (strcmp(line, "%CFILES\n") == 0) 108 fn = emitcfiles; 109 else if (strcmp(line, "%SFILES\n") == 0) 110 fn = emitsfiles; 111 else if (strcmp(line, "%RULES\n") == 0) 112 fn = emitrules; 113 else if (strcmp(line, "%LOAD\n") == 0) 114 fn = emitload; 115 else { 116 xerror(ifname, lineno, 117 "unknown %% construct ignored: %s", line); 118 continue; 119 } 120 if ((*fn)(ofp)) 121 goto wrerror; 122 } 123 if (startdir != NULL) { 124 if (emitreconfig(ofp) != 0) 125 goto wrerror; 126 } 127 if (ferror(ifp)) { 128 (void)fprintf(stderr, 129 "config: error reading %s (at line %d): %s\n", 130 ifname, lineno, strerror(errno)); 131 goto bad; 132 } 133 if (fclose(ofp)) { 134 ofp = NULL; 135 goto wrerror; 136 } 137 (void)fclose(ifp); 138 free(ifname); 139 return (0); 140 wrerror: 141 (void)fprintf(stderr, "config: error writing Makefile: %s\n", 142 strerror(errno)); 143 bad: 144 if (ofp != NULL) 145 (void)fclose(ofp); 146 /* (void)unlink("Makefile"); */ 147 free(ifname); 148 return (1); 149 } 150 151 char * 152 expandname(const char *_nam) 153 { 154 char *ret = NULL, *nam, *n, *s, *e, *expand; 155 const char *var = NULL; 156 157 if ((nam = n = strdup(_nam)) == NULL) 158 errx(1, "out of memory"); 159 160 while (*n) { 161 /* Search for a ${name} to expand */ 162 if ((s = strchr(n, '$')) == NULL) { 163 if (ret == NULL) 164 break; 165 if (asprintf(&expand, "%s%s", ret, n) == -1) 166 errx(1, "out of memory"); 167 free(ret); 168 ret = expand; 169 break; 170 } 171 *s++ = '\0'; 172 if (*s != '{') 173 error("{"); 174 e = strchr(++s, '}'); 175 if (!e) 176 error("}"); 177 *e = '\0'; 178 179 if (strcmp(s, "MACHINE_ARCH") == 0) 180 var = machinearch ? machinearch : machine; 181 else if (strcmp(s, "MACHINE") == 0) 182 var = machine; 183 else 184 error("variable `%s' not supported", s); 185 186 if (asprintf(&expand, "%s%s", ret ? ret : nam, var) == -1) 187 errx(1, "out of memory"); 188 free(ret); 189 ret = expand; 190 n = e + 1; 191 } 192 free(nam); 193 return (ret); 194 } 195 196 /* 197 * Return (possibly in a static buffer) the name of the `source' for a 198 * file. If we have `options source', or if the file is marked `always 199 * source', this is always the path from the `file' line; otherwise we 200 * get the .o from the obj-directory. 201 */ 202 static const char * 203 srcpath(struct files *fi) 204 { 205 /* Always have source, don't support object dirs for kernel builds. */ 206 struct nvlist *nv, *nv1; 207 char *expand, *source; 208 209 /* Search path list for files we will want to use */ 210 if (fi->fi_nvpath->nv_next == NULL) { 211 nv = fi->fi_nvpath; 212 goto onlyone; 213 } 214 215 for (nv = fi->fi_nvpath; nv; nv = nv->nv_next) { 216 expand = expandname(nv->nv_name); 217 source = sourcepath(expand ? expand : nv->nv_name); 218 if (access(source, R_OK) == 0) { 219 /* XXX poolalloc() prevents freeing old nv_name */ 220 if (expand) 221 nv->nv_name = intern(expand); 222 break; 223 } 224 free(expand); 225 free(source); 226 } 227 if (nv == NULL) 228 nv = fi->fi_nvpath; 229 230 /* 231 * Now that we know which path is selected, delete all the 232 * other paths to skip the access() checks next time. 233 */ 234 while ((nv1 = fi->fi_nvpath)) { 235 nv1 = nv1->nv_next; 236 if (fi->fi_nvpath != nv) 237 nvfree(fi->fi_nvpath); 238 fi->fi_nvpath = nv1; 239 } 240 fi->fi_nvpath = nv; 241 nv->nv_next = NULL; 242 onlyone: 243 return (nv->nv_name); 244 } 245 246 static int 247 emitdefs(FILE *fp) 248 { 249 struct nvlist *nv; 250 char *sp; 251 252 if (fputs("IDENT=", fp) < 0) 253 return (1); 254 sp = ""; 255 for (nv = options; nv != NULL; nv = nv->nv_next) { 256 if (ht_lookup(defopttab, nv->nv_name) != NULL) 257 continue; 258 if (fprintf(fp, "%s-D%s", sp, nv->nv_name) < 0) 259 return 1; 260 if (nv->nv_str) 261 if (fprintf(fp, "=\"%s\"", nv->nv_str) < 0) 262 return 1; 263 sp = " "; 264 } 265 if (putc('\n', fp) < 0) 266 return (1); 267 if (fprintf(fp, "PARAM=-DMAXUSERS=%d\n", maxusers) < 0) 268 return (1); 269 if (fprintf(fp, "S=\t%s\n", srcdir) < 0) 270 return (1); 271 if (fprintf(fp, "_mach=%s\n", machine) < 0) 272 return (1); 273 if (fprintf(fp, "_arch=%s\n", machinearch ? machinearch : machine) < 0) 274 return (1); 275 for (nv = mkoptions; nv != NULL; nv = nv->nv_next) 276 if (fprintf(fp, "%s=%s\n", nv->nv_name, nv->nv_str) < 0) 277 return (1); 278 return (0); 279 } 280 281 static int 282 emitreconfig(FILE *fp) 283 { 284 if (fputs("\n" 285 ".PHONY: config\n" 286 "config:\n", fp) < 0) 287 return (1); 288 if (fprintf(fp, "\tcd %s && config ", startdir) < 0) 289 return (1); 290 if (pflag) { 291 if (fputs("-p ", fp) < 0) 292 return (1); 293 } 294 if (sflag) { 295 if (fprintf(fp, "-s %s ", sflag) < 0) 296 return (1); 297 } 298 if (bflag) { 299 if (fprintf(fp, "-b %s ", bflag) < 0) 300 return (1); 301 } 302 /* other options */ 303 if (fprintf(fp, "%s\n", conffile) < 0) 304 return (1); 305 return (0); 306 } 307 308 static int 309 emitobjs(FILE *fp) 310 { 311 struct files *fi; 312 struct objects *oi; 313 int lpos, len, sp; 314 const char *fpath; 315 316 if (fputs("OBJS=", fp) < 0) 317 return (1); 318 sp = '\t'; 319 lpos = 7; 320 for (fi = allfiles; fi != NULL; fi = fi->fi_next) { 321 if ((fi->fi_flags & FI_SEL) == 0) 322 continue; 323 if ((fpath = srcpath(fi)) == NULL) 324 return (1); 325 len = strlen(fi->fi_base) + 3; 326 if (lpos + len > 72) { 327 if (fputs(" \\\n", fp) < 0) 328 return (1); 329 sp = '\t'; 330 lpos = 7; 331 } 332 if (fprintf(fp, "%c%s.o", sp, fi->fi_base) < 0) 333 return (1); 334 lpos += len + 1; 335 sp = ' '; 336 } 337 for (oi = allobjects; oi != NULL; oi = oi->oi_next) { 338 if ((oi->oi_flags & OI_SEL) == 0) 339 continue; 340 len = strlen(oi->oi_path) + 3; 341 if (lpos + len > 72) { 342 if (fputs(" \\\n", fp) < 0) 343 return (1); 344 sp = '\t'; 345 lpos = 7; 346 } 347 if (fprintf(fp, "%c$S/%s", sp, oi->oi_path) < 0) 348 return (1); 349 lpos += len + 1; 350 sp = ' '; 351 } 352 if (putc('\n', fp) < 0) 353 return (1); 354 return (0); 355 } 356 357 static int 358 emitcfiles(FILE *fp) 359 { 360 361 return (emitfiles(fp, 'c')); 362 } 363 364 static int 365 emitsfiles(FILE *fp) 366 { 367 368 return (emitfiles(fp, 's')); 369 } 370 371 static int 372 emitfiles(FILE *fp, int suffix) 373 { 374 struct files *fi; 375 int lpos, len, sp; 376 const char *fpath; 377 char uppersuffix = toupper((unsigned char)suffix); 378 379 if (fprintf(fp, "%cFILES=", uppersuffix) < 0) 380 return (1); 381 sp = '\t'; 382 lpos = 7; 383 for (fi = allfiles; fi != NULL; fi = fi->fi_next) { 384 if ((fi->fi_flags & FI_SEL) == 0) 385 continue; 386 if ((fpath = srcpath(fi)) == NULL) 387 return (1); 388 len = strlen(fpath); 389 if (fpath[len - 1] != suffix && fpath[len - 1] != uppersuffix) 390 continue; 391 if (*fpath != '/') 392 len += 3; /* "$S/" */ 393 if (lpos + len > 72) { 394 if (fputs(" \\\n", fp) < 0) 395 return (1); 396 sp = '\t'; 397 lpos = 7; 398 } 399 if (fprintf(fp, "%c%s%s", sp, *fpath != '/' ? "$S/" : "", 400 fpath) < 0) 401 return (1); 402 lpos += len + 1; 403 sp = ' '; 404 } 405 if (putc('\n', fp) < 0) 406 return (1); 407 return (0); 408 } 409 410 /* 411 * Emit the make-rules. 412 */ 413 static int 414 emit_1rule(FILE *fp, struct files *fi, const char *fpath, const char *suffix) 415 { 416 if (fprintf(fp, "%s%s: %s%s\n", fi->fi_base, suffix, 417 *fpath != '/' ? "$S/" : "", fpath) < 0) 418 return (1); 419 if (fi->fi_mkrule != NULL) { 420 if (fprintf(fp, "\t%s\n\n", fi->fi_mkrule) < 0) 421 return (1); 422 } 423 return (0); 424 } 425 426 static int 427 emitrules(FILE *fp) 428 { 429 struct files *fi; 430 const char *fpath; 431 432 /* write suffixes */ 433 if (fprintf(fp, 434 ".SUFFIXES:\n" 435 ".SUFFIXES: .s .S .c .o\n\n" 436 437 ".PHONY: depend all install clean tags\n\n" 438 439 ".c.o:\n" 440 "\t${NORMAL_C}\n\n" 441 442 ".s.o:\n" 443 "\t${NORMAL_S}\n\n" 444 445 ".S.o:\n" 446 "\t${NORMAL_S}\n\n") < 0) 447 return (1); 448 449 450 for (fi = allfiles; fi != NULL; fi = fi->fi_next) { 451 if ((fi->fi_flags & FI_SEL) == 0) 452 continue; 453 if ((fpath = srcpath(fi)) == NULL) 454 return (1); 455 /* special rule: need to emit them independently */ 456 if (fi->fi_mkrule) { 457 if (emit_1rule(fp, fi, fpath, ".o")) 458 return (1); 459 /* simple default rule */ 460 } else { 461 if (fprintf(fp, "%s.o: %s%s\n", fi->fi_base, 462 *fpath != '/' ? "$S/" : "", fpath) < 0) 463 return (1); 464 } 465 466 } 467 return (0); 468 } 469 470 /* 471 * Emit the load commands. 472 * 473 * This function is not to be called `spurt'. 474 */ 475 static int 476 emitload(FILE *fp) 477 { 478 struct config *cf; 479 const char *nm, *swname; 480 int first; 481 482 if (fputs("all:", fp) < 0) 483 return (1); 484 for (cf = allcf; cf != NULL; cf = cf->cf_next) { 485 if (fprintf(fp, " %s", cf->cf_name) < 0) 486 return (1); 487 } 488 if (fputs("\n\n", fp) < 0) 489 return (1); 490 for (first = 1, cf = allcf; cf != NULL; cf = cf->cf_next) { 491 nm = cf->cf_name; 492 swname = 493 cf->cf_root != NULL ? cf->cf_name : "generic"; 494 if (fprintf(fp, "%s: ${SYSTEM_DEP} swap%s.o", nm, swname) < 0) 495 return (1); 496 if (first) { 497 if (fputs(" vers.o", fp) < 0) 498 return (1); 499 first = 0; 500 } 501 if (fprintf(fp, "\n" 502 "\t${SYSTEM_LD_HEAD}\n" 503 "\t${SYSTEM_LD} swap%s.o\n" 504 "\t${SYSTEM_LD_TAIL}\n" 505 "\n" 506 "swap%s.o: ", swname, swname) < 0) 507 return (1); 508 if (cf->cf_root != NULL) { 509 if (fprintf(fp, "swap%s.c\n", nm) < 0) 510 return (1); 511 } else { 512 if (fprintf(fp, "$S/conf/swapgeneric.c\n") < 0) 513 return (1); 514 } 515 if (fputs("\t${NORMAL_C}\n\n", fp) < 0) 516 return (1); 517 } 518 return (0); 519 } 520