mkdep.c revision 1.18 1 /* $NetBSD: mkdep.c,v 1.18 2003/11/10 17:56:38 dsl Exp $ */
2
3 /*-
4 * Copyright (c) 1999 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Matthias Scheler.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
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.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #if HAVE_NBTOOL_CONFIG_H
40 #include "nbtool_config.h"
41 #endif
42
43 #include <sys/cdefs.h>
44 #if !defined(lint)
45 __COPYRIGHT("@(#) Copyright (c) 1999 The NetBSD Foundation, Inc.\n\
46 All rights reserved.\n");
47 __RCSID("$NetBSD: mkdep.c,v 1.18 2003/11/10 17:56:38 dsl Exp $");
48 #endif /* not lint */
49
50 #include <sys/mman.h>
51 #include <sys/param.h>
52 #include <sys/wait.h>
53 #include <ctype.h>
54 #include <err.h>
55 #include <fcntl.h>
56 #include <locale.h>
57 #include <paths.h>
58 #include <signal.h>
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #include <unistd.h>
63
64 #include "findcc.h"
65
66 #define DEFAULT_PATH _PATH_DEFPATH
67 #define DEFAULT_FILENAME ".depend"
68
69
70 static inline void *
71 deconst(const void *p)
72 {
73 return (const char *)p - (const char *)0 + (char *)0;
74 }
75
76 static void
77 usage(void)
78 {
79 (void)fprintf(stderr,
80 "usage: %s [-acopq] [-f file] [-s suffix_list] flags file ...\n",
81 getprogname());
82 exit(EXIT_FAILURE);
83 }
84
85 static int
86 run_cc(int argc, char **argv, const char **fname)
87 {
88 const char *CC, *pathname, *tmpdir;
89 static char tmpfilename[MAXPATHLEN];
90 char **args;
91 int tmpfd;
92 pid_t pid, cpid;
93 int status;
94
95 if ((CC = getenv("CC")) == NULL)
96 CC = DEFAULT_CC;
97 if ((pathname = findcc(CC)) == NULL)
98 if (!setenv("PATH", DEFAULT_PATH, 1))
99 pathname = findcc(CC);
100 if (pathname == NULL)
101 err(EXIT_FAILURE, "%s: not found", CC);
102 if ((args = malloc((argc + 3) * sizeof(char *))) == NULL)
103 err(EXIT_FAILURE, "malloc");
104
105 args[0] = deconst(CC);
106 args[1] = deconst("-M");
107 (void)memcpy(&args[2], argv, (argc + 1) * sizeof(char *));
108
109 if ((tmpdir = getenv("TMPDIR")) == NULL)
110 tmpdir = _PATH_TMP;
111 (void)snprintf(tmpfilename, sizeof (tmpfilename), "%s/%s", tmpdir,
112 "mkdepXXXXXX");
113 if ((tmpfd = mkstemp(tmpfilename)) < 0) {
114 warn("unable to create temporary file %s", tmpfilename);
115 exit(EXIT_FAILURE);
116 }
117 (void)unlink(tmpfilename);
118 *fname = tmpfilename;
119
120 switch (cpid = vfork()) {
121 case 0:
122 (void)dup2(tmpfd, STDOUT_FILENO);
123 (void)close(tmpfd);
124
125 (void)execv(pathname, args);
126 _exit(EXIT_FAILURE);
127 /* NOTREACHED */
128
129 case -1:
130 err(EXIT_FAILURE, "unable to fork");
131 }
132
133 while (((pid = wait(&status)) != cpid) && (pid >= 0))
134 continue;
135
136 if (status)
137 errx(EXIT_FAILURE, "compile failed.");
138
139 return tmpfd;
140 }
141
142 int
143 main(int argc, char **argv)
144 {
145 int aflag, dflag, oflag, qflag;
146 const char *filename;
147 int dependfile;
148 char *buf, *ptr, *line, *suf, *colon, *eol;
149 int ok_ind, ch;
150 int sz;
151 int fd;
152 const char *fname;
153 const char *suffixes = NULL, *s, *s1;
154
155 setlocale(LC_ALL, "");
156 setprogname(argv[0]);
157
158 aflag = O_WRONLY | O_APPEND | O_CREAT | O_TRUNC;
159 dflag = 0;
160 oflag = 0;
161 qflag = 0;
162 filename = DEFAULT_FILENAME;
163 dependfile = -1;
164
165 opterr = 0; /* stop getopt() bleating about errors. */
166 ok_ind = 1;
167 for (; (ch = getopt(argc, argv, "adf:opqs:")) != -1; ok_ind = optind) {
168 switch (ch) {
169 case 'a': /* Append to output file */
170 aflag &= ~O_TRUNC;
171 continue;
172 case 'd': /* Process *.d files (don't run cc -M) */
173 dflag = 1;
174 opterr = 1;
175 continue;
176 case 'f': /* Name of output file */
177 filename = optarg;
178 continue;
179 case 'o': /* Mark dependant files .OPTIONAL */
180 oflag = 1;
181 continue;
182 case 'p': /* Program mode (x.o: -> x:) */
183 suffixes = "";
184 continue;
185 case 'q': /* Quiet */
186 qflag = 1;
187 continue;
188 case 's': /* Suffix list */
189 suffixes = optarg;
190 continue;
191 default:
192 if (dflag)
193 usage();
194 /* Unknown arguments are passed to "${CC} -M" */
195 break;
196 }
197 break;
198 }
199
200 argc -= ok_ind;
201 argv += ok_ind;
202 if (argc == 0 && !dflag)
203 usage();
204
205 dependfile = open(filename, aflag, 0666);
206 if (dependfile == -1)
207 err(EXIT_FAILURE, "unable to %s to file %s\n",
208 aflag & O_TRUNC ? "write" : "append", filename);
209
210 for (; *argv != NULL; argv++) {
211 if (dflag) {
212 fname = *argv;
213 fd = open(fname, O_RDONLY, 0);
214 if (fd == -1) {
215 if (!qflag)
216 warn("ignoring %s", fname);
217 continue;
218 }
219 } else {
220 fd = run_cc(argc, argv, &fname);
221 /* consume all args... */
222 argv += argc - 1;
223 }
224
225 sz = lseek(fd, 0, SEEK_END);
226 if (sz == 0) {
227 close(fd);
228 continue;
229 }
230 buf = mmap(NULL, sz, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
231 close(fd);
232
233 if (buf == MAP_FAILED)
234 err(EXIT_FAILURE, "unable to mmap file %s",
235 *argv);
236
237 /* Remove leading "./" from filenames */
238 for (ptr = buf; (ptr = strstr(ptr, "./")) != NULL; ptr += 2) {
239 if (ptr == buf)
240 continue;
241 if (!isspace((unsigned char)ptr[-1]))
242 continue;
243 ptr[0] = ' ';
244 ptr[1] = ' ';
245 }
246
247 line = eol = buf;
248 for (; (eol = strchr(eol, '\n')) != NULL; line = eol) {
249 eol++;
250 if (line == eol - 1)
251 /* empty line - ignore */
252 continue;
253 if (eol[-2] == '\\')
254 /* Assemble continuation lines */
255 continue;
256 colon = strchr(line, ':');
257 if (colon > eol)
258 colon = NULL;
259 if (colon != NULL && suffixes != NULL) {
260 /* Find the .o: */
261 for (suf = colon - 2; ; suf--) {
262 if (suf <= line) {
263 colon = NULL;
264 break;
265 }
266 if (isspace((unsigned char)suf[1]))
267 continue;
268 if (suf[0] != '.' || suf[1] != 'o')
269 /* not a file.o: line */
270 colon = NULL;
271 break;
272 }
273 }
274 if (colon == NULL) {
275 /* No dependency - just transcribe line */
276 write(dependfile, line, eol - line);
277 line = eol;
278 continue;
279 }
280 if (suffixes != NULL) {
281 for (s = suffixes; ; s = s1 + 1) {
282 s1 = strpbrk(s, ", ");
283 if (s1 == NULL)
284 s1 = s + strlen(s);
285 write(dependfile, line, suf - line);
286 write(dependfile, s, s1 - s);
287 if (*s1 == 0)
288 break;
289 write(dependfile, " ", 1);
290 }
291 write(dependfile, colon, eol - colon);
292 } else
293 write(dependfile, line, eol - line);
294
295 if (oflag) {
296 write(dependfile, ".OPTIONAL", 9);
297 write(dependfile, colon, eol - colon);
298 }
299 }
300 munmap(buf, sz);
301 }
302 close(dependfile);
303
304 exit(EXIT_SUCCESS);
305 }
306