1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1980, 1990, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #ifndef lint 33 #if 0 34 static char sccsid[] = "@(#)mkmakefile.c 8.1 (Berkeley) 6/6/93"; 35 #endif 36 static const char rcsid[] = 37 "$FreeBSD$"; 38 #endif /* not lint */ 39 40 /* 41 * Build the makefile for the system, from 42 * the information in the files files and the 43 * additional files for the machine being compiled to. 44 */ 45 #include <sys/param.h> 46 47 #include <ctype.h> 48 #include <err.h> 49 #include <stdarg.h> 50 #include <stdbool.h> 51 #include <stdio.h> 52 #include <string.h> 53 #include <string> 54 #include <unordered_map> 55 56 #include "y.tab.h" 57 #include "config.h" 58 #include "configvers.h" 59 60 typedef std::unordered_map<std::string, std::string> env_map; 61 62 static char *tail(char *); 63 static void do_clean(FILE *); 64 static void do_rules(FILE *); 65 static void do_xxfiles(char *, FILE *); 66 static void do_objs(FILE *); 67 static void do_before_depend(FILE *); 68 static void read_files(void); 69 static void sanitize_envline(char *result, const char *src); 70 static bool preprocess(char *line, char *result); 71 static void process_into_file(char *line, FILE *ofp); 72 static void process_into_map(char *line, env_map &emap); 73 static void dump_map(env_map &emap, FILE *ofp); 74 75 static void errout(const char *fmt, ...) 76 { 77 va_list ap; 78 79 va_start(ap, fmt); 80 vfprintf(stderr, fmt, ap); 81 va_end(ap); 82 exit(1); 83 } 84 85 /* 86 * Lookup a file, by name. 87 */ 88 static struct file_list * 89 fl_lookup(char *file) 90 { 91 struct file_list *fp; 92 93 STAILQ_FOREACH(fp, &ftab, f_next) { 94 if (eq(fp->f_fn, file)) 95 return (fp); 96 } 97 return (0); 98 } 99 100 /* 101 * Make a new file list entry 102 */ 103 static struct file_list * 104 new_fent(void) 105 { 106 struct file_list *fp; 107 108 fp = (struct file_list *) calloc(1, sizeof *fp); 109 if (fp == NULL) 110 err(EXIT_FAILURE, "calloc"); 111 STAILQ_INSERT_TAIL(&ftab, fp, f_next); 112 return (fp); 113 } 114 115 /* 116 * Open the correct Makefile and return it, or error out. 117 */ 118 FILE * 119 open_makefile_template(void) 120 { 121 FILE *ifp; 122 char line[BUFSIZ]; 123 124 snprintf(line, sizeof(line), "../../conf/Makefile.%s", machinename); 125 ifp = fopen(line, "r"); 126 if (ifp == NULL) { 127 snprintf(line, sizeof(line), "Makefile.%s", machinename); 128 ifp = fopen(line, "r"); 129 } 130 if (ifp == NULL) 131 err(1, "%s", line); 132 return (ifp); 133 } 134 135 /* 136 * Build the makefile from the skeleton 137 */ 138 void 139 makefile(void) 140 { 141 FILE *ifp, *ofp; 142 char line[BUFSIZ]; 143 struct opt *op, *t; 144 145 read_files(); 146 ifp = open_makefile_template(); 147 ofp = fopen(path("Makefile.new"), "w"); 148 if (ofp == NULL) 149 err(1, "%s", path("Makefile.new")); 150 fprintf(ofp, "KERN_IDENT=%s\n", ident); 151 fprintf(ofp, "MACHINE=%s\n", machinename); 152 fprintf(ofp, "MACHINE_ARCH=%s\n", machinearch); 153 SLIST_FOREACH_SAFE(op, &mkopt, op_next, t) { 154 fprintf(ofp, "%s=%s", op->op_name, op->op_value); 155 while ((op = SLIST_NEXT(op, op_append)) != NULL) 156 fprintf(ofp, " %s", op->op_value); 157 fprintf(ofp, "\n"); 158 } 159 if (debugging) 160 fprintf(ofp, "DEBUG=-g\n"); 161 if (*srcdir != '\0') 162 fprintf(ofp,"S=%s\n", srcdir); 163 while (fgets(line, BUFSIZ, ifp) != NULL) { 164 if (*line != '%') { 165 fprintf(ofp, "%s", line); 166 continue; 167 } 168 if (eq(line, "%BEFORE_DEPEND\n")) 169 do_before_depend(ofp); 170 else if (eq(line, "%OBJS\n")) 171 do_objs(ofp); 172 else if (strncmp(line, "%FILES.", 7) == 0) 173 do_xxfiles(line, ofp); 174 else if (eq(line, "%RULES\n")) 175 do_rules(ofp); 176 else if (eq(line, "%CLEAN\n")) 177 do_clean(ofp); 178 else if (strncmp(line, "%VERSREQ=", 9) == 0) 179 line[0] = '\0'; /* handled elsewhere */ 180 else 181 fprintf(stderr, 182 "Unknown %% construct in generic makefile: %s", 183 line); 184 } 185 (void) fclose(ifp); 186 (void) fclose(ofp); 187 moveifchanged(path("Makefile.new"), path("Makefile")); 188 } 189 190 static void 191 sanitize_envline(char *result, const char *src) 192 { 193 const char *eq; 194 char c, *dst; 195 bool leading; 196 197 /* If there is no '=' it's not a well-formed name=value line. */ 198 if ((eq = strchr(src, '=')) == NULL) { 199 *result = '\0'; 200 return; 201 } 202 dst = result; 203 204 /* Copy chars before the '=', skipping any leading spaces/quotes. */ 205 leading = true; 206 while (src < eq) { 207 c = *src++; 208 if (leading && (isspace(c) || c == '"')) 209 continue; 210 *dst++ = c; 211 leading = false; 212 } 213 214 /* If it was all leading space, we don't have a well-formed line. */ 215 if (leading) { 216 *result = '\0'; 217 return; 218 } 219 220 /* Trim spaces/quotes immediately before the '=', then copy the '='. */ 221 while (isspace(dst[-1]) || dst[-1] == '"') 222 --dst; 223 *dst++ = *src++; 224 225 /* Copy chars after the '=', skipping any leading whitespace. */ 226 leading = true; 227 while ((c = *src++) != '\0') { 228 if (leading && (isspace(c) || c == '"')) 229 continue; 230 *dst++ = c; 231 leading = false; 232 } 233 234 /* If it was all leading space, it's a valid 'var=' (nil value). */ 235 if (leading) { 236 *dst = '\0'; 237 return; 238 } 239 240 /* Trim trailing whitespace and quotes. */ 241 while (isspace(dst[-1]) || dst[-1] == '"') 242 --dst; 243 244 *dst = '\0'; 245 } 246 247 /* 248 * Returns true if the caller may use the string. 249 */ 250 static bool 251 preprocess(char *line, char *result) 252 { 253 char *s; 254 255 /* Strip any comments */ 256 if ((s = strchr(line, '#')) != NULL) 257 *s = '\0'; 258 sanitize_envline(result, line); 259 /* Return true if it's non-empty */ 260 return (*result != '\0'); 261 } 262 263 static void 264 process_into_file(char *line, FILE *ofp) 265 { 266 char result[BUFSIZ]; 267 268 if (preprocess(line, result)) 269 fprintf(ofp, "\"%s\\0\"\n", result); 270 } 271 272 static void 273 process_into_map(char *line, env_map &emap) 274 { 275 char result[BUFSIZ], *s; 276 277 if (preprocess(line, result)) { 278 s = strchr(result, '='); 279 *s = '\0'; 280 emap[result] = s + 1; 281 } 282 } 283 284 static void 285 dump_map(env_map &emap, FILE *ofp) 286 { 287 288 for (auto iter : emap) { 289 fprintf(ofp, "\"%s=%s\\0\"\n", iter.first.c_str(), 290 iter.second.c_str()); 291 } 292 } 293 294 /* 295 * Build hints.c from the skeleton 296 */ 297 void 298 makehints(void) 299 { 300 FILE *ifp, *ofp; 301 env_map emap; 302 char line[BUFSIZ]; 303 struct hint *hint; 304 305 ofp = fopen(path("hints.c.new"), "w"); 306 if (ofp == NULL) 307 err(1, "%s", path("hints.c.new")); 308 fprintf(ofp, "#include <sys/types.h>\n"); 309 fprintf(ofp, "#include <sys/systm.h>\n"); 310 fprintf(ofp, "\n"); 311 /* 312 * Write out hintmode for older kernels. Remove when config(8) major 313 * version rolls over. 314 */ 315 if (versreq <= CONFIGVERS_ENVMODE_REQ) 316 fprintf(ofp, "int hintmode = %d;\n", 317 !STAILQ_EMPTY(&hints) ? 1 : 0); 318 fprintf(ofp, "char static_hints[] = {\n"); 319 STAILQ_FOREACH(hint, &hints, hint_next) { 320 ifp = fopen(hint->hint_name, "r"); 321 if (ifp == NULL) 322 err(1, "%s", hint->hint_name); 323 while (fgets(line, BUFSIZ, ifp) != NULL) 324 process_into_map(line, emap); 325 dump_map(emap, ofp); 326 fclose(ifp); 327 } 328 fprintf(ofp, "\"\\0\"\n};\n"); 329 fclose(ofp); 330 moveifchanged(path("hints.c.new"), path("hints.c")); 331 } 332 333 /* 334 * Build env.c from the skeleton 335 */ 336 void 337 makeenv(void) 338 { 339 FILE *ifp, *ofp; 340 env_map emap; 341 char line[BUFSIZ]; 342 struct envvar *envvar; 343 344 ofp = fopen(path("env.c.new"), "w"); 345 if (ofp == NULL) 346 err(1, "%s", path("env.c.new")); 347 fprintf(ofp, "#include <sys/types.h>\n"); 348 fprintf(ofp, "#include <sys/systm.h>\n"); 349 fprintf(ofp, "\n"); 350 /* 351 * Write out envmode for older kernels. Remove when config(8) major 352 * version rolls over. 353 */ 354 if (versreq <= CONFIGVERS_ENVMODE_REQ) 355 fprintf(ofp, "int envmode = %d;\n", 356 !STAILQ_EMPTY(&envvars) ? 1 : 0); 357 fprintf(ofp, "char static_env[] = {\n"); 358 STAILQ_FOREACH(envvar, &envvars, envvar_next) { 359 if (envvar->env_is_file) { 360 ifp = fopen(envvar->env_str, "r"); 361 if (ifp == NULL) 362 err(1, "%s", envvar->env_str); 363 while (fgets(line, BUFSIZ, ifp) != NULL) 364 process_into_map(line, emap); 365 dump_map(emap, ofp); 366 fclose(ifp); 367 } else 368 process_into_file(envvar->env_str, ofp); 369 } 370 fprintf(ofp, "\"\\0\"\n};\n"); 371 fclose(ofp); 372 moveifchanged(path("env.c.new"), path("env.c")); 373 } 374 375 static void 376 read_file(char *fname) 377 { 378 char ifname[MAXPATHLEN]; 379 FILE *fp; 380 struct file_list *tp; 381 struct device *dp; 382 struct opt *op; 383 configword wd; 384 char *rfile, *compilewith, *depends, *clean, *warning; 385 const char *objprefix; 386 int compile, match, nreqs, std, filetype, negate, 387 imp_rule, no_ctfconvert, no_obj, before_depend, nowerror; 388 389 fp = fopen(fname, "r"); 390 if (fp == NULL) 391 err(1, "%s", fname); 392 next: 393 /* 394 * include "filename" 395 * filename [ standard | optional ] 396 * [ dev* [ | dev* ... ] | [ no-obj ] 397 * [ compile-with "compile rule" [no-implicit-rule] ] 398 * [ dependency "dependency-list"] [ before-depend ] 399 * [ clean "file-list"] [ warning "text warning" ] 400 * [ obj-prefix "file prefix"] 401 * [ nowerror ] [ local ] 402 */ 403 wd = get_word(fp); 404 if (wd.eof()) { 405 (void) fclose(fp); 406 return; 407 } 408 if (wd.eol()) 409 goto next; 410 if (wd[0] == '#') 411 { 412 while (!(wd = get_word(fp)).eof() && !wd.eol()) 413 ; 414 goto next; 415 } 416 if (eq(wd, "include")) { 417 wd = get_quoted_word(fp); 418 if (wd.eof() || wd.eol()) 419 errout("%s: missing include filename.\n", fname); 420 (void) snprintf(ifname, sizeof(ifname), "../../%s", 421 wd->c_str()); 422 read_file(ifname); 423 while (!(wd = get_word(fp)).eof() && !wd.eol()) 424 ; 425 goto next; 426 } 427 rfile = ns(wd); 428 wd = get_word(fp); 429 if (wd.eof()) 430 return; 431 if (wd.eol()) 432 errout("%s: No type for %s.\n", fname, rfile); 433 tp = fl_lookup(rfile); 434 compile = 0; 435 match = 1; 436 nreqs = 0; 437 compilewith = NULL; 438 depends = NULL; 439 clean = NULL; 440 warning = NULL; 441 std = 0; 442 imp_rule = 0; 443 no_ctfconvert = 0; 444 no_obj = 0; 445 before_depend = 0; 446 nowerror = 0; 447 negate = 0; 448 filetype = NORMAL; 449 objprefix = ""; 450 if (eq(wd, "standard")) 451 std = 1; 452 else if (!eq(wd, "optional")) 453 errout("%s: \"%s\" %s must be optional or standard\n", 454 fname, wd->c_str(), rfile); 455 for (wd = get_word(fp); !wd.eol(); wd = get_word(fp)) { 456 if (wd.eof()) 457 return; 458 if (eq(wd, "!")) { 459 negate = 1; 460 continue; 461 } 462 if (eq(wd, "|")) { 463 if (nreqs == 0) 464 errout("%s: syntax error describing %s\n", 465 fname, rfile); 466 compile += match; 467 match = 1; 468 nreqs = 0; 469 continue; 470 } 471 if (eq(wd, "no-ctfconvert")) { 472 no_ctfconvert++; 473 continue; 474 } 475 if (eq(wd, "no-obj")) { 476 no_obj++; 477 continue; 478 } 479 if (eq(wd, "no-implicit-rule")) { 480 if (compilewith == NULL) 481 errout("%s: alternate rule required when " 482 "\"no-implicit-rule\" is specified for" 483 " %s.\n", 484 fname, rfile); 485 imp_rule++; 486 continue; 487 } 488 if (eq(wd, "before-depend")) { 489 before_depend++; 490 continue; 491 } 492 if (eq(wd, "dependency")) { 493 wd = get_quoted_word(fp); 494 if (wd.eof() || wd.eol()) 495 errout("%s: %s missing dependency string.\n", 496 fname, rfile); 497 depends = ns(wd); 498 continue; 499 } 500 if (eq(wd, "clean")) { 501 wd = get_quoted_word(fp); 502 if (wd.eof() || wd.eol()) 503 errout("%s: %s missing clean file list.\n", 504 fname, rfile); 505 clean = ns(wd); 506 continue; 507 } 508 if (eq(wd, "compile-with")) { 509 wd = get_quoted_word(fp); 510 if (wd.eof() || wd.eol()) 511 errout("%s: %s missing compile command string.\n", 512 fname, rfile); 513 compilewith = ns(wd); 514 continue; 515 } 516 if (eq(wd, "warning")) { 517 wd = get_quoted_word(fp); 518 if (wd.eof() || wd.eol()) 519 errout("%s: %s missing warning text string.\n", 520 fname, rfile); 521 warning = ns(wd); 522 continue; 523 } 524 if (eq(wd, "obj-prefix")) { 525 wd = get_quoted_word(fp); 526 if (wd.eof() || wd.eol()) 527 errout("%s: %s missing object prefix string.\n", 528 fname, rfile); 529 objprefix = ns(wd); 530 continue; 531 } 532 if (eq(wd, "nowerror")) { 533 nowerror = 1; 534 continue; 535 } 536 if (eq(wd, "local")) { 537 filetype = LOCAL; 538 continue; 539 } 540 if (eq(wd, "no-depend")) { 541 filetype = NODEPEND; 542 continue; 543 } 544 nreqs++; 545 if (std) 546 errout("standard entry %s has optional inclusion specifier %s!\n", 547 rfile, wd->c_str()); 548 STAILQ_FOREACH(dp, &dtab, d_next) 549 if (eq(dp->d_name, wd)) { 550 if (negate) 551 match = 0; 552 else 553 dp->d_done |= DEVDONE; 554 goto nextparam; 555 } 556 SLIST_FOREACH(op, &opt, op_next) 557 if (op->op_value == 0 && 558 strcasecmp(op->op_name, wd) == 0) { 559 if (negate) 560 match = 0; 561 goto nextparam; 562 } 563 match &= negate; 564 nextparam:; 565 negate = 0; 566 } 567 compile += match; 568 if (compile && tp == NULL) { 569 if (std == 0 && nreqs == 0) 570 errout("%s: what is %s optional on?\n", 571 fname, rfile); 572 tp = new_fent(); 573 tp->f_fn = rfile; 574 tp->f_type = filetype; 575 if (filetype == LOCAL) 576 tp->f_srcprefix = ""; 577 else 578 tp->f_srcprefix = "$S/"; 579 if (imp_rule) 580 tp->f_flags |= NO_IMPLCT_RULE; 581 if (no_ctfconvert) 582 tp->f_flags |= NO_CTFCONVERT; 583 if (no_obj) 584 tp->f_flags |= NO_OBJ | NO_CTFCONVERT; 585 if (before_depend) 586 tp->f_flags |= BEFORE_DEPEND; 587 if (nowerror) 588 tp->f_flags |= NOWERROR; 589 tp->f_compilewith = compilewith; 590 tp->f_depends = depends; 591 tp->f_clean = clean; 592 tp->f_warn = warning; 593 tp->f_objprefix = objprefix; 594 } 595 goto next; 596 } 597 598 /* 599 * Read in the information about files used in making the system. 600 * Store it in the ftab linked list. 601 */ 602 static void 603 read_files(void) 604 { 605 char fname[MAXPATHLEN]; 606 struct files_name *nl, *tnl; 607 608 (void) snprintf(fname, sizeof(fname), "../../conf/files"); 609 read_file(fname); 610 (void) snprintf(fname, sizeof(fname), 611 "../../conf/files.%s", machinename); 612 read_file(fname); 613 for (nl = STAILQ_FIRST(&fntab); nl != NULL; nl = tnl) { 614 read_file(nl->f_name); 615 tnl = STAILQ_NEXT(nl, f_next); 616 free(nl->f_name); 617 free(nl); 618 } 619 } 620 621 static void 622 do_before_depend(FILE *fp) 623 { 624 struct file_list *tp; 625 int lpos, len; 626 627 fputs("BEFORE_DEPEND=", fp); 628 lpos = 15; 629 STAILQ_FOREACH(tp, &ftab, f_next) 630 if (tp->f_flags & BEFORE_DEPEND) { 631 len = strlen(tp->f_fn) + strlen(tp->f_srcprefix); 632 if (len + lpos > 72) { 633 lpos = 8; 634 fputs("\\\n\t", fp); 635 } 636 if (tp->f_flags & NO_IMPLCT_RULE) 637 lpos += fprintf(fp, "%s ", tp->f_fn); 638 else 639 lpos += fprintf(fp, "%s%s ", tp->f_srcprefix, 640 tp->f_fn); 641 } 642 if (lpos != 8) 643 putc('\n', fp); 644 } 645 646 static void 647 do_objs(FILE *fp) 648 { 649 struct file_list *tp; 650 int lpos, len; 651 char *cp, och, *sp; 652 653 fprintf(fp, "OBJS="); 654 lpos = 6; 655 STAILQ_FOREACH(tp, &ftab, f_next) { 656 if (tp->f_flags & NO_OBJ) 657 continue; 658 sp = tail(tp->f_fn); 659 cp = sp + (len = strlen(sp)) - 1; 660 och = *cp; 661 *cp = 'o'; 662 len += strlen(tp->f_objprefix); 663 if (len + lpos > 72) { 664 lpos = 8; 665 fprintf(fp, "\\\n\t"); 666 } 667 fprintf(fp, "%s%s ", tp->f_objprefix, sp); 668 lpos += len + 1; 669 *cp = och; 670 } 671 if (lpos != 8) 672 putc('\n', fp); 673 } 674 675 static void 676 do_xxfiles(char *tag, FILE *fp) 677 { 678 struct file_list *tp; 679 int lpos, len, slen; 680 char *suff, *SUFF; 681 682 if (tag[strlen(tag) - 1] == '\n') 683 tag[strlen(tag) - 1] = '\0'; 684 685 suff = ns(tag + 7); 686 SUFF = ns(suff); 687 raisestr(SUFF); 688 slen = strlen(suff); 689 690 fprintf(fp, "%sFILES=", SUFF); 691 free(SUFF); 692 lpos = 8; 693 STAILQ_FOREACH(tp, &ftab, f_next) 694 if (tp->f_type != NODEPEND) { 695 len = strlen(tp->f_fn); 696 if (tp->f_fn[len - slen - 1] != '.') 697 continue; 698 if (strcasecmp(&tp->f_fn[len - slen], suff) != 0) 699 continue; 700 if (len + strlen(tp->f_srcprefix) + lpos > 72) { 701 lpos = 8; 702 fputs("\\\n\t", fp); 703 } 704 lpos += fprintf(fp, "%s%s ", tp->f_srcprefix, tp->f_fn); 705 } 706 free(suff); 707 if (lpos != 8) 708 putc('\n', fp); 709 } 710 711 static char * 712 tail(char *fn) 713 { 714 char *cp; 715 716 cp = strrchr(fn, '/'); 717 if (cp == NULL) 718 return (fn); 719 return (cp+1); 720 } 721 722 /* 723 * Create the makerules for each file 724 * which is part of the system. 725 */ 726 static void 727 do_rules(FILE *f) 728 { 729 char *cp, *np, och; 730 struct file_list *ftp; 731 char *compilewith; 732 char cmd[128]; 733 734 STAILQ_FOREACH(ftp, &ftab, f_next) { 735 if (ftp->f_warn) 736 fprintf(stderr, "WARNING: %s\n", ftp->f_warn); 737 cp = (np = ftp->f_fn) + strlen(ftp->f_fn) - 1; 738 och = *cp; 739 if (ftp->f_flags & NO_IMPLCT_RULE) { 740 if (ftp->f_depends) 741 fprintf(f, "%s%s: %s\n", 742 ftp->f_objprefix, np, ftp->f_depends); 743 else 744 fprintf(f, "%s%s: \n", ftp->f_objprefix, np); 745 } 746 else { 747 *cp = '\0'; 748 if (och == 'o') { 749 fprintf(f, "%s%so:\n\t-cp %s%so .\n\n", 750 ftp->f_objprefix, tail(np), 751 ftp->f_srcprefix, np); 752 continue; 753 } 754 if (ftp->f_depends) { 755 fprintf(f, "%s%so: %s%s%c %s\n", 756 ftp->f_objprefix, tail(np), 757 ftp->f_srcprefix, np, och, 758 ftp->f_depends); 759 } 760 else { 761 fprintf(f, "%s%so: %s%s%c\n", 762 ftp->f_objprefix, tail(np), 763 ftp->f_srcprefix, np, och); 764 } 765 } 766 compilewith = ftp->f_compilewith; 767 if (compilewith == NULL) { 768 const char *ftype = NULL; 769 770 switch (ftp->f_type) { 771 case NORMAL: 772 ftype = "NORMAL"; 773 break; 774 default: 775 fprintf(stderr, 776 "config: don't know rules for %s\n", np); 777 break; 778 } 779 snprintf(cmd, sizeof(cmd), 780 "${%s_%c%s}", ftype, 781 toupper(och), 782 ftp->f_flags & NOWERROR ? "_NOWERROR" : ""); 783 compilewith = cmd; 784 } 785 *cp = och; 786 if (strlen(ftp->f_objprefix)) 787 fprintf(f, "\t%s %s%s\n", compilewith, 788 ftp->f_srcprefix, np); 789 else 790 fprintf(f, "\t%s\n", compilewith); 791 792 if (!(ftp->f_flags & NO_CTFCONVERT)) 793 fprintf(f, "\t${NORMAL_CTFCONVERT}\n\n"); 794 else 795 fprintf(f, "\n"); 796 } 797 } 798 799 static void 800 do_clean(FILE *fp) 801 { 802 struct file_list *tp; 803 int lpos, len; 804 805 fputs("CLEAN=", fp); 806 lpos = 7; 807 STAILQ_FOREACH(tp, &ftab, f_next) 808 if (tp->f_clean) { 809 len = strlen(tp->f_clean); 810 if (len + lpos > 72) { 811 lpos = 8; 812 fputs("\\\n\t", fp); 813 } 814 fprintf(fp, "%s ", tp->f_clean); 815 lpos += len + 1; 816 } 817 if (lpos != 8) 818 putc('\n', fp); 819 } 820 821 char * 822 raisestr(char *str) 823 { 824 char *cp = str; 825 826 while (*str) { 827 if (islower(*str)) 828 *str = toupper(*str); 829 str++; 830 } 831 return (cp); 832 } 833