1/* 2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights 7 * Reserved. This file contains Original Code and/or Modifications of 8 * Original Code as defined in and that are subject to the Apple Public 9 * Source License Version 1.0 (the 'License'). You may not use this file 10 * except in compliance with the License. Please obtain a copy of the 11 * License at http://www.apple.com/publicsource and read it before using 12 * this file. 13 * 14 * The Original Code and all software distributed under the License are 15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the 19 * License for the specific language governing rights and limitations 20 * under the License." 21 * 22 * @APPLE_LICENSE_HEADER_END@ 23 */ 24/* 25 * Mach Operating System 26 * Copyright (c) 1990 Carnegie-Mellon University 27 * Copyright (c) 1989 Carnegie-Mellon University 28 * Copyright (c) 1988 Carnegie-Mellon University 29 * Copyright (c) 1987 Carnegie-Mellon University 30 * All rights reserved. The CMU software License Agreement specifies 31 * the terms and conditions for use and redistribution. 32 */ 33 34/* 35 * Copyright (c) 1980 Regents of the University of California. 36 * All rights reserved. 37 * 38 * Redistribution and use in source and binary forms are permitted 39 * provided that the above copyright notice and this paragraph are 40 * duplicated in all such forms and that any documentation, 41 * advertising materials, and other materials related to such 42 * distribution and use acknowledge that the software was developed 43 * by the University of California, Berkeley. The name of the 44 * University may not be used to endorse or promote products derived 45 * from this software without specific prior written permission. 46 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 47 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 48 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 49 */ 50 51#ifndef lint 52static char sccsid[] __attribute__((used)) = "@(#)mkmakefile.c 5.21 (Berkeley) 6/18/88"; 53#endif /* not lint */ 54 55/* 56 * Build the makefile for the system, from 57 * the information in the files files and the 58 * additional files for the machine being compiled to. 59 */ 60 61#include <stdio.h> 62#include <unistd.h> /* for unlink */ 63#include <ctype.h> 64#include "parser.h" 65#include "config.h" 66 67void read_files(void); 68void do_objs(FILE *fp, const char *msg, int ext); 69void do_files(FILE *fp, const char *msg, char ext); 70void do_machdep(FILE *ofp); 71void do_rules(FILE *f); 72void copy_dependencies(FILE *makin, FILE *makout); 73 74struct file_list *fl_lookup(char *file); 75struct file_list *fltail_lookup(char *file); 76struct file_list *new_fent(void); 77 78void put_source_file_name(FILE *fp, struct file_list *tp); 79 80 81#define next_word(fp, wd) \ 82 { register const char *word = get_word(fp); \ 83 if (word == (char *)EOF) \ 84 return; \ 85 else \ 86 wd = word; \ 87 } 88 89static struct file_list *fcur; 90const char *tail(const char *fn); 91char *allCaps(char *str); 92 93/* 94 * Lookup a file, by name. 95 */ 96struct file_list * 97fl_lookup(char *file) 98{ 99 register struct file_list *fp; 100 101 for (fp = ftab ; fp != 0; fp = fp->f_next) { 102 if (eq(fp->f_fn, file)) 103 return (fp); 104 } 105 return (0); 106} 107 108/* 109 * Lookup a file, by final component name. 110 */ 111struct file_list * 112fltail_lookup(char *file) 113{ 114 register struct file_list *fp; 115 116 for (fp = ftab ; fp != 0; fp = fp->f_next) { 117 if (eq(tail(fp->f_fn), tail(file))) 118 return (fp); 119 } 120 return (0); 121} 122 123/* 124 * Make a new file list entry 125 */ 126struct file_list * 127new_fent(void) 128{ 129 register struct file_list *fp; 130 131 fp = (struct file_list *) malloc(sizeof *fp); 132 fp->f_needs = 0; 133 fp->f_next = 0; 134 fp->f_flags = 0; 135 fp->f_type = 0; 136 fp->f_extra = (char *) 0; 137 if (fcur == 0) 138 fcur = ftab = fp; 139 else 140 fcur->f_next = fp; 141 fcur = fp; 142 return (fp); 143} 144 145char *COPTS; 146 147const char * 148get_VPATH(void) 149{ 150 static char *vpath = NULL; 151 152 if ((vpath == NULL) && 153 ((vpath = getenv("VPATH")) != NULL) && 154 (*vpath != ':')) { 155 register char *buf = malloc((unsigned)(strlen(vpath) + 2)); 156 157 vpath = strcat(strcpy(buf, ":"), vpath); 158 } 159 160 return vpath ? vpath : ""; 161} 162 163 164/* 165 * Build the makefile from the skeleton 166 */ 167void 168makefile(void) 169{ 170 FILE *ifp, *ofp; 171 FILE *dfp; 172 char pname[BUFSIZ]; 173 char line[BUFSIZ]; 174 struct opt *op; 175 176 read_files(); 177 (void) sprintf(line, "%s/Makefile.template", config_directory); 178 ifp = fopenp(VPATH, line, pname, "r"); 179 if (ifp == 0) { 180 perror(line); 181 exit(1); 182 } 183 dfp = fopen(path("Makefile"), "r"); 184 rename(path("Makefile"), path("Makefile.old")); 185 unlink(path("Makefile.old")); 186 ofp = fopen(path("Makefile"), "w"); 187 if (ofp == 0) { 188 perror(path("Makefile")); 189 exit(1); 190 } 191 fprintf(ofp, "SOURCE_DIR=%s\n", source_directory); 192 193 fprintf(ofp, "export CONFIG_DEFINES ="); 194 if (profiling) 195 fprintf(ofp, " -DGPROF"); 196 197 for (op = opt; op; op = op->op_next) 198 if (op->op_value) 199 fprintf(ofp, " -D%s=\"%s\"", op->op_name, op->op_value); 200 else 201 fprintf(ofp, " -D%s", op->op_name); 202 fprintf(ofp, "\n"); 203 for (op = mkopt; op; op = op->op_next) 204 if (op->op_value) 205 fprintf(ofp, "%s=%s\n", op->op_name, op->op_value); 206 else 207 fprintf(ofp, "%s\n", op->op_name); 208 209 while (fgets(line, BUFSIZ, ifp) != 0) { 210 if (*line == '%') 211 goto percent; 212 if (profiling && strncmp(line, "COPTS=", 6) == 0) { 213 register char *cp; 214 fprintf(ofp, 215 "GPROF.EX=$(SOURCE_DIR)/machdep/%s/gmon.ex\n", machinename); 216 cp = index(line, '\n'); 217 if (cp) 218 *cp = 0; 219 cp = line + 6; 220 while (*cp && (*cp == ' ' || *cp == '\t')) 221 cp++; 222 COPTS = malloc((unsigned)(strlen(cp) + 1)); 223 if (COPTS == 0) { 224 printf("config: out of memory\n"); 225 exit(1); 226 } 227 strcpy(COPTS, cp); 228 fprintf(ofp, "%s -pg\n", line); 229 continue; 230 } 231 fprintf(ofp, "%s", line); 232 continue; 233 percent: 234 if (eq(line, "%OBJS\n")) { 235 do_objs(ofp, "OBJS=", -1); 236 } else if (eq(line, "%CFILES\n")) { 237 do_files(ofp, "CFILES=", 'c'); 238 do_objs(ofp, "COBJS=", 'c'); 239 } else if (eq(line, "%CXXFILES\n")) { 240 do_files(ofp, "CXXFILES=", 'p'); 241 do_objs(ofp, "CXXOBJS=", 'p'); 242 } else if (eq(line, "%SFILES\n")) { 243 do_files(ofp, "SFILES=", 's'); 244 do_objs(ofp, "SOBJS=", 's'); 245 } else if (eq(line, "%MACHDEP\n")) { 246 do_machdep(ofp); 247 } else if (eq(line, "%RULES\n")) 248 do_rules(ofp); 249 else 250 fprintf(stderr, 251 "Unknown %% construct in generic makefile: %s", 252 line); 253 } 254 if (dfp != NULL) 255 { 256 copy_dependencies(dfp, ofp); 257 (void) fclose(dfp); 258 } 259 (void) fclose(ifp); 260 (void) fclose(ofp); 261} 262 263/* 264 * Read in the information about files used in making the system. 265 * Store it in the ftab linked list. 266 */ 267void 268read_files(void) 269{ 270 FILE *fp; 271 register struct file_list *tp, *pf; 272 register struct device *dp; 273 register struct opt *op; 274 const char *wd; 275 char *this, *needs; 276 const char *devorprof; 277 int options; 278 int not_option; 279 char pname[BUFSIZ]; 280 char fname[1024]; 281 char *rest = (char *) 0; 282 int nreqs, first = 1, isdup; 283 284 ftab = 0; 285 (void) sprintf(fname, "%s/files", config_directory); 286openit: 287 fp = fopenp(VPATH, fname, pname, "r"); 288 if (fp == 0) { 289 perror(fname); 290 exit(1); 291 } 292next: 293 options = 0; 294 rest = (char *) 0; 295 /* 296 * filename [ standard | optional ] 297 * [ dev* | profiling-routine ] [ device-driver] 298 */ 299 wd = get_word(fp); 300 if (wd == (char *)EOF) { 301 (void) fclose(fp); 302 if (first == 1) { 303 (void) sprintf(fname, "%s/files.%s", config_directory, machinename); 304 first++; 305 goto openit; 306 } 307 return; 308 } 309 if (wd == 0) 310 goto next; 311 /* 312 * Allow comment lines beginning witha '#' character. 313 */ 314 if (*wd == '#') 315 { 316 while ((wd=get_word(fp)) && wd != (char *)EOF) 317 ; 318 goto next; 319 } 320 321 this = ns(wd); 322 next_word(fp, wd); 323 if (wd == 0) { 324 printf("%s: No type for %s.\n", 325 fname, this); 326 exit(1); 327 } 328 if ((pf = fl_lookup(this)) && (pf->f_type != INVISIBLE || pf->f_flags)) 329 isdup = 1; 330 else 331 isdup = 0; 332 tp = 0; 333 nreqs = 0; 334 devorprof = ""; 335 needs = 0; 336 if (eq(wd, "standard")) 337 goto checkdev; 338 if (!eq(wd, "optional")) { 339 printf("%s: %s must be optional or standard\n", fname, this); 340 exit(1); 341 } 342 if (strncmp(this, "OPTIONS/", 8) == 0) 343 options++; 344 not_option = 0; 345nextopt: 346 next_word(fp, wd); 347 if (wd == 0) 348 goto doneopt; 349 if (eq(wd, "not")) { 350 not_option = !not_option; 351 goto nextopt; 352 } 353 devorprof = wd; 354 if (eq(wd, "device-driver") || eq(wd, "profiling-routine")) { 355 next_word(fp, wd); 356 goto save; 357 } 358 nreqs++; 359 if (needs == 0 && nreqs == 1) 360 needs = ns(wd); 361 if (isdup) 362 goto invis; 363 if (options) 364 { 365 struct opt *lop = 0; 366 struct device tdev; 367 368 /* 369 * Allocate a pseudo-device entry which we will insert into 370 * the device list below. The flags field is set non-zero to 371 * indicate an internal entry rather than one generated from 372 * the configuration file. The slave field is set to define 373 * the corresponding symbol as 0 should we fail to find the 374 * option in the option list. 375 */ 376 init_dev(&tdev); 377 tdev.d_name = ns(wd); 378 tdev.d_type = PSEUDO_DEVICE; 379 tdev.d_flags++; 380 tdev.d_slave = 0; 381 382 for (op=opt; op; lop=op, op=op->op_next) 383 { 384 char *od = allCaps(ns(wd)); 385 386 /* 387 * Found an option which matches the current device 388 * dependency identifier. Set the slave field to 389 * define the option in the header file. 390 */ 391 if (strcmp(op->op_name, od) == 0) 392 { 393 tdev.d_slave = 1; 394 if (lop == 0) 395 opt = op->op_next; 396 else 397 lop->op_next = op->op_next; 398 free(op); 399 op = 0; 400 } 401 free(od); 402 if (op == 0) 403 break; 404 } 405 newdev(&tdev); 406 } 407 for (dp = dtab; dp != 0; dp = dp->d_next) { 408 if (eq(dp->d_name, wd) && (dp->d_type != PSEUDO_DEVICE || dp->d_slave)) { 409 if (not_option) 410 goto invis; /* dont want file if option present */ 411 else 412 goto nextopt; 413 } 414 } 415 if (not_option) 416 goto nextopt; /* want file if option missing */ 417 418 for (op = opt; op != 0; op = op->op_next) 419 if (op->op_value == 0 && opteq(op->op_name, wd)) { 420 if (nreqs == 1) { 421 free(needs); 422 needs = 0; 423 } 424 goto nextopt; 425 } 426 427invis: 428 while ((wd = get_word(fp)) != 0) 429 ; 430 if (tp == 0) 431 tp = new_fent(); 432 tp->f_fn = this; 433 tp->f_type = INVISIBLE; 434 tp->f_needs = needs; 435 tp->f_flags = isdup; 436 goto next; 437 438doneopt: 439 if (nreqs == 0) { 440 printf("%s: what is %s optional on?\n", 441 fname, this); 442 exit(1); 443 } 444 445checkdev: 446 if (wd) { 447 if (*wd == '|') 448 goto getrest; 449 next_word(fp, wd); 450 if (wd) { 451 devorprof = wd; 452 next_word(fp, wd); 453 } 454 } 455 456save: 457getrest: 458 if (wd) { 459 if (*wd == '|') { 460 rest = ns(get_rest(fp)); 461 } else { 462 printf("%s: syntax error describing %s\n", 463 fname, this); 464 exit(1); 465 } 466 } 467 if (eq(devorprof, "profiling-routine") && profiling == 0) 468 goto next; 469 if (tp == 0) 470 tp = new_fent(); 471 tp->f_fn = this; 472 tp->f_extra = rest; 473 if (options) 474 tp->f_type = INVISIBLE; 475 else 476 if (eq(devorprof, "device-driver")) 477 tp->f_type = DRIVER; 478 else if (eq(devorprof, "profiling-routine")) 479 tp->f_type = PROFILING; 480 else 481 tp->f_type = NORMAL; 482 tp->f_flags = 0; 483 tp->f_needs = needs; 484 if (pf && pf->f_type == INVISIBLE) 485 pf->f_flags = 1; /* mark as duplicate */ 486 goto next; 487} 488 489int 490opteq(const char *cp, const char *dp) 491{ 492 char c, d; 493 494 for (; ; cp++, dp++) { 495 if (*cp != *dp) { 496 c = isupper(*cp) ? tolower(*cp) : *cp; 497 d = isupper(*dp) ? tolower(*dp) : *dp; 498 if (c != d) 499 return (0); 500 } 501 if (*cp == 0) 502 return (1); 503 } 504} 505 506void 507put_source_file_name(FILE *fp, struct file_list *tp) 508{ 509 if ((tp->f_fn[0] == '.') && (tp->f_fn[1] == '/')) 510 fprintf(fp, "%s ", tp->f_fn); 511 else 512 fprintf(fp, "$(SOURCE_DIR)/%s ", tp->f_fn); 513} 514 515void 516do_objs(FILE *fp, const char *msg, int ext) 517{ 518 register struct file_list *tp; 519 register int lpos, len; 520 char *cp; 521 char och; 522 const char *sp; 523 524 fprintf(fp, "%s", msg); 525 lpos = strlen(msg); 526 for (tp = ftab; tp != 0; tp = tp->f_next) { 527 if (tp->f_type == INVISIBLE) 528 continue; 529 530 /* 531 * Check for '.o' file in list 532 */ 533 cp = tp->f_fn + (len = strlen(tp->f_fn)) - 1; 534 if (ext != -1 && *cp != ext) 535 continue; 536 else if (*cp == 'o') { 537 if (len + lpos > 72) { 538 lpos = 8; 539 fprintf(fp, "\\\n\t"); 540 } 541 put_source_file_name(fp, tp); 542 fprintf(fp, " "); 543 lpos += len + 1; 544 continue; 545 } 546 sp = tail(tp->f_fn); 547 cp = (char *)sp + (len = strlen(sp)) - 1; 548 och = *cp; 549 *cp = 'o'; 550 if (len + lpos > 72) { 551 lpos = 8; 552 fprintf(fp, "\\\n\t"); 553 } 554 fprintf(fp, "%s ", sp); 555 lpos += len + 1; 556 *cp = och; 557 } 558 putc('\n', fp); 559} 560 561void 562do_files(FILE *fp, const char *msg, char ext) 563{ 564 register struct file_list *tp; 565 register int lpos, len=0; /* dvw: init to 0 */ 566 567 fprintf(fp, "%s", msg); 568 lpos = 8; 569 for (tp = ftab; tp != 0; tp = tp->f_next) { 570 if (tp->f_type == INVISIBLE) 571 continue; 572 if (tp->f_fn[strlen(tp->f_fn)-1] != ext) 573 continue; 574 /* 575 * Always generate a newline. 576 * Our Makefile's aren't readable anyway. 577 */ 578 579 lpos = 8; 580 fprintf(fp, "\\\n\t"); 581 put_source_file_name(fp, tp); 582 lpos += len + 1; 583 } 584 putc('\n', fp); 585} 586 587/* 588 * Include machine dependent makefile in output 589 */ 590 591void 592do_machdep(FILE *ofp) 593{ 594 FILE *ifp; 595 char pname[BUFSIZ]; 596 char line[BUFSIZ]; 597 598 (void) sprintf(line, "%s/Makefile.%s", config_directory, machinename); 599 ifp = fopenp(VPATH, line, pname, "r"); 600 if (ifp == 0) { 601 perror(line); 602 exit(1); 603 } 604 while (fgets(line, BUFSIZ, ifp) != 0) { 605 if (profiling && (strncmp(line, "LIBS=", 5) == 0)) 606 fprintf(ofp,"LIBS=${LIBS_P}\n"); 607 else 608 fputs(line, ofp); 609 } 610 fclose(ifp); 611} 612 613const char * 614tail(const char *fn) 615{ 616 register const char *cp; 617 618 cp = rindex(fn, '/'); 619 if (cp == 0) 620 return (fn); 621 return (cp+1); 622} 623 624/* 625 * Create the makerules for each file 626 * which is part of the system. 627 * Devices are processed with the special c2 option -i 628 * which avoids any problem areas with i/o addressing 629 * (e.g. for the VAX); assembler files are processed by as. 630 */ 631void 632do_rules(FILE *f) 633{ 634 char *cp; 635 char *np, och; 636 const char *tp; 637 register struct file_list *ftp; 638 const char *extras = ""; /* dvw: init to "" */ 639 char *source_dir; 640 char och_upper; 641 const char *nl = ""; 642 643 for (ftp = ftab; ftp != 0; ftp = ftp->f_next) { 644 if (ftp->f_type == INVISIBLE) 645 continue; 646 cp = (np = ftp->f_fn) + strlen(ftp->f_fn) - 1; 647 och = *cp; 648 /* 649 * Don't compile '.o' files 650 */ 651 if (och == 'o') 652 continue; 653 /* 654 * Determine where sources should come from 655 */ 656 if ((np[0] == '.') && (np[1] == '/')) { 657 source_dir = ""; 658 np += 2; 659 } else 660 source_dir = "$(SOURCE_DIR)/"; 661 *cp = '\0'; 662 tp = tail(np); /* dvw: init tp before 'if' */ 663 fprintf(f, "-include %sd\n", tp); 664 fprintf(f, "%so: %s%s%c\n", tp, source_dir, np, och); 665 if (och == 's') { 666 fprintf(f, "\t${S_RULE_0}\n"); 667 fprintf(f, "\t${S_RULE_1A}%s%.*s${S_RULE_1B}%s\n", 668 source_dir, (int)(tp-np), np, nl); 669 fprintf(f, "\t${S_RULE_2}%s\n", nl); 670 continue; 671 } 672 extras = ""; 673 switch (ftp->f_type) { 674 675 case NORMAL: 676 goto common; 677 break; 678 679 case DRIVER: 680 extras = "_D"; 681 goto common; 682 break; 683 684 case PROFILING: 685 if (!profiling) 686 continue; 687 if (COPTS == 0) { 688 fprintf(stderr, 689 "config: COPTS undefined in generic makefile"); 690 COPTS = ""; 691 } 692 extras = "_P"; 693 goto common; 694 695 common: 696 och_upper = och + 'A' - 'a'; 697 fprintf(f, "\t${%c_RULE_0%s}\n", och_upper, extras); 698 fprintf(f, "\t${%c_RULE_1A%s}", och_upper, extras); 699 if (ftp->f_extra) 700 fprintf(f, "%s", ftp->f_extra); 701 fprintf(f, "%s%.*s${%c_RULE_1B%s}%s\n", 702 source_dir, (int)(tp-np), np, och_upper, extras, nl); 703 704 /* While we are still using CTF, any build that normally does not support CTF will 705 * a "standard" compile done as well that we can harvest CTF information from; do 706 * that here. 707 */ 708 fprintf(f, "\t${%c_CTFRULE_1A%s}", och_upper, extras); 709 if (ftp->f_extra) 710 fprintf(f, "%s", ftp->f_extra); 711 fprintf(f, "%s%.*s${%c_CTFRULE_1B%s}%s\n", 712 source_dir, (int)(tp-np), np, och_upper, extras, nl); 713 714 fprintf(f, "\t${%c_RULE_2%s}%s\n", och_upper, extras, nl); 715 fprintf(f, "\t${%c_CTFRULE_2%s}%s\n", och_upper, extras, nl); 716 break; 717 718 default: 719 printf("Don't know rules for %s\n", np); 720 break; 721 } 722 *cp = och; 723 } 724} 725 726char * 727allCaps(str) 728 register char *str; 729{ 730 register char *cp = str; 731 732 while (*str) { 733 if (islower(*str)) 734 *str = toupper(*str); 735 str++; 736 } 737 return (cp); 738} 739 740#define OLDSALUTATION "# DO NOT DELETE THIS LINE" 741 742#define LINESIZE 1024 743static char makbuf[LINESIZE]; /* one line buffer for makefile */ 744 745void 746copy_dependencies(FILE *makin, FILE *makout) 747{ 748 register int oldlen = (sizeof OLDSALUTATION - 1); 749 750 while (fgets(makbuf, LINESIZE, makin) != NULL) { 751 if (! strncmp(makbuf, OLDSALUTATION, oldlen)) 752 break; 753 } 754 while (fgets(makbuf, LINESIZE, makin) != NULL) { 755 if (oldlen != 0) 756 { 757 if (makbuf[0] == '\n') 758 continue; 759 else 760 oldlen = 0; 761 } 762 fputs(makbuf, makout); 763 } 764} 765