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