1 /* $NetBSD: mkdep.c,v 1.32 2008/07/21 14:19:24 lukem Exp $ */
4 * Copyright (c) 1999 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #if HAVE_NBTOOL_CONFIG_H
33 #include "nbtool_config.h"
36 #include <sys/cdefs.h>
38 __COPYRIGHT("@(#) Copyright (c) 1999 The NetBSD Foundation, Inc.\
39 All rights reserved.");
40 __RCSID("$NetBSD: mkdep.c,v 1.32 2008/07/21 14:19:24 lukem Exp $");
44 #include <sys/param.h>
58 typedef struct opt opt_t
;
72 /* tree of includes for -o processing */
76 #define DEFAULT_PATH _PATH_DEFPATH
77 #define DEFAULT_FILENAME ".depend"
79 static void save_for_optional(const char *, const char *);
80 static int write_optional(int, opt_t
*, int);
84 deconst(const void *p
)
86 return (const char *)p
- (const char *)0 + (char *)0;
93 "usage: %s [-aDdopq] [-f file] [-s suffixes] -- [flags] file ...\n",
99 run_cc(int argc
, char **argv
, const char **fname
)
101 const char *CC
, *tmpdir
;
102 char * volatile pathname
;
103 static char tmpfilename
[MAXPATHLEN
];
109 if ((CC
= getenv("CC")) == NULL
)
111 if ((pathname
= findcc(CC
)) == NULL
)
112 if (!setenv("PATH", DEFAULT_PATH
, 1))
113 pathname
= findcc(CC
);
114 if (pathname
== NULL
)
115 err(EXIT_FAILURE
, "%s: not found", CC
);
116 if ((args
= malloc((argc
+ 3) * sizeof(char *))) == NULL
)
117 err(EXIT_FAILURE
, "malloc");
119 args
[0] = deconst(CC
);
120 args
[1] = deconst("-M");
121 (void)memcpy(&args
[2], argv
, (argc
+ 1) * sizeof(char *));
123 if ((tmpdir
= getenv("TMPDIR")) == NULL
)
125 (void)snprintf(tmpfilename
, sizeof (tmpfilename
), "%s/%s", tmpdir
,
127 if ((tmpfd
= mkstemp(tmpfilename
)) < 0) {
128 warn("unable to create temporary file %s", tmpfilename
);
131 (void)unlink(tmpfilename
);
132 *fname
= tmpfilename
;
134 switch (cpid
= vfork()) {
136 (void)dup2(tmpfd
, STDOUT_FILENO
);
139 (void)execv(pathname
, args
);
144 err(EXIT_FAILURE
, "unable to fork");
150 while (((pid
= wait(&status
)) != cpid
) && (pid
>= 0))
154 errx(EXIT_FAILURE
, "compile failed.");
166 for (len
= 0; (ch
= getchar()) != EOF
; len
++) {
173 if (len
>= fbuflen
- 1) {
174 fbuf
= realloc(fbuf
, fbuflen
+= 32);
176 err(EXIT_FAILURE
, "no memory");
187 main(int argc
, char **argv
)
189 int aflag
, dflag
, oflag
, qflag
;
190 const char *filename
;
192 char *buf
, *lim
, *ptr
, *line
, *suf
, *colon
, *eol
;
197 const char *suffixes
= NULL
, *s
;
198 suff_list_t
*suff_list
= NULL
, *sl
;
200 suf
= NULL
; /* XXXGCC -Wuninitialized [sun2] */
201 sl
= NULL
; /* XXXGCC -Wuninitialized [sun2] */
203 setlocale(LC_ALL
, "");
204 setprogname(argv
[0]);
206 aflag
= O_WRONLY
| O_APPEND
| O_CREAT
| O_TRUNC
;
210 filename
= DEFAULT_FILENAME
;
213 opterr
= 0; /* stop getopt() bleating about errors. */
216 ch
= getopt(argc
, argv
, "aDdf:opqs:");
221 case 'a': /* Append to output file */
224 case 'D': /* Process *.d files (don't run cc -M) */
225 dflag
= 2; /* Read names from stdin */
228 case 'd': /* Process *.d files (don't run cc -M) */
232 case 'f': /* Name of output file */
235 case 'o': /* Mark dependant files .OPTIONAL */
238 case 'p': /* Program mode (x.o: -> x:) */
241 case 'q': /* Quiet */
244 case 's': /* Suffix list */
250 /* Unknown arguments are passed to "${CC} -M" */
258 if ((argc
== 0 && !dflag
) || (argc
!= 0 && dflag
== 2))
261 if (suffixes
!= NULL
) {
262 /* parse list once and save names and lengths */
263 /* allocate an extra entry to mark end of list */
264 for (sz
= 1, s
= suffixes
; *s
!= 0; s
++)
267 suff_list
= calloc(sz
, sizeof *suff_list
);
268 if (suff_list
== NULL
)
271 for (s
= suffixes
; (s
= strchr(s
, '.')); s
+= sz
, sl
++ ) {
272 sz
= strcspn(s
, ", ");
273 if (sz
> sizeof sl
->suff
)
274 errx(2, "suffix too long");
276 memcpy(sl
->suff
, s
, sz
);
280 dependfile
= open(filename
, aflag
, 0666);
281 if (dependfile
== -1)
282 err(EXIT_FAILURE
, "unable to %s to file %s\n",
283 aflag
& O_TRUNC
? "write" : "append", filename
);
285 while (dflag
== 2 || *argv
!= NULL
) {
288 fname
= read_fname();
293 fd
= open(fname
, O_RDONLY
, 0);
296 warn("ignoring %s", fname
);
300 fd
= run_cc(argc
, argv
, &fname
);
301 /* consume all args... */
305 sz
= lseek(fd
, 0, SEEK_END
);
310 buf
= mmap(NULL
, sz
, PROT_READ
|PROT_WRITE
, MAP_PRIVATE
, fd
, 0);
313 if (buf
== MAP_FAILED
)
314 err(EXIT_FAILURE
, "unable to mmap file %s", fname
);
317 /* Remove leading "./" from filenames */
318 for (ptr
= buf
; ptr
< lim
; ptr
++) {
319 if (ptr
[1] != '.' || ptr
[2] != '/'
320 || !isspace((unsigned char)ptr
[0]))
326 for (line
= eol
= buf
; eol
<= lim
;) {
327 while (eol
<= lim
&& *eol
++ != '\n')
328 /* Find end of this line */
330 if (line
== eol
- 1) {
331 /* empty line - ignore */
336 /* Assemble continuation lines */
338 for (colon
= line
; *colon
!= ':'; colon
++) {
344 if (isspace((unsigned char)*line
) || colon
== NULL
) {
345 /* No dependency - just transcribe line */
346 write(dependfile
, line
, eol
- line
);
350 if (suff_list
!= NULL
) {
352 /* First allow for any whitespace */
353 for (suf
= colon
; suf
> buf
; suf
--) {
354 if (!isspace((unsigned char)suf
[-1]))
359 "Corrupted file `%s'", fname
);
360 /* Then look for any valid suffix */
361 for (sl
= suff_list
; sl
->len
!= 0; sl
++) {
362 if (!memcmp(suf
- sl
->len
, sl
->suff
,
367 if (suff_list
!= NULL
&& sl
->len
!= 0) {
369 for (sl
= suff_list
; sl
->len
!= 0; sl
++) {
371 write(dependfile
, " ", 1);
372 write(dependfile
, line
, suf
- line
);
373 write(dependfile
, sl
->suff
, sl
->len
);
375 write(dependfile
, colon
, eol
- colon
);
377 write(dependfile
, line
, eol
- line
);
380 save_for_optional(colon
+ 1, eol
);
386 if (oflag
&& opt
!= NULL
) {
387 write(dependfile
, ".OPTIONAL:", 10);
389 sz
= write_optional(dependfile
, opt
, 0);
390 /* 'depth' is about 39 for an i386 kernel */
391 /* fprintf(stderr, "Recursion depth %d\n", sz); */
400 * Only save each file once - the kernel .depend is 3MB and there is
401 * no point doubling its size.
402 * The data seems to be 'random enough' so the simple binary tree
403 * only has a reasonable depth.
406 save_for_optional(const char *start
, const char *limit
)
409 const char *name
, *end
;
412 while (start
< limit
&& strchr(" \t\n\\", *start
))
414 for (name
= start
; ; name
= end
) {
415 while (name
< limit
&& strchr(" \t\n\\", *name
))
417 for (end
= name
; end
< limit
&& !strchr(" \t\n\\", *end
);)
421 if (end
[-1] == 'c' && end
[-2] == '.' && name
== start
)
422 /* ignore dependency on the files own .c */
427 n
= malloc(sizeof *n
+ (end
- name
));
428 n
->left
= n
->right
= 0;
432 memcpy(n
->name
+ 1, name
, end
- name
);
436 c
= (end
- name
) - n
->len
;
438 c
= memcmp(n
->name
+ 1, name
, (end
- name
));
453 write_optional(int fd
, opt_t
*node
, int depth
)
458 d1
= write_optional(fd
, node
->left
, d1
);
459 if (width
> 76 - node
->len
) {
460 write(fd
, " \\\n ", 4);
463 width
+= 1 + node
->len
;
464 write(fd
, node
->name
, 1 + node
->len
);
466 depth
= write_optional(fd
, node
->right
, depth
);
467 return d1
> depth
? d1
: depth
;