1 /* $NetBSD: mkdep.c,v 1.35 2010/05/26 18:07:34 christos 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.35 2010/05/26 18:07:34 christos Exp $");
46 #include <sys/param.h>
60 typedef struct opt opt_t
;
74 /* tree of includes for -o processing */
78 #define DEFAULT_PATH _PATH_DEFPATH
79 #define DEFAULT_FILENAME ".depend"
81 static void save_for_optional(const char *, const char *);
82 static int write_optional(int, opt_t
*, int);
86 deconst(const void *p
)
88 return (const char *)p
- (const char *)0 + (char *)0;
95 "usage: %s [-aDdopq] [-f file] [-s suffixes] -- [flags] file ...\n",
101 run_cc(int argc
, char **argv
, const char **fname
)
103 const char *CC
, *tmpdir
;
104 char * volatile pathname
;
105 static char tmpfilename
[MAXPATHLEN
];
111 if ((CC
= getenv("CC")) == NULL
)
113 if ((pathname
= findcc(CC
)) == NULL
)
114 if (!setenv("PATH", DEFAULT_PATH
, 1))
115 pathname
= findcc(CC
);
116 if (pathname
== NULL
)
117 err(EXIT_FAILURE
, "%s: not found", CC
);
118 if ((args
= malloc((argc
+ 3) * sizeof(char *))) == NULL
)
119 err(EXIT_FAILURE
, "malloc");
121 args
[0] = deconst(CC
);
122 args
[1] = deconst("-M");
123 (void)memcpy(&args
[2], argv
, (argc
+ 1) * sizeof(char *));
125 if ((tmpdir
= getenv("TMPDIR")) == NULL
)
127 (void)snprintf(tmpfilename
, sizeof (tmpfilename
), "%s/%s", tmpdir
,
129 if ((tmpfd
= mkstemp(tmpfilename
)) < 0) {
130 warn("unable to create temporary file %s", tmpfilename
);
133 (void)unlink(tmpfilename
);
134 *fname
= tmpfilename
;
136 switch (cpid
= vfork()) {
138 (void)dup2(tmpfd
, STDOUT_FILENO
);
141 (void)execv(pathname
, args
);
146 err(EXIT_FAILURE
, "unable to fork");
152 while (((pid
= wait(&status
)) != cpid
) && (pid
>= 0))
156 errx(EXIT_FAILURE
, "compile failed.");
168 for (len
= 0; (ch
= getchar()) != EOF
; len
++) {
175 if (len
>= fbuflen
- 1) {
176 fbuf
= realloc(fbuf
, fbuflen
+= 32);
178 err(EXIT_FAILURE
, "no memory");
189 main(int argc
, char **argv
)
191 int aflag
, dflag
, oflag
, qflag
;
192 const char *filename
;
194 char *buf
, *lim
, *ptr
, *line
, *suf
, *colon
, *eol
;
200 const char *suffixes
= NULL
, *s
;
201 suff_list_t
*suff_list
= NULL
, *sl
;
206 suf
= NULL
; /* XXXGCC -Wuninitialized [sun2] */
207 sl
= NULL
; /* XXXGCC -Wuninitialized [sun2] */
209 setlocale(LC_ALL
, "");
210 setprogname(argv
[0]);
212 aflag
= O_WRONLY
| O_APPEND
| O_CREAT
| O_TRUNC
;
216 filename
= DEFAULT_FILENAME
;
219 opterr
= 0; /* stop getopt() bleating about errors. */
222 ch
= getopt(argc
, argv
, "aDdf:opqs:");
227 case 'a': /* Append to output file */
230 case 'D': /* Process *.d files (don't run cc -M) */
231 dflag
= 2; /* Read names from stdin */
234 case 'd': /* Process *.d files (don't run cc -M) */
238 case 'f': /* Name of output file */
241 case 'o': /* Mark dependant files .OPTIONAL */
244 case 'p': /* Program mode (x.o: -> x:) */
247 case 'q': /* Quiet */
250 case 's': /* Suffix list */
256 /* Unknown arguments are passed to "${CC} -M" */
264 if ((argc
== 0 && !dflag
) || (argc
!= 0 && dflag
== 2))
267 if (suffixes
!= NULL
) {
268 /* parse list once and save names and lengths */
269 /* allocate an extra entry to mark end of list */
270 for (sz
= 1, s
= suffixes
; *s
!= 0; s
++)
273 suff_list
= calloc(sz
, sizeof *suff_list
);
274 if (suff_list
== NULL
)
277 for (s
= suffixes
; (s
= strchr(s
, '.')); s
+= sz
, sl
++) {
278 sz
= strcspn(s
, ", ");
279 if (sz
> sizeof sl
->suff
)
280 errx(2, "suffix too long");
282 memcpy(sl
->suff
, s
, sz
);
286 dependfile
= open(filename
, aflag
, 0666);
287 if (dependfile
== -1)
288 err(EXIT_FAILURE
, "unable to %s to file %s\n",
289 aflag
& O_TRUNC
? "write" : "append", filename
);
291 while (dflag
== 2 || *argv
!= NULL
) {
294 fname
= read_fname();
299 fd
= open(fname
, O_RDONLY
, 0);
302 warn("ignoring %s", fname
);
306 fd
= run_cc(argc
, argv
, &fname
);
307 /* consume all args... */
311 sz
= lseek(fd
, 0, SEEK_END
);
317 buf
= mmap(NULL
, sz
, PROT_READ
|PROT_WRITE
, MAP_PRIVATE
, fd
, 0);
320 if (buf
== MAP_FAILED
)
321 err(EXIT_FAILURE
, "unable to mmap file %s", fname
);
325 err(EXIT_FAILURE
, "malloc");
326 if ((nr
= pread(fd
, buf
, sz
, 0)) != sz
)
327 err(EXIT_FAILURE
, "read error %s", fname
);
332 /* Remove leading "./" from filenames */
333 for (ptr
= buf
; ptr
< lim
; ptr
++) {
334 if (ptr
[1] != '.' || ptr
[2] != '/'
335 || !isspace((unsigned char)ptr
[0]))
341 for (line
= eol
= buf
; eol
<= lim
;) {
342 while (eol
<= lim
&& *eol
++ != '\n')
343 /* Find end of this line */
345 if (line
== eol
- 1) {
346 /* empty line - ignore */
351 /* Assemble continuation lines */
353 for (colon
= line
; *colon
!= ':'; colon
++) {
359 if (isspace((unsigned char)*line
) || colon
== NULL
) {
360 /* No dependency - just transcribe line */
361 write(dependfile
, line
, eol
- line
);
365 if (suff_list
!= NULL
) {
367 /* First allow for any whitespace */
368 for (suf
= colon
; suf
> buf
; suf
--) {
369 if (!isspace((unsigned char)suf
[-1]))
374 "Corrupted file `%s'", fname
);
375 /* Then look for any valid suffix */
376 for (sl
= suff_list
; sl
->len
!= 0; sl
++) {
377 if (!memcmp(suf
- sl
->len
, sl
->suff
,
382 * Not found, check for .o, since the
383 * original file will have it.
385 if (sl
->len
== 0 && suff_list
->len
!= 0) {
386 if (memcmp(suf
- 2, ".o", 2) == 0)
393 if (suff_list
!= NULL
&& slen
!= 0) {
395 for (sl
= suff_list
; sl
->len
!= 0; sl
++) {
397 write(dependfile
, " ", 1);
398 write(dependfile
, line
, suf
- line
);
399 write(dependfile
, sl
->suff
, sl
->len
);
401 write(dependfile
, colon
, eol
- colon
);
403 write(dependfile
, line
, eol
- line
);
406 save_for_optional(colon
+ 1, eol
);
416 if (oflag
&& opt
!= NULL
) {
417 write(dependfile
, ".OPTIONAL:", 10);
419 sz
= write_optional(dependfile
, opt
, 0);
420 /* 'depth' is about 39 for an i386 kernel */
421 /* fprintf(stderr, "Recursion depth %d\n", sz); */
430 * Only save each file once - the kernel .depend is 3MB and there is
431 * no point doubling its size.
432 * The data seems to be 'random enough' so the simple binary tree
433 * only has a reasonable depth.
436 save_for_optional(const char *start
, const char *limit
)
439 const char *name
, *end
;
442 while (start
< limit
&& strchr(" \t\n\\", *start
))
444 for (name
= start
; ; name
= end
) {
445 while (name
< limit
&& strchr(" \t\n\\", *name
))
447 for (end
= name
; end
< limit
&& !strchr(" \t\n\\", *end
);)
451 if (end
[-1] == 'c' && end
[-2] == '.' && name
== start
)
452 /* ignore dependency on the files own .c */
457 n
= malloc(sizeof *n
+ (end
- name
));
458 n
->left
= n
->right
= 0;
462 memcpy(n
->name
+ 1, name
, end
- name
);
466 c
= (end
- name
) - n
->len
;
468 c
= memcmp(n
->name
+ 1, name
, (end
- name
));
483 write_optional(int fd
, opt_t
*node
, int depth
)
488 d1
= write_optional(fd
, node
->left
, d1
);
489 if (width
> 76 - node
->len
) {
490 write(fd
, " \\\n ", 4);
493 width
+= 1 + node
->len
;
494 write(fd
, node
->name
, 1 + node
->len
);
496 depth
= write_optional(fd
, node
->right
, depth
);
497 return d1
> depth
? d1
: depth
;