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