1/* $OpenBSD: mkmakefile.c,v 1.48 2021/11/28 19:26:03 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 58static const char *srcpath(struct files *); 59 60static int emitdefs(FILE *); 61static int emitreconfig(FILE *); 62static int emitfiles(FILE *, int); 63 64static int emitobjs(FILE *); 65static int emitcfiles(FILE *); 66static int emitsfiles(FILE *); 67static int emitrules(FILE *); 68static int emitload(FILE *); 69 70int 71mkmakefile(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 warn("cannot read %s", ifname); 84 free(ifname); 85 return (1); 86 } 87 if ((ofp = fopen("Makefile", "w")) == NULL) { 88 warn("cannot write Makefile"); 89 free(ifname); 90 (void)fclose(ifp); 91 return (1); 92 } 93 if (emitdefs(ofp) != 0) 94 goto wrerror; 95 lineno = 0; 96 while (fgets(line, sizeof(line), ifp) != NULL) { 97 lineno++; 98 if (line[0] != '%') { 99 if (fputs(line, ofp) == EOF) 100 goto wrerror; 101 continue; 102 } 103 if (strcmp(line, "%OBJS\n") == 0) 104 fn = emitobjs; 105 else if (strcmp(line, "%CFILES\n") == 0) 106 fn = emitcfiles; 107 else if (strcmp(line, "%SFILES\n") == 0) 108 fn = emitsfiles; 109 else if (strcmp(line, "%RULES\n") == 0) 110 fn = emitrules; 111 else if (strcmp(line, "%LOAD\n") == 0) 112 fn = emitload; 113 else { 114 xerror(ifname, lineno, 115 "unknown %% construct ignored: %s", line); 116 continue; 117 } 118 if ((*fn)(ofp)) 119 goto wrerror; 120 } 121 if (startdir != NULL) { 122 if (emitreconfig(ofp) != 0) 123 goto wrerror; 124 } 125 if (ferror(ifp)) { 126 warn("error reading %s (at line %d)", ifname, lineno); 127 goto bad; 128 } 129 if (fclose(ofp) == EOF) { 130 ofp = NULL; 131 goto wrerror; 132 } 133 (void)fclose(ifp); 134 free(ifname); 135 return (0); 136wrerror: 137 warn("error writing Makefile"); 138bad: 139 if (ofp != NULL) 140 (void)fclose(ofp); 141 /* (void)unlink("Makefile"); */ 142 free(ifname); 143 return (1); 144} 145 146char * 147expandname(const char *_nam) 148{ 149 char *ret = NULL, *nam, *n, *s, *e, *expand; 150 const char *var = NULL; 151 152 if ((nam = n = strdup(_nam)) == NULL) 153 errx(1, "out of memory"); 154 155 while (*n) { 156 /* Search for a ${name} to expand */ 157 if ((s = strchr(n, '$')) == NULL) { 158 if (ret == NULL) 159 break; 160 if (asprintf(&expand, "%s%s", ret, n) == -1) 161 errx(1, "out of memory"); 162 free(ret); 163 ret = expand; 164 break; 165 } 166 *s++ = '\0'; 167 if (*s != '{') 168 error("{"); 169 e = strchr(++s, '}'); 170 if (!e) 171 error("}"); 172 *e = '\0'; 173 174 if (strcmp(s, "MACHINE_ARCH") == 0) 175 var = machinearch ? machinearch : machine; 176 else if (strcmp(s, "MACHINE") == 0) 177 var = machine; 178 else 179 error("variable `%s' not supported", s); 180 181 if (asprintf(&expand, "%s%s", ret ? ret : nam, var) == -1) 182 errx(1, "out of memory"); 183 free(ret); 184 ret = expand; 185 n = e + 1; 186 } 187 free(nam); 188 return (ret); 189} 190 191/* 192 * Return (possibly in a static buffer) the name of the `source' for a 193 * file. If we have `options source', or if the file is marked `always 194 * source', this is always the path from the `file' line; otherwise we 195 * get the .o from the obj-directory. 196 */ 197static const char * 198srcpath(struct files *fi) 199{ 200 /* Always have source, don't support object dirs for kernel builds. */ 201 struct nvlist *nv, *nv1; 202 char *expand, *source; 203 204 /* Search path list for files we will want to use */ 205 if (fi->fi_nvpath->nv_next == NULL) { 206 nv = fi->fi_nvpath; 207 goto onlyone; 208 } 209 210 for (nv = fi->fi_nvpath; nv; nv = nv->nv_next) { 211 expand = expandname(nv->nv_name); 212 source = sourcepath(expand ? expand : nv->nv_name); 213 if (access(source, R_OK) == 0) { 214 if (expand) 215 nv->nv_name = intern(expand); 216 break; 217 } 218 free(expand); 219 free(source); 220 } 221 if (nv == NULL) 222 nv = fi->fi_nvpath; 223 224 /* 225 * Now that we know which path is selected, delete all the 226 * other paths to skip the access() checks next time. 227 */ 228 while ((nv1 = fi->fi_nvpath)) { 229 nv1 = nv1->nv_next; 230 if (fi->fi_nvpath != nv) 231 nvfree(fi->fi_nvpath); 232 fi->fi_nvpath = nv1; 233 } 234 fi->fi_nvpath = nv; 235 nv->nv_next = NULL; 236onlyone: 237 return (nv->nv_name); 238} 239 240static int 241emitdefs(FILE *fp) 242{ 243 struct nvlist *nv; 244 char *sp; 245 246 if (fputs("IDENT=", fp) == EOF) 247 return (1); 248 sp = ""; 249 for (nv = options; nv != NULL; nv = nv->nv_next) { 250 if (ht_lookup(defopttab, nv->nv_name) != NULL) 251 continue; 252 if (fprintf(fp, "%s-D%s", sp, nv->nv_name) < 0) 253 return 1; 254 if (nv->nv_str) 255 if (fprintf(fp, "=\"%s\"", nv->nv_str) < 0) 256 return 1; 257 sp = " "; 258 } 259 if (putc('\n', fp) == EOF) 260 return (1); 261 if (fprintf(fp, "PARAM=-DMAXUSERS=%d\n", maxusers) < 0) 262 return (1); 263 if (fprintf(fp, "S=\t%s\n", srcdir) < 0) 264 return (1); 265 if (fprintf(fp, "_mach=%s\n", machine) < 0) 266 return (1); 267 if (fprintf(fp, "_arch=%s\n", machinearch ? machinearch : machine) < 0) 268 return (1); 269 for (nv = mkoptions; nv != NULL; nv = nv->nv_next) 270 if (fprintf(fp, "%s=%s\n", nv->nv_name, nv->nv_str) < 0) 271 return (1); 272 return (0); 273} 274 275static int 276emitreconfig(FILE *fp) 277{ 278 if (fputs("\n" 279 ".PHONY: config\n" 280 "config:\n", fp) == EOF) 281 return (1); 282 if (fprintf(fp, "\tcd %s && config ", startdir) < 0) 283 return (1); 284 if (pflag) { 285 if (fputs("-p ", fp) == EOF) 286 return (1); 287 } 288 if (sflag) { 289 if (fprintf(fp, "-s %s ", sflag) < 0) 290 return (1); 291 } 292 if (bflag) { 293 if (fprintf(fp, "-b %s ", bflag) < 0) 294 return (1); 295 } 296 /* other options */ 297 if (fprintf(fp, "%s\n", conffile) < 0) 298 return (1); 299 return (0); 300} 301 302static int 303emitobjs(FILE *fp) 304{ 305 struct files *fi; 306 struct objects *oi; 307 int lpos, len, sp; 308 const char *fpath; 309 310 if (fputs("OBJS=", fp) == EOF) 311 return (1); 312 sp = '\t'; 313 lpos = 7; 314 for (fi = allfiles; fi != NULL; fi = fi->fi_next) { 315 if ((fi->fi_flags & FI_SEL) == 0) 316 continue; 317 if ((fpath = srcpath(fi)) == NULL) 318 return (1); 319 len = strlen(fi->fi_base) + 3; 320 if (lpos + len > 72) { 321 if (fputs(" \\\n", fp) == EOF) 322 return (1); 323 sp = '\t'; 324 lpos = 7; 325 } 326 if (fprintf(fp, "%c%s.o", sp, fi->fi_base) < 0) 327 return (1); 328 lpos += len + 1; 329 sp = ' '; 330 } 331 for (oi = allobjects; oi != NULL; oi = oi->oi_next) { 332 if ((oi->oi_flags & OI_SEL) == 0) 333 continue; 334 len = strlen(oi->oi_path) + 3; 335 if (lpos + len > 72) { 336 if (fputs(" \\\n", fp) == EOF) 337 return (1); 338 sp = '\t'; 339 lpos = 7; 340 } 341 if (fprintf(fp, "%c$S/%s", sp, oi->oi_path) < 0) 342 return (1); 343 lpos += len + 1; 344 sp = ' '; 345 } 346 if (putc('\n', fp) == EOF) 347 return (1); 348 return (0); 349} 350 351static int 352emitcfiles(FILE *fp) 353{ 354 355 return (emitfiles(fp, 'c')); 356} 357 358static int 359emitsfiles(FILE *fp) 360{ 361 362 return (emitfiles(fp, 's')); 363} 364 365static int 366emitfiles(FILE *fp, int suffix) 367{ 368 struct files *fi; 369 int lpos, len, sp; 370 const char *fpath; 371 char uppersuffix = toupper((unsigned char)suffix); 372 373 if (fprintf(fp, "%cFILES=", uppersuffix) < 0) 374 return (1); 375 sp = '\t'; 376 lpos = 7; 377 for (fi = allfiles; fi != NULL; fi = fi->fi_next) { 378 if ((fi->fi_flags & FI_SEL) == 0) 379 continue; 380 if ((fpath = srcpath(fi)) == NULL) 381 return (1); 382 len = strlen(fpath); 383 if (fpath[len - 1] != suffix && fpath[len - 1] != uppersuffix) 384 continue; 385 if (*fpath != '/') 386 len += 3; /* "$S/" */ 387 if (lpos + len > 72) { 388 if (fputs(" \\\n", fp) == EOF) 389 return (1); 390 sp = '\t'; 391 lpos = 7; 392 } 393 if (fprintf(fp, "%c%s%s", sp, *fpath != '/' ? "$S/" : "", 394 fpath) < 0) 395 return (1); 396 lpos += len + 1; 397 sp = ' '; 398 } 399 if (putc('\n', fp) == EOF) 400 return (1); 401 return (0); 402} 403 404/* 405 * Emit the make-rules. 406 */ 407static int 408emit_1rule(FILE *fp, struct files *fi, const char *fpath, const char *suffix) 409{ 410 if (fprintf(fp, "%s%s: %s%s\n", fi->fi_base, suffix, 411 *fpath != '/' ? "$S/" : "", fpath) < 0) 412 return (1); 413 if (fi->fi_mkrule != NULL) { 414 if (fprintf(fp, "\t%s\n\n", fi->fi_mkrule) < 0) 415 return (1); 416 } 417 return (0); 418} 419 420static int 421emitrules(FILE *fp) 422{ 423 struct files *fi; 424 const char *fpath; 425 426 /* write suffixes */ 427 if (fprintf(fp, 428 ".SUFFIXES:\n" 429 ".SUFFIXES: .s .S .c .o\n\n" 430 431 ".PHONY: depend all install clean tags newbsd update-link\n\n" 432 433 ".c.o:\n" 434 "\t${NORMAL_C}\n\n" 435 436 ".s.o:\n" 437 "\t${NORMAL_S}\n\n" 438 439 ".S.o:\n" 440 "\t${NORMAL_S}\n\n") < 0) 441 return (1); 442 443 444 for (fi = allfiles; fi != NULL; fi = fi->fi_next) { 445 if ((fi->fi_flags & FI_SEL) == 0) 446 continue; 447 if ((fpath = srcpath(fi)) == NULL) 448 return (1); 449 /* special rule: need to emit them independently */ 450 if (fi->fi_mkrule) { 451 if (emit_1rule(fp, fi, fpath, ".o")) 452 return (1); 453 /* simple default rule */ 454 } else { 455 if (fprintf(fp, "%s.o: %s%s\n", fi->fi_base, 456 *fpath != '/' ? "$S/" : "", fpath) < 0) 457 return (1); 458 } 459 460 } 461 return (0); 462} 463 464/* 465 * Emit the load commands. 466 * 467 * This function is not to be called `spurt'. 468 */ 469static int 470emitload(FILE *fp) 471{ 472 struct config *cf; 473 const char *nm, *swname; 474 int first; 475 476 if (fputs("all:", fp) == EOF) 477 return (1); 478 for (cf = allcf; cf != NULL; cf = cf->cf_next) { 479 if (fprintf(fp, " %s", cf->cf_name) < 0) 480 return (1); 481 } 482 if (fputs("\n\n", fp) == EOF) 483 return (1); 484 for (first = 1, cf = allcf; cf != NULL; cf = cf->cf_next) { 485 nm = cf->cf_name; 486 swname = 487 cf->cf_root != NULL ? cf->cf_name : "generic"; 488 if (fprintf(fp, "%s: ${SYSTEM_DEP} swap%s.o", nm, swname) < 0) 489 return (1); 490 if (first) { 491 if (fputs(" vers.o", fp) == EOF) 492 return (1); 493 first = 0; 494 } 495 if (fprintf(fp, "\n" 496 "\t${SYSTEM_LD_HEAD}\n" 497 "\t${SYSTEM_LD} swap%s.o\n" 498 "\t${SYSTEM_LD_TAIL}\n" 499 "\n" 500 "swap%s.o: ", swname, swname) < 0) 501 return (1); 502 if (cf->cf_root != NULL) { 503 if (fprintf(fp, "swap%s.c\n", nm) < 0) 504 return (1); 505 } else { 506 if (fprintf(fp, "$S/conf/swapgeneric.c\n") < 0) 507 return (1); 508 } 509 if (fputs("\t${NORMAL_C}\n\n", fp) == EOF) 510 return (1); 511 512 if (fprintf(fp, "new%s:\n", nm) < 0) 513 return (1); 514 if (fprintf(fp, 515 "\t${MAKE_GAP}\n" 516 "\t${SYSTEM_LD_HEAD}\n" 517 "\t${SYSTEM_LD} swap%s.o\n" 518 "\t${SYSTEM_LD_TAIL}\n" 519 "\trm -f %s.gdb\n" 520 "\tmv -f new%s %s\n\n", 521 swname, nm, nm, nm) < 0) 522 return (1); 523 524 if (fprintf(fp, "update-link:\n") < 0) 525 return (1); 526 if (fprintf(fp, 527 "\tmkdir -p -m 700 /usr/share/relink/kernel\n" 528 "\trm -rf /usr/share/relink/kernel/%s /usr/share/relink/kernel.tgz\n" 529 "\tmkdir /usr/share/relink/kernel/%s\n" 530 "\ttar -chf - Makefile makegap.sh ld.script *.o | \\\n" 531 "\t tar -C /usr/share/relink/kernel/%s -xf -\n\n", 532 last_component, last_component, last_component) < 0) 533 return (1); 534 } 535 return (0); 536} 537