1 /* $NetBSD: mkdep.c,v 1.44 2015/06/16 22:54:10 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.44 2015/06/16 22:54:10 christos Exp $");
44 #include <sys/param.h>
59 typedef struct opt opt_t
;
68 typedef struct suff_list
{
71 struct suff_list
*next
;
74 /* tree of includes for -o processing */
79 #define DEFAULT_PATH _PATH_DEFPATH
80 #define DEFAULT_FILENAME ".depend"
82 static void save_for_optional(const char *, const char *);
83 static size_t write_optional(int, opt_t
*, size_t);
86 deconst(const void *p
)
88 return (const char *)p
- (const char *)0 + (char *)0;
95 "usage: %s [-aDdiopqv] [-f file] [-P prefix] [-s suffixes] "
96 "-- [flags] file ...\n",
102 run_cc(int argc
, char **argv
, const char **fname
)
104 const char *CC
, *tmpdir
;
105 char * volatile pathname
;
106 static char tmpfilename
[MAXPATHLEN
];
112 if ((CC
= getenv("CC")) == NULL
)
114 if ((pathname
= findcc(CC
)) == NULL
)
115 if (!setenv("PATH", DEFAULT_PATH
, 1))
116 pathname
= findcc(CC
);
117 if (pathname
== NULL
)
118 err(EXIT_FAILURE
, "%s: not found", CC
);
119 if ((args
= malloc((argc
+ 3) * sizeof(char *))) == NULL
)
120 err(EXIT_FAILURE
, "malloc");
122 args
[0] = deconst(CC
);
123 args
[1] = deconst("-M");
124 (void)memcpy(&args
[2], argv
, (argc
+ 1) * sizeof(char *));
126 if ((tmpdir
= getenv("TMPDIR")) == NULL
)
128 (void)snprintf(tmpfilename
, sizeof (tmpfilename
), "%s/%s", tmpdir
,
130 if ((tmpfd
= mkstemp(tmpfilename
)) < 0)
131 err(EXIT_FAILURE
, "Unable to create temporary file %s",
133 (void)unlink(tmpfilename
);
134 *fname
= tmpfilename
;
138 for (a
= args
; *a
; a
++)
143 switch (cpid
= vfork()) {
145 (void)dup2(tmpfd
, STDOUT_FILENO
);
148 (void)execv(pathname
, args
);
153 err(EXIT_FAILURE
, "unable to fork");
159 while (((pid
= wait(&status
)) != cpid
) && (pid
>= 0))
163 errx(EXIT_FAILURE
, "compile failed.");
175 for (len
= 0; (ch
= getchar()) != EOF
; len
++) {
182 if (len
>= fbuflen
- 1) {
183 fbuf
= realloc(fbuf
, fbuflen
+= 32);
185 err(EXIT_FAILURE
, "no memory");
195 static struct option longopt
[] = {
196 { "sysroot", 1, NULL
, 'R' },
197 { NULL
, 0, NULL
, '\0' },
201 addsuff(suff_list_t
**l
, const char *s
, size_t len
)
203 suff_list_t
*p
= calloc(1, sizeof(*p
));
206 p
->suff
= malloc(len
+ 1);
209 memcpy(p
->suff
, s
, len
);
217 main(int argc
, char **argv
)
219 int aflag
, dflag
, iflag
, oflag
, qflag
;
220 const char *filename
;
222 char *buf
, *lim
, *ptr
, *line
, *suf
, *colon
, *eol
;
228 const char *prefix
= NULL
;
229 const char *suffixes
= NULL
, *s
;
230 suff_list_t
*suff_list
= NULL
, *sl
;
231 #if !defined(__minix)
234 /* triggers a 'may be used uninitialized', when compiled with gcc,
235 * asserts off, and -Os. */
237 #endif /* !defined(__minix) */
239 suf
= NULL
; /* XXXGCC -Wuninitialized [sun2] */
240 sl
= NULL
; /* XXXGCC -Wuninitialized [sun2] */
242 setlocale(LC_ALL
, "");
243 setprogname(argv
[0]);
245 aflag
= O_WRONLY
| O_APPEND
| O_CREAT
| O_TRUNC
;
250 filename
= DEFAULT_FILENAME
;
253 opterr
= 0; /* stop getopt() bleating about errors. */
256 ch
= getopt_long(argc
, argv
, "aDdf:ioP:pqRs:v", longopt
, NULL
);
261 case 'a': /* Append to output file */
264 case 'D': /* Process *.d files (don't run cc -M) */
265 dflag
= 2; /* Read names from stdin */
268 case 'd': /* Process *.d files (don't run cc -M) */
272 case 'f': /* Name of output file */
278 case 'o': /* Mark dependent files .OPTIONAL */
281 case 'P': /* Prefix for each target filename */
284 case 'p': /* Program mode (x.o: -> x:) */
287 case 'q': /* Quiet */
291 /* sysroot = optarg */
293 case 's': /* Suffix list */
302 /* Unknown arguments are passed to "${CC} -M" */
310 if ((argc
== 0 && !dflag
) || (argc
!= 0 && dflag
== 2))
313 if (suffixes
!= NULL
) {
315 for (s
= suffixes
; (sz
= strcspn(s
, ", ")) != 0;) {
316 addsuff(&suff_list
, s
, sz
);
318 while (*s
&& strchr(", ", *s
))
322 addsuff(&suff_list
, "", 0);
325 dependfile
= open(filename
, aflag
, 0666);
326 if (dependfile
== -1)
329 while (dflag
== 2 || *argv
!= NULL
) {
332 fname
= read_fname();
338 if (dprintf(dependfile
, ".-include \"%s\"\n",
343 fd
= open(fname
, O_RDONLY
, 0);
346 warn("ignoring %s", fname
);
350 fd
= run_cc(argc
, argv
, &fname
);
351 /* consume all args... */
355 sz
= lseek(fd
, 0, SEEK_END
);
360 buf
= mmap(NULL
, sz
, PROT_READ
|PROT_WRITE
, MAP_PRIVATE
, fd
, 0);
363 if (buf
== MAP_FAILED
)
364 err(EXIT_FAILURE
, "unable to mmap file %s", fname
);
367 /* Remove leading "./" from filenames */
368 for (ptr
= buf
; ptr
< lim
; ptr
++) {
369 if (ptr
[1] != '.' || ptr
[2] != '/'
370 || !isspace((unsigned char)ptr
[0]))
376 for (line
= eol
= buf
; eol
<= lim
;) {
377 while (eol
<= lim
&& *eol
++ != '\n')
378 /* Find end of this line */
380 if (line
== eol
- 1) {
381 /* empty line - ignore */
386 /* Assemble continuation lines */
388 for (colon
= line
; *colon
!= ':'; colon
++) {
394 if (isspace((unsigned char)*line
) || colon
== NULL
) {
395 /* No dependency - just transcribe line */
396 if (write(dependfile
, line
, eol
- line
) < 0)
401 if (suff_list
!= NULL
) {
403 /* First allow for any whitespace */
404 for (suf
= colon
; suf
> buf
; suf
--) {
405 if (!isspace((unsigned char)suf
[-1]))
410 "Corrupted file `%s'", fname
);
411 /* Then look for any valid suffix */
412 for (sl
= suff_list
; sl
!= NULL
;
414 if (sl
->len
&& buf
<= suf
- sl
->len
&&
415 !memcmp(suf
- sl
->len
, sl
->suff
,
420 * Not found, check for .o, since the
421 * original file will have it.
424 if (memcmp(suf
- 2, ".o", 2) == 0)
431 if (suff_list
!= NULL
&& slen
!= 0) {
433 for (sl
= suff_list
; sl
!= NULL
; sl
= sl
->next
)
436 if (write(dependfile
, " ", 1)
440 if (write(dependfile
, prefix
,
443 if (write(dependfile
, line
,
446 if (write(dependfile
, sl
->suff
,
450 if (write(dependfile
, colon
, eol
- colon
) < 0)
454 if (write(dependfile
, prefix
,
457 if (write(dependfile
, line
, eol
- line
) < 0)
462 save_for_optional(colon
+ 1, eol
);
468 if (oflag
&& opt
!= NULL
) {
469 if (write(dependfile
, ".OPTIONAL:", 10) < 0)
472 sz
= write_optional(dependfile
, opt
, 0);
473 if (sz
== (size_t)-1)
475 /* 'depth' is about 39 for an i386 kernel */
476 /* fprintf(stderr, "Recursion depth %d\n", sz); */
482 err(EXIT_FAILURE
, "unable to %s to file %s",
483 aflag
& O_TRUNC
? "write" : "append", filename
);
488 * Only save each file once - the kernel .depend is 3MB and there is
489 * no point doubling its size.
490 * The data seems to be 'random enough' so the simple binary tree
491 * only has a reasonable depth.
494 save_for_optional(const char *start
, const char *limit
)
497 const char *name
, *end
;
500 while (start
< limit
&& strchr(" \t\n\\", *start
))
502 for (name
= start
; ; name
= end
) {
503 while (name
< limit
&& strchr(" \t\n\\", *name
))
505 for (end
= name
; end
< limit
&& !strchr(" \t\n\\", *end
);)
509 if (end
[-1] == 'c' && end
[-2] == '.' && name
== start
)
510 /* ignore dependency on the files own .c */
515 n
= malloc(sizeof *n
+ (end
- name
));
516 n
->left
= n
->right
= 0;
520 memcpy(n
->name
+ 1, name
, end
- name
);
524 c
= (end
- name
) - n
->len
;
526 c
= memcmp(n
->name
+ 1, name
, (end
- name
));
541 write_optional(int fd
, opt_t
*node
, size_t depth
)
546 d1
= write_optional(fd
, node
->left
, d1
);
547 if (width
> 76 - node
->len
) {
548 if (write(fd
, " \\\n ", 4) < 0)
552 width
+= 1 + node
->len
;
553 if (write(fd
, node
->name
, 1 + node
->len
) < 0)
556 depth
= write_optional(fd
, node
->right
, depth
);
557 return d1
> depth
? d1
: depth
;