]>
git.saurik.com Git - apple/xnu.git/blob - SETUP/md/md.c
f253bf5fe90c86442ac5615b16de0028d33c35d4
1 /* ************************************************************************ *\
5 * Updates makefiles from the .n dependency files generated by the *
6 * -MD option to "cc" (and "cpp"). *
10 * Basically, "md" does two things: *
11 * 1) It processes the raw dependency files produced by the cpp -MD *
12 * option. There is one line in the file for every #include *
13 * encountered, but there are repeats and patterns like *
14 * .../dir1/../dir2 appear which should reduce to .../dir2 *
15 * Md canonicalizes and flushes repeats from the dependency *
16 * list. It also sorts the file names and "fills" them to a 78 *
18 * 2) Md also updates the makefile directly with the dependency *
19 * information, so the .d file can be thrown away (-- -d option) *
20 * This is done to save space. Md assumes that dependency *
21 * information in the makefile is sorted by .o file name and it *
22 * procedes to merge in (add/or replace [as appropriate]) the new *
23 * dependency lines that it has generated. For time effeciency, *
24 * Md assumes that any .d files it is given that were created *
25 * before the creation date of the "makefile" were processed *
26 * already. It ignores them unless the force flag (-f) is given. *
30 * -d delete the .d file after it is processed *
31 * -f force an update of the dependencies in the makefile *
32 * even though the makefile is more recent than the .n file *
33 * (This implies that md has been run already.) *
34 * -m specify the makefile to be upgraded. The defaults are *
35 * "makefile" and then "Makefile". *
36 * -u like -m above, but the file will be created if necessary *
37 * -o specify an output file for the dependencies other than a *
39 * -v set the verbose flag *
40 * -x expunge old dependency info from makefile *
41 * -D subswitch for debugging. can be followed by any of *
42 * "c", "d", "m", "o", "t", "D" meaning: *
43 * c show file contents *
44 * d show new dependency crunching *
45 * m show generation of makefile *
46 * o show files being opened *
47 * t show time comparisons *
48 * D show very low level debugging *
50 * Author: Robert V. Baron *
51 * Copyright (c) 1986 by Robert V. Baron *
54 * 29-Apr-87 Robert Baron (rvb) at Carnegie-Mellon University
55 * If specified -u file does not exist, assume it is empty and
56 * generate one. As a sanity check, it must be possible to create
58 * Also, generalized fix below to handle any case of . as a
61 * 25-Mar-87 Mary Thompson (mrt) at Carnegie Mellon
62 * Fixed up pathnamecanonicalization to recognize .// and
63 * drop the second / as well. mmax cpp generates this form.
65 * 6-Jan-87 Robert Baron (rvb) at Carnegie-Mellon University
66 * Fixed up pathname canonicalization to that ../../, etc would be
68 * Also made "force" on by default.
70 * 16-Mar-86 Robert Baron (rvb) at Carnegie-Mellon University
73 \* ************************************************************************ */
76 #include <sys/types.h>
82 #define LINESIZE 65536 // NeXT_MOD
85 #define IObuffer 50000
86 #define SALUTATION "# Dependencies for File:"
87 #define SALUTATIONLEN (sizeof SALUTATION - 1)
88 #define OLDSALUTATION "# DO NOT DELETE THIS LINE"
89 #define OLDSALUTATIONLEN (sizeof OLDSALUTATION - 1)
91 char file_array
[IObuffer
]; /* read file and store crunched names */
92 char dep_line
[LINESIZE
]; /* line being processed */
93 char dot_o
[LINESIZE
]; /* <foo.o>: prefix */
94 char *path_component
[100]; /* stores components for a path while being
97 struct dep
{ /* stores paths that a file depends on */
107 return strcmp(a
->str
, b
->str
);
110 char *outfile
= (char *) 0; /* generate dependency file */
113 char *makefile
= (char *) 0; /* user supplied makefile name */
114 char *real_mak_name
; /* actual makefile name (if not supplied) */
115 char shadow_mak_name
[LINESIZE
]; /* changes done here then renamed */
116 FILE *mak
; /* for reading makefile */
117 FILE *makout
; /* for writing shadow */
118 char makbuf
[LINESIZE
]; /* one line buffer for makefile */
119 struct stat makstat
; /* stat of makefile for time comparisons */
120 int mak_eof
= 0; /* eof seen on makefile */
121 FILE *find_mak(), *temp_mak();
123 int delete = 0; /* -d delete dependency file */
125 int D_contents
= 0; /* print file contents */
126 int D_depend
= 0; /* print dependency processing info */
127 int D_make
= 0; /* print makefile processing info */
128 int D_open
= 0; /* print after succesful open */
129 int D_time
= 0; /* print time comparison info */
130 int force
= 1; /* always update dependency info */
131 int update
= 0; /* it's ok if the -m file does not exist */
132 int verbose
= 0; /* tell me something */
133 int expunge
= 0; /* first flush dependency stuff from makefile */
138 static void scan_mak(FILE *, FILE *, char *);
139 static void finish_mak(FILE *, FILE *);
142 register char **argv
;
147 {register char *cp
=name
;
148 while (*cp
) if (*cp
++ == '/') name
= cp
;
151 for ( argv
++ ; --argc
; argv
++ ) { register char *token
= *argv
;
152 if (*token
++ != '-' || !*token
)
154 else { register int flag
;
155 for ( ; flag
= *token
++ ; ) {
167 if (--argc
< 0) goto usage
;
171 if (--argc
< 0) goto usage
;
180 for ( ; flag
= *token
++ ; )
213 if (!expunge
&& argc
< 1) goto usage
;
214 if ((int) outfile
&& (int) makefile
) /* not both */
219 * NeXT_MOD, For SGS stuff, in case still linked to master version
223 if ((out
= fopen(outfile
, "w")) == NULL
) {
224 fprintf(stderr
, "%s: outfile = \"%s\" ", name
, outfile
);
226 fflush(stdout
), fflush(stderr
);
229 printf("%s: opened outfile \"%s\"\n", name
, outfile
);
230 } else if (mak
= find_mak(makefile
)) {
234 expunge_mak(mak
, makout
);
236 skip_mak(mak
, makout
);
237 } else if (mak_eof
&& /* non existent file == mt file */
238 (int)(makout
= temp_mak())) { /* but we need to be able */
239 out
= makout
; /* to write here */
240 } else if (makefile
) {
241 fprintf(stderr
, "%s: makefile \"%s\" can not be opened or stat'ed\n",
246 for (; argc
--; argv
++) {
249 if (size
= read_dep(*argv
)) {
252 if (D_depend
) printf("%s: dot_o = \"%s\"\n", name
, dot_o
);
255 if (mak
) scan_mak(mak
, makout
, dot_o
);
256 if (out
) output_dep(out
);
263 if (mak
) finish_mak(mak
, makout
);
264 rename(shadow_mak_name
, real_mak_name
);
267 fprintf(stderr
, "usage: md -f -Dcdmot -m makefile -o outputfile -v <file1> ... <filen>\n");
279 if ((fd
= open(file
, 0)) < 0) {
280 fprintf(stderr
, "%s: file = \"%s\" ", name
, file
);
282 fflush(stdout
), fflush(stderr
);
286 printf("%s: opened dependency file \"%s\"\n", name
, file
);
288 if (fstat(fd
, &statbuf
) < 0) {
289 fprintf(stderr
, "%s: file = \"%s\" ", name
, file
);
291 fflush(stdout
), fflush(stderr
);
294 switch(statbuf
.st_mode
& S_IFMT
) {
297 printf("%s: file time = %d\n", name
, statbuf
.st_mtime
);
299 if (statbuf
.st_size
> IObuffer
) {
300 fprintf(stderr
, "%s: file \"%s\" tooo big for IObuffer\n",
305 else if ((int) mak
&& statbuf
.st_mtime
< makstat
.st_mtime
) {
306 if (verbose
|| D_time
)
307 fprintf(stderr
, "%s: skipping \"%s\" %d < %d \"%s\"\n",
308 name
, file
, statbuf
.st_mtime
, makstat
.st_mtime
,
319 fprintf(stderr
, "%s: bad mode: 0%o on \"%s\"\n",
320 name
, statbuf
.st_mode
, file
);
321 fflush(stdout
), fflush(stderr
);
325 if ((size
= read(fd
, file_array
, sizeof (file_array
))) < 0) {
326 fprintf(stderr
, "%s: file = \"%s\" ", name
, file
);
328 fflush(stdout
), fflush(stderr
);
331 file_array
[size
] = 0;
334 fprintf(stderr
, "%s: file = \"%s\" ", name
, file
);
336 fflush(stdout
), fflush(stderr
);
340 if (D_depend
&& D_contents
)
341 printf("file_array: \"%s\"\n", file_array
);
350 register char *cp
= file_array
;
351 register char *svp
= dot_o
;
354 while ((*svp
++ = (c
= *cp
++)) && c
!= ':');
360 register char *lp
= file_array
;
363 while (*lp
) {register char *tlp
= lp
;
364 register char *cp
= dep_line
;
370 /* get a line to process */
371 while ((c
= *lp
++) && c
!= '\n')
374 lp
++; /* skip backslash newline */
383 /* skip .o file name */
384 while ((c
= *cp
++) && c
!= ':'); if (!c
) continue;
388 while ((c
= *cp
) && (c
== ' ' || c
== '\t')) cp
++; if (!c
) continue;
390 /* canonicalization processing */
392 /* initial / is remembered */
396 while (c
&& c
!= ' ' && c
!= '\t') {
397 if (D_depend
) printf("i = %d going \"%s\"\n", i
, cp
);
399 while ((c
= *cp
) && c
== '/') cp
++; if (!c
) break;
400 path_component
[i
] = cp
;
401 /* swallow chars till next / or null */
402 while ((c
= *cp
++) && c
!= '/' && c
!= ' ' && c
!= '\t');
403 if (c
) cp
[-1]=0;/* end component C style */
406 if (!strcmp(path_component
[i
], "."))
407 ; /* if "component" != .. */
408 else /* don't reduce /component/.. to nothing */
409 i
++; /* there could be symbolic links! */
411 /* reassemble components */
412 oldc
= c
; /* save c */
413 oldcp
= cp
; /* save cp */
414 cp
= tlp
; /* overwrite line in buffer */
417 for (c
=0; c
<i
; c
++) {register char *ccp
= path_component
[c
];
418 while (*cp
++ = *ccp
++);
425 dep_files
[c
].str
= tlp
;
426 dep_files
[c
].len
= cp
- tlp
;
428 printf("%s: dep_file[%d] = \"%s\" Len %d\n",
429 name
, dep_file_index
- 1, tlp
, cp
- tlp
);
443 register int size
= 1000;
444 register int dot_o_len
= strlen(dot_o
);
445 register struct dep
*dp
= dep_files
;
448 if (D_depend
&& debug
)
449 for(j
= 0; j
< dep_file_index
; j
++) {
450 printf("dep_files[%d] = %s\n", j
, dep_files
[j
].str
);
453 qsort(dep_files
, dep_file_index
, sizeof (struct dep
), qsort_strcmp
);
455 if (D_depend
&& debug
)
456 for(j
= 0; j
< dep_file_index
; j
++) {
457 printf("dep_files[%d] = %s\n", j
, dep_files
[j
].str
);
460 fprintf(out
, "%s %s", SALUTATION
, dot_o
);
461 for(j
= 0; j
< dep_file_index
; j
++, dp
++)
462 {register int len
= dp
->len
;
463 register char *str
= dp
->str
;
464 if (j
&& len
== (dp
-1)->len
&& !strcmp(str
, (dp
-1)->str
))
467 if (size
+ len
+ 1 > OUTLINELEN
) {
468 fprintf(out
, "\n%s %s", dot_o
, str
);
469 size
= dot_o_len
+ len
+ 1;
471 fprintf(out
, " %s", str
);
477 fprintf(stdout
, "%s: \"%s\" %d => %d\n", name
, dot_o
, dep_file_index
, written
);
480 /* process makefile */
488 if ((mak
= fopen(file
, "r")) != NULL
) {
489 real_mak_name
= file
;
492 real_mak_name
= file
;
495 fprintf(stderr
, "%s: file = \"%s\" ", name
, file
);
497 fflush(stdout
), fflush(stderr
);
501 if ((mak
= fopen("makefile", "r")) != NULL
) {
502 real_mak_name
= "makefile";
503 } else if ((mak
= fopen("Makefile", "r")) != NULL
) {
504 real_mak_name
= "Makefile";
508 if (fstat(fileno(mak
), &makstat
) < 0) {
509 fprintf(stderr
, "%s: file = \"%s\" ", name
, real_mak_name
);
511 fflush(stdout
), fflush(stderr
);
515 printf("%s: opened makefile \"%s\"\n", name
, real_mak_name
);
517 printf("%s: makefile time = %d\n", name
, makstat
.st_mtime
);
527 strcpy(shadow_mak_name
, real_mak_name
);
528 strcat(shadow_mak_name
, ".md");
531 * For SGS stuff, in case still linked to master version
533 unlink(shadow_mak_name
);
534 if ((mak
= fopen(shadow_mak_name
, "w")) == NULL
) {
535 fprintf(stderr
, "%s: file = \"%s\" ", name
, shadow_mak_name
);
537 fflush(stdout
), fflush(stderr
);
541 printf("%s: opened makefile.md \"%s\"\n", name
, shadow_mak_name
);
546 skip_mak(makin
, makout
)
547 register FILE *makin
, *makout
;
549 register int len
= SALUTATIONLEN
;
552 printf("skipping in \"%s\" ", real_mak_name
);
554 while (fgets(makbuf
, LINESIZE
, makin
) != NULL
) {
555 if (D_make
&& D_contents
)
556 printf("%s: \"%s\"\n", real_mak_name
, makbuf
);
557 if (strncmp(makbuf
, SALUTATION
, len
)) {
558 fputs(makbuf
, makout
);
562 mak_eof
= feof(makin
);
566 printf("eof = %d str = \"%s\"", mak_eof
, makbuf
);
569 expunge_mak(makin
, makout
)
570 register FILE *makin
, *makout
;
572 register int len
= SALUTATIONLEN
;
573 register int oldlen
= OLDSALUTATIONLEN
;
576 printf("expunging in \"%s\" ", real_mak_name
);
578 while (fgets(makbuf
, LINESIZE
, makin
) != NULL
) {
579 if (D_make
&& D_contents
)
580 printf("%s: \"%s\"\n", real_mak_name
, makbuf
);
581 if (! strncmp(makbuf
, SALUTATION
, len
) ||
582 ! strncmp(makbuf
, OLDSALUTATION
, oldlen
))
585 fputs(makbuf
, makout
);
591 printf("eof = %d str = \"%s\"", mak_eof
, makbuf
);
595 scan_mak(FILE *makin
, FILE *makout
, char *file
)
597 register char *cp
= &makbuf
[SALUTATIONLEN
+1];
598 register int len
= strlen(file
);
602 printf("scanning in \"%s\" for \"%s\"\n", real_mak_name
, file
);
605 if (mak_eof
) /* don't scan any more */
608 ret
= strncmp(cp
, file
, len
);
610 printf("saw \"%s\" ret = %d\n", cp
, ret
);
612 if (ret
< 0) { /* skip forward till match or greater */
613 fputs(makbuf
, makout
); /* line we're looking at */
614 while (fgets(makbuf
, LINESIZE
, makin
) != NULL
) {
615 if (strncmp(makbuf
, SALUTATION
, SALUTATIONLEN
)) {
616 fputs(makbuf
, makout
);
620 mak_eof
= feof(makin
);
624 } else if (ret
== 0) { /* flush match */
625 while (fgets(makbuf
, LINESIZE
, makin
) != NULL
) {
626 if (strncmp(makbuf
, SALUTATION
, SALUTATIONLEN
)) {
627 ; /* flush old stuff */
631 mak_eof
= feof(makin
);
635 } else { /* no luck this time */
642 finish_mak(FILE *makin
, FILE *makout
)
644 if (mak_eof
) /* don't scan any more */
648 printf("finishing in \"%s\"\n", real_mak_name
);
650 fputs(makbuf
, makout
); /* line we're looking at */
651 while (fgets(makbuf
, LINESIZE
, makin
) != NULL
) {
652 fputs(makbuf
, makout
);