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