mkmakefile.c revision 160495
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 160495 2006-07-19 10:46:38Z stefanf $"; 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 STAILQ_INSERT_TAIL(&ftab, fp, f_next); 102 return (fp); 103} 104 105/* 106 * Build the makefile from the skeleton 107 */ 108void 109makefile(void) 110{ 111 FILE *ifp, *ofp; 112 char line[BUFSIZ]; 113 struct opt *op; 114 int versreq; 115 116 read_files(); 117 snprintf(line, sizeof(line), "../../conf/Makefile.%s", machinename); 118 ifp = fopen(line, "r"); 119 if (ifp == 0) { 120 snprintf(line, sizeof(line), "Makefile.%s", machinename); 121 ifp = fopen(line, "r"); 122 } 123 if (ifp == 0) 124 err(1, "%s", line); 125 126 ofp = fopen(path("Makefile.new"), "w"); 127 if (ofp == 0) 128 err(1, "%s", path("Makefile.new")); 129 fprintf(ofp, "KERN_IDENT=%s\n", ident); 130 SLIST_FOREACH(op, &mkopt, op_next) 131 fprintf(ofp, "%s=%s\n", op->op_name, op->op_value); 132 if (debugging) 133 fprintf(ofp, "DEBUG=-g\n"); 134 if (profiling) 135 fprintf(ofp, "PROFLEVEL=%d\n", profiling); 136 if (*srcdir != '\0') 137 fprintf(ofp,"S=%s\n", srcdir); 138 while (fgets(line, BUFSIZ, ifp) != 0) { 139 if (*line != '%') { 140 fprintf(ofp, "%s", line); 141 continue; 142 } 143 if (eq(line, "%BEFORE_DEPEND\n")) 144 do_before_depend(ofp); 145 else if (eq(line, "%OBJS\n")) 146 do_objs(ofp); 147 else if (strncmp(line, "%FILES.", 7) == 0) 148 do_xxfiles(line, ofp); 149 else if (eq(line, "%RULES\n")) 150 do_rules(ofp); 151 else if (eq(line, "%CLEAN\n")) 152 do_clean(ofp); 153 else if (strncmp(line, "%VERSREQ=", sizeof("%VERSREQ=") - 1) == 0) { 154 versreq = atoi(line + sizeof("%VERSREQ=") - 1); 155 if (MAJOR_VERS(versreq) != MAJOR_VERS(CONFIGVERS) || 156 versreq > CONFIGVERS) { 157 fprintf(stderr, "ERROR: version of config(8) does not match kernel!\n"); 158 fprintf(stderr, "config version = %d, ", CONFIGVERS); 159 fprintf(stderr, "version required = %d\n\n", versreq); 160 fprintf(stderr, "Make sure that /usr/src/usr.sbin/config is in sync\n"); 161 fprintf(stderr, "with your /usr/src/sys and install a new config binary\n"); 162 fprintf(stderr, "before trying this again.\n\n"); 163 fprintf(stderr, "If running the new config fails check your config\n"); 164 fprintf(stderr, "file against the GENERIC or LINT config files for\n"); 165 fprintf(stderr, "changes in config syntax, or option/device naming\n"); 166 fprintf(stderr, "conventions\n\n"); 167 exit(1); 168 } 169 } else 170 fprintf(stderr, 171 "Unknown %% construct in generic makefile: %s", 172 line); 173 } 174 (void) fclose(ifp); 175 (void) fclose(ofp); 176 moveifchanged(path("Makefile.new"), path("Makefile")); 177} 178 179/* 180 * Build hints.c from the skeleton 181 */ 182void 183makehints(void) 184{ 185 FILE *ifp, *ofp; 186 char line[BUFSIZ]; 187 char *s; 188 189 if (hints) { 190 ifp = fopen(hints, "r"); 191 if (ifp == NULL) 192 err(1, "%s", hints); 193 } else { 194 ifp = NULL; 195 } 196 ofp = fopen(path("hints.c.new"), "w"); 197 if (ofp == NULL) 198 err(1, "%s", path("hints.c.new")); 199 fprintf(ofp, "#include <sys/types.h>\n"); 200 fprintf(ofp, "#include <sys/systm.h>\n"); 201 fprintf(ofp, "\n"); 202 fprintf(ofp, "int hintmode = %d;\n", hintmode); 203 fprintf(ofp, "char static_hints[] = {\n"); 204 if (ifp) { 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 } 235 fprintf(ofp, "\"\\0\"\n};\n"); 236 if (ifp) 237 fclose(ifp); 238 fclose(ofp); 239 moveifchanged(path("hints.c.new"), path("hints.c")); 240} 241 242/* 243 * Build env.c from the skeleton 244 */ 245void 246makeenv(void) 247{ 248 FILE *ifp, *ofp; 249 char line[BUFSIZ]; 250 char *s; 251 252 if (env) { 253 ifp = fopen(env, "r"); 254 if (ifp == NULL) 255 err(1, "%s", env); 256 } else { 257 ifp = NULL; 258 } 259 ofp = fopen(path("env.c.new"), "w"); 260 if (ofp == NULL) 261 err(1, "%s", path("env.c.new")); 262 fprintf(ofp, "#include <sys/types.h>\n"); 263 fprintf(ofp, "#include <sys/systm.h>\n"); 264 fprintf(ofp, "\n"); 265 fprintf(ofp, "int envmode = %d;\n", envmode); 266 fprintf(ofp, "char static_env[] = {\n"); 267 if (ifp) { 268 while (fgets(line, BUFSIZ, ifp) != 0) { 269 /* zap trailing CR and/or LF */ 270 while ((s = rindex(line, '\n')) != NULL) 271 *s = '\0'; 272 while ((s = rindex(line, '\r')) != NULL) 273 *s = '\0'; 274 /* remove # comments */ 275 s = index(line, '#'); 276 if (s) 277 *s = '\0'; 278 /* remove any whitespace and " characters */ 279 s = line; 280 while (*s) { 281 if (*s == ' ' || *s == '\t' || *s == '"') { 282 while (*s) { 283 s[0] = s[1]; 284 s++; 285 } 286 /* start over */ 287 s = line; 288 continue; 289 } 290 s++; 291 } 292 /* anything left? */ 293 if (*line == '\0') 294 continue; 295 fprintf(ofp, "\"%s\\0\"\n", line); 296 } 297 } 298 fprintf(ofp, "\"\\0\"\n};\n"); 299 if (ifp) 300 fclose(ifp); 301 fclose(ofp); 302 moveifchanged(path("env.c.new"), path("env.c")); 303} 304 305static void 306read_file(char *fname) 307{ 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 * filename [ standard | mandatory | optional ] 322 * [ dev* [ | dev* ... ] | profiling-routine ] [ no-obj ] 323 * [ compile-with "compile rule" [no-implicit-rule] ] 324 * [ dependency "dependency-list"] [ before-depend ] 325 * [ clean "file-list"] [ warning "text warning" ] 326 */ 327 wd = get_word(fp); 328 if (wd == (char *)EOF) { 329 (void) fclose(fp); 330 return; 331 } 332 if (wd == 0) 333 goto next; 334 if (wd[0] == '#') 335 { 336 while (((wd = get_word(fp)) != (char *)EOF) && wd) 337 ; 338 goto next; 339 } 340 this = ns(wd); 341 next_word(fp, wd); 342 if (wd == 0) { 343 printf("%s: No type for %s.\n", 344 fname, this); 345 exit(1); 346 } 347 tp = fl_lookup(this); 348 compile = 0; 349 match = 1; 350 nreqs = 0; 351 compilewith = 0; 352 depends = 0; 353 clean = 0; 354 warning = 0; 355 std = mandatory = 0; 356 imp_rule = 0; 357 no_obj = 0; 358 before_depend = 0; 359 nowerror = 0; 360 filetype = NORMAL; 361 if (eq(wd, "standard")) { 362 std = 1; 363 /* 364 * If an entry is marked "mandatory", config will abort if it's 365 * not called by a configuration line in the config file. Apart 366 * from this, the device is handled like one marked "optional". 367 */ 368 } else if (eq(wd, "mandatory")) { 369 mandatory = 1; 370 } else if (!eq(wd, "optional")) { 371 printf("%s: %s must be optional, mandatory or standard\n", 372 fname, this); 373 exit(1); 374 } 375nextparam: 376 next_word(fp, wd); 377 if (wd == 0) { 378 compile += match; 379 if (compile && tp == NULL) 380 goto doneparam; 381 goto next; 382 } 383 if (eq(wd, "|")) { 384 if (nreqs == 0) { 385 printf("%s: syntax error describing %s\n", 386 fname, this); 387 exit(1); 388 } 389 compile += match; 390 match = 1; 391 nreqs = 0; 392 goto nextparam; 393 } 394 if (eq(wd, "no-obj")) { 395 no_obj++; 396 goto nextparam; 397 } 398 if (eq(wd, "no-implicit-rule")) { 399 if (compilewith == 0) { 400 printf("%s: alternate rule required when " 401 "\"no-implicit-rule\" is specified.\n", 402 fname); 403 } 404 imp_rule++; 405 goto nextparam; 406 } 407 if (eq(wd, "before-depend")) { 408 before_depend++; 409 goto nextparam; 410 } 411 if (eq(wd, "dependency")) { 412 next_quoted_word(fp, wd); 413 if (wd == 0) { 414 printf("%s: %s missing compile command string.\n", 415 fname, this); 416 exit(1); 417 } 418 depends = ns(wd); 419 goto nextparam; 420 } 421 if (eq(wd, "clean")) { 422 next_quoted_word(fp, wd); 423 if (wd == 0) { 424 printf("%s: %s missing clean file list.\n", 425 fname, this); 426 exit(1); 427 } 428 clean = ns(wd); 429 goto nextparam; 430 } 431 if (eq(wd, "compile-with")) { 432 next_quoted_word(fp, wd); 433 if (wd == 0) { 434 printf("%s: %s missing compile command string.\n", 435 fname, this); 436 exit(1); 437 } 438 compilewith = ns(wd); 439 goto nextparam; 440 } 441 if (eq(wd, "warning")) { 442 next_quoted_word(fp, wd); 443 if (wd == 0) { 444 printf("%s: %s missing warning text string.\n", 445 fname, this); 446 exit(1); 447 } 448 warning = ns(wd); 449 goto nextparam; 450 } 451 nreqs++; 452 if (eq(wd, "local")) { 453 filetype = LOCAL; 454 goto nextparam; 455 } 456 if (eq(wd, "no-depend")) { 457 filetype = NODEPEND; 458 goto nextparam; 459 } 460 if (eq(wd, "profiling-routine")) { 461 filetype = PROFILING; 462 goto nextparam; 463 } 464 if (eq(wd, "nowerror")) { 465 nowerror = 1; 466 goto nextparam; 467 } 468 STAILQ_FOREACH(dp, &dtab, d_next) 469 if (eq(dp->d_name, wd)) { 470 dp->d_done |= DEVDONE; 471 goto nextparam; 472 } 473 if (mandatory) { 474 printf("%s: mandatory device \"%s\" not found\n", 475 fname, wd); 476 exit(1); 477 } 478 if (std) { 479 printf("standard entry %s has a device keyword - %s!\n", 480 this, wd); 481 exit(1); 482 } 483 SLIST_FOREACH(op, &opt, op_next) 484 if (op->op_value == 0 && opteq(op->op_name, wd)) 485 goto nextparam; 486 match = 0; 487 goto nextparam; 488 489doneparam: 490 if (std == 0 && nreqs == 0) { 491 printf("%s: what is %s optional on?\n", 492 fname, this); 493 exit(1); 494 } 495 496 if (wd) { 497 printf("%s: syntax error describing %s\n", 498 fname, this); 499 exit(1); 500 } 501 if (filetype == PROFILING && profiling == 0) 502 goto next; 503 tp = new_fent(); 504 tp->f_fn = this; 505 tp->f_type = filetype; 506 if (imp_rule) 507 tp->f_flags |= NO_IMPLCT_RULE; 508 if (no_obj) 509 tp->f_flags |= NO_OBJ; 510 if (before_depend) 511 tp->f_flags |= BEFORE_DEPEND; 512 if (nowerror) 513 tp->f_flags |= NOWERROR; 514 tp->f_compilewith = compilewith; 515 tp->f_depends = depends; 516 tp->f_clean = clean; 517 tp->f_warn = warning; 518 goto next; 519} 520 521/* 522 * Read in the information about files used in making the system. 523 * Store it in the ftab linked list. 524 */ 525static void 526read_files(void) 527{ 528 char fname[MAXPATHLEN]; 529 struct files_name *nl, *tnl; 530 531 (void) snprintf(fname, sizeof(fname), "../../conf/files"); 532 read_file(fname); 533 (void) snprintf(fname, sizeof(fname), 534 "../../conf/files.%s", machinename); 535 read_file(fname); 536 for (nl = STAILQ_FIRST(&fntab); nl != NULL; nl = tnl) { 537 read_file(nl->f_name); 538 tnl = STAILQ_NEXT(nl, f_next); 539 free(nl->f_name); 540 free(nl); 541 } 542} 543 544static int 545opteq(const char *cp, const char *dp) 546{ 547 char c, d; 548 549 for (; ; cp++, dp++) { 550 if (*cp != *dp) { 551 c = isupper(*cp) ? tolower(*cp) : *cp; 552 d = isupper(*dp) ? tolower(*dp) : *dp; 553 if (c != d) 554 return (0); 555 } 556 if (*cp == 0) 557 return (1); 558 } 559} 560 561static void 562do_before_depend(FILE *fp) 563{ 564 struct file_list *tp; 565 int lpos, len; 566 567 fputs("BEFORE_DEPEND=", fp); 568 lpos = 15; 569 STAILQ_FOREACH(tp, &ftab, f_next) 570 if (tp->f_flags & BEFORE_DEPEND) { 571 len = strlen(tp->f_fn); 572 if ((len = 3 + len) + lpos > 72) { 573 lpos = 8; 574 fputs("\\\n\t", fp); 575 } 576 if (tp->f_flags & NO_IMPLCT_RULE) 577 fprintf(fp, "%s ", tp->f_fn); 578 else 579 fprintf(fp, "$S/%s ", tp->f_fn); 580 lpos += len + 1; 581 } 582 if (lpos != 8) 583 putc('\n', fp); 584} 585 586static void 587do_objs(FILE *fp) 588{ 589 struct file_list *tp; 590 int lpos, len; 591 char *cp, och, *sp; 592 593 fprintf(fp, "OBJS="); 594 lpos = 6; 595 STAILQ_FOREACH(tp, &ftab, f_next) { 596 if (tp->f_flags & NO_OBJ) 597 continue; 598 sp = tail(tp->f_fn); 599 cp = sp + (len = strlen(sp)) - 1; 600 och = *cp; 601 *cp = 'o'; 602 if (len + lpos > 72) { 603 lpos = 8; 604 fprintf(fp, "\\\n\t"); 605 } 606 fprintf(fp, "%s ", sp); 607 lpos += len + 1; 608 *cp = och; 609 } 610 if (lpos != 8) 611 putc('\n', fp); 612} 613 614static void 615do_xxfiles(char *tag, FILE *fp) 616{ 617 struct file_list *tp; 618 int lpos, len, slen; 619 char *suff, *SUFF; 620 621 if (tag[strlen(tag) - 1] == '\n') 622 tag[strlen(tag) - 1] = '\0'; 623 624 suff = ns(tag + 7); 625 SUFF = ns(suff); 626 raisestr(SUFF); 627 slen = strlen(suff); 628 629 fprintf(fp, "%sFILES=", SUFF); 630 lpos = 8; 631 STAILQ_FOREACH(tp, &ftab, f_next) 632 if (tp->f_type != NODEPEND) { 633 len = strlen(tp->f_fn); 634 if (tp->f_fn[len - slen - 1] != '.') 635 continue; 636 if (strcasecmp(&tp->f_fn[len - slen], suff) != 0) 637 continue; 638 if ((len = 3 + len) + lpos > 72) { 639 lpos = 8; 640 fputs("\\\n\t", fp); 641 } 642 if (tp->f_type != LOCAL) 643 fprintf(fp, "$S/%s ", tp->f_fn); 644 else 645 fprintf(fp, "%s ", tp->f_fn); 646 lpos += len + 1; 647 } 648 if (lpos != 8) 649 putc('\n', fp); 650} 651 652static char * 653tail(char *fn) 654{ 655 char *cp; 656 657 cp = rindex(fn, '/'); 658 if (cp == 0) 659 return (fn); 660 return (cp+1); 661} 662 663/* 664 * Create the makerules for each file 665 * which is part of the system. 666 */ 667static void 668do_rules(FILE *f) 669{ 670 char *cp, *np, och; 671 struct file_list *ftp; 672 char *compilewith; 673 674 STAILQ_FOREACH(ftp, &ftab, f_next) { 675 if (ftp->f_warn) 676 printf("WARNING: %s\n", ftp->f_warn); 677 cp = (np = ftp->f_fn) + strlen(ftp->f_fn) - 1; 678 och = *cp; 679 if (ftp->f_flags & NO_IMPLCT_RULE) { 680 if (ftp->f_depends) 681 fprintf(f, "%s: %s\n", np, ftp->f_depends); 682 else 683 fprintf(f, "%s: \n", np); 684 } 685 else { 686 *cp = '\0'; 687 if (och == 'o') { 688 fprintf(f, "%so:\n\t-cp $S/%so .\n\n", 689 tail(np), np); 690 continue; 691 } 692 if (ftp->f_depends) { 693 fprintf(f, "%sln: $S/%s%c %s\n", tail(np), 694 np, och, ftp->f_depends); 695 fprintf(f, "\t${NORMAL_LINT}\n\n"); 696 fprintf(f, "%so: $S/%s%c %s\n", tail(np), 697 np, och, ftp->f_depends); 698 } 699 else { 700 fprintf(f, "%sln: $S/%s%c\n", tail(np), 701 np, och); 702 fprintf(f, "\t${NORMAL_LINT}\n\n"); 703 fprintf(f, "%so: $S/%s%c\n", tail(np), 704 np, och); 705 } 706 } 707 compilewith = ftp->f_compilewith; 708 if (compilewith == 0) { 709 const char *ftype = NULL; 710 static char cmd[128]; 711 712 switch (ftp->f_type) { 713 714 case NORMAL: 715 ftype = "NORMAL"; 716 break; 717 718 case PROFILING: 719 if (!profiling) 720 continue; 721 ftype = "PROFILE"; 722 break; 723 724 default: 725 printf("config: don't know rules for %s\n", np); 726 break; 727 } 728 snprintf(cmd, sizeof(cmd), "${%s_%c%s}", ftype, 729 toupper(och), 730 ftp->f_flags & NOWERROR ? "_NOWERROR" : ""); 731 compilewith = cmd; 732 } 733 *cp = och; 734 fprintf(f, "\t%s\n\n", compilewith); 735 } 736} 737 738static void 739do_clean(FILE *fp) 740{ 741 struct file_list *tp; 742 int lpos, len; 743 744 fputs("CLEAN=", fp); 745 lpos = 7; 746 STAILQ_FOREACH(tp, &ftab, f_next) 747 if (tp->f_clean) { 748 len = strlen(tp->f_clean); 749 if (len + lpos > 72) { 750 lpos = 8; 751 fputs("\\\n\t", fp); 752 } 753 fprintf(fp, "%s ", tp->f_clean); 754 lpos += len + 1; 755 } 756 if (lpos != 8) 757 putc('\n', fp); 758} 759 760char * 761raisestr(char *str) 762{ 763 char *cp = str; 764 765 while (*str) { 766 if (islower(*str)) 767 *str = toupper(*str); 768 str++; 769 } 770 return (cp); 771} 772