0
|
1 /* Dependency generator for Makefile fragments.
|
111
|
2 Copyright (C) 2000-2017 Free Software Foundation, Inc.
|
0
|
3 Contributed by Zack Weinberg, Mar 2000
|
|
4
|
|
5 This program is free software; you can redistribute it and/or modify it
|
|
6 under the terms of the GNU General Public License as published by the
|
|
7 Free Software Foundation; either version 3, or (at your option) any
|
|
8 later version.
|
|
9
|
|
10 This program is distributed in the hope that it will be useful,
|
|
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13 GNU General Public License for more details.
|
|
14
|
|
15 You should have received a copy of the GNU General Public License
|
|
16 along with this program; see the file COPYING3. If not see
|
|
17 <http://www.gnu.org/licenses/>.
|
|
18
|
|
19 In other words, you are welcome to use, share and improve this program.
|
|
20 You are forbidden to forbid anyone else to use, share and improve
|
|
21 what you give them. Help stamp out software-hoarding! */
|
|
22
|
|
23 #include "config.h"
|
|
24 #include "system.h"
|
|
25 #include "mkdeps.h"
|
|
26
|
|
27 /* Keep this structure local to this file, so clients don't find it
|
|
28 easy to start making assumptions. */
|
|
29 struct deps
|
|
30 {
|
|
31 const char **targetv;
|
|
32 unsigned int ntargets; /* number of slots actually occupied */
|
|
33 unsigned int targets_size; /* amt of allocated space - in words */
|
|
34
|
|
35 const char **depv;
|
|
36 unsigned int ndeps;
|
|
37 unsigned int deps_size;
|
|
38
|
|
39 const char **vpathv;
|
|
40 size_t *vpathlv;
|
|
41 unsigned int nvpaths;
|
|
42 unsigned int vpaths_size;
|
|
43 };
|
|
44
|
|
45 static const char *munge (const char *);
|
|
46
|
|
47 /* Given a filename, quote characters in that filename which are
|
|
48 significant to Make. Note that it's not possible to quote all such
|
|
49 characters - e.g. \n, %, *, ?, [, \ (in some contexts), and ~ are
|
|
50 not properly handled. It isn't possible to get this right in any
|
|
51 current version of Make. (??? Still true? Old comment referred to
|
|
52 3.76.1.) */
|
|
53
|
|
54 static const char *
|
|
55 munge (const char *filename)
|
|
56 {
|
|
57 int len;
|
|
58 const char *p, *q;
|
|
59 char *dst, *buffer;
|
|
60
|
|
61 for (p = filename, len = 0; *p; p++, len++)
|
|
62 {
|
|
63 switch (*p)
|
|
64 {
|
|
65 case ' ':
|
|
66 case '\t':
|
|
67 /* GNU make uses a weird quoting scheme for white space.
|
|
68 A space or tab preceded by 2N+1 backslashes represents
|
|
69 N backslashes followed by space; a space or tab
|
|
70 preceded by 2N backslashes represents N backslashes at
|
|
71 the end of a file name; and backslashes in other
|
|
72 contexts should not be doubled. */
|
|
73 for (q = p - 1; filename <= q && *q == '\\'; q--)
|
|
74 len++;
|
|
75 len++;
|
|
76 break;
|
|
77
|
|
78 case '$':
|
|
79 /* '$' is quoted by doubling it. */
|
|
80 len++;
|
|
81 break;
|
|
82
|
|
83 case '#':
|
|
84 /* '#' is quoted with a backslash. */
|
|
85 len++;
|
|
86 break;
|
|
87 }
|
|
88 }
|
|
89
|
|
90 /* Now we know how big to make the buffer. */
|
|
91 buffer = XNEWVEC (char, len + 1);
|
|
92
|
|
93 for (p = filename, dst = buffer; *p; p++, dst++)
|
|
94 {
|
|
95 switch (*p)
|
|
96 {
|
|
97 case ' ':
|
|
98 case '\t':
|
|
99 for (q = p - 1; filename <= q && *q == '\\'; q--)
|
|
100 *dst++ = '\\';
|
|
101 *dst++ = '\\';
|
|
102 break;
|
|
103
|
|
104 case '$':
|
|
105 *dst++ = '$';
|
|
106 break;
|
|
107
|
|
108 case '#':
|
|
109 *dst++ = '\\';
|
|
110 break;
|
|
111
|
|
112 default:
|
|
113 /* nothing */;
|
|
114 }
|
|
115 *dst = *p;
|
|
116 }
|
|
117
|
|
118 *dst = '\0';
|
|
119 return buffer;
|
|
120 }
|
|
121
|
|
122 /* If T begins with any of the partial pathnames listed in d->vpathv,
|
|
123 then advance T to point beyond that pathname. */
|
|
124 static const char *
|
|
125 apply_vpath (struct deps *d, const char *t)
|
|
126 {
|
|
127 if (d->vpathv)
|
|
128 {
|
|
129 unsigned int i;
|
|
130 for (i = 0; i < d->nvpaths; i++)
|
|
131 {
|
111
|
132 if (!filename_ncmp (d->vpathv[i], t, d->vpathlv[i]))
|
0
|
133 {
|
|
134 const char *p = t + d->vpathlv[i];
|
|
135 if (!IS_DIR_SEPARATOR (*p))
|
|
136 goto not_this_one;
|
|
137
|
|
138 /* Do not simplify $(vpath)/../whatever. ??? Might not
|
|
139 be necessary. */
|
|
140 if (p[1] == '.' && p[2] == '.' && IS_DIR_SEPARATOR (p[3]))
|
|
141 goto not_this_one;
|
|
142
|
|
143 /* found a match */
|
|
144 t = t + d->vpathlv[i] + 1;
|
|
145 break;
|
|
146 }
|
|
147 not_this_one:;
|
|
148 }
|
|
149 }
|
|
150
|
|
151 /* Remove leading ./ in any case. */
|
|
152 while (t[0] == '.' && IS_DIR_SEPARATOR (t[1]))
|
|
153 {
|
|
154 t += 2;
|
|
155 /* If we removed a leading ./, then also remove any /s after the
|
|
156 first. */
|
|
157 while (IS_DIR_SEPARATOR (t[0]))
|
|
158 ++t;
|
|
159 }
|
|
160
|
|
161 return t;
|
|
162 }
|
|
163
|
|
164 /* Public routines. */
|
|
165
|
|
166 struct deps *
|
|
167 deps_init (void)
|
|
168 {
|
|
169 return XCNEW (struct deps);
|
|
170 }
|
|
171
|
|
172 void
|
|
173 deps_free (struct deps *d)
|
|
174 {
|
|
175 unsigned int i;
|
|
176
|
|
177 if (d->targetv)
|
|
178 {
|
|
179 for (i = 0; i < d->ntargets; i++)
|
|
180 free ((void *) d->targetv[i]);
|
|
181 free (d->targetv);
|
|
182 }
|
|
183
|
|
184 if (d->depv)
|
|
185 {
|
|
186 for (i = 0; i < d->ndeps; i++)
|
|
187 free ((void *) d->depv[i]);
|
|
188 free (d->depv);
|
|
189 }
|
|
190
|
|
191 if (d->vpathv)
|
|
192 {
|
|
193 for (i = 0; i < d->nvpaths; i++)
|
|
194 free ((void *) d->vpathv[i]);
|
|
195 free (d->vpathv);
|
|
196 free (d->vpathlv);
|
|
197 }
|
|
198
|
|
199 free (d);
|
|
200 }
|
|
201
|
|
202 /* Adds a target T. We make a copy, so it need not be a permanent
|
|
203 string. QUOTE is true if the string should be quoted. */
|
|
204 void
|
|
205 deps_add_target (struct deps *d, const char *t, int quote)
|
|
206 {
|
|
207 if (d->ntargets == d->targets_size)
|
|
208 {
|
|
209 d->targets_size = d->targets_size * 2 + 4;
|
|
210 d->targetv = XRESIZEVEC (const char *, d->targetv, d->targets_size);
|
|
211 }
|
|
212
|
|
213 t = apply_vpath (d, t);
|
|
214 if (quote)
|
|
215 t = munge (t); /* Also makes permanent copy. */
|
|
216 else
|
|
217 t = xstrdup (t);
|
|
218
|
|
219 d->targetv[d->ntargets++] = t;
|
|
220 }
|
|
221
|
|
222 /* Sets the default target if none has been given already. An empty
|
|
223 string as the default target in interpreted as stdin. The string
|
|
224 is quoted for MAKE. */
|
|
225 void
|
|
226 deps_add_default_target (struct deps *d, const char *tgt)
|
|
227 {
|
|
228 /* Only if we have no targets. */
|
|
229 if (d->ntargets)
|
|
230 return;
|
|
231
|
|
232 if (tgt[0] == '\0')
|
|
233 deps_add_target (d, "-", 1);
|
|
234 else
|
|
235 {
|
|
236 #ifndef TARGET_OBJECT_SUFFIX
|
|
237 # define TARGET_OBJECT_SUFFIX ".o"
|
|
238 #endif
|
|
239 const char *start = lbasename (tgt);
|
|
240 char *o = (char *) alloca (strlen (start)
|
|
241 + strlen (TARGET_OBJECT_SUFFIX) + 1);
|
|
242 char *suffix;
|
|
243
|
|
244 strcpy (o, start);
|
|
245
|
|
246 suffix = strrchr (o, '.');
|
|
247 if (!suffix)
|
|
248 suffix = o + strlen (o);
|
|
249 strcpy (suffix, TARGET_OBJECT_SUFFIX);
|
|
250
|
|
251 deps_add_target (d, o, 1);
|
|
252 }
|
|
253 }
|
|
254
|
|
255 void
|
|
256 deps_add_dep (struct deps *d, const char *t)
|
|
257 {
|
|
258 t = munge (apply_vpath (d, t)); /* Also makes permanent copy. */
|
|
259
|
|
260 if (d->ndeps == d->deps_size)
|
|
261 {
|
|
262 d->deps_size = d->deps_size * 2 + 8;
|
|
263 d->depv = XRESIZEVEC (const char *, d->depv, d->deps_size);
|
|
264 }
|
|
265 d->depv[d->ndeps++] = t;
|
|
266 }
|
|
267
|
|
268 void
|
|
269 deps_add_vpath (struct deps *d, const char *vpath)
|
|
270 {
|
|
271 const char *elem, *p;
|
|
272 char *copy;
|
|
273 size_t len;
|
|
274
|
|
275 for (elem = vpath; *elem; elem = p)
|
|
276 {
|
|
277 for (p = elem; *p && *p != ':'; p++);
|
|
278 len = p - elem;
|
|
279 copy = XNEWVEC (char, len + 1);
|
|
280 memcpy (copy, elem, len);
|
|
281 copy[len] = '\0';
|
|
282 if (*p == ':')
|
|
283 p++;
|
|
284
|
|
285 if (d->nvpaths == d->vpaths_size)
|
|
286 {
|
|
287 d->vpaths_size = d->vpaths_size * 2 + 8;
|
|
288 d->vpathv = XRESIZEVEC (const char *, d->vpathv, d->vpaths_size);
|
|
289 d->vpathlv = XRESIZEVEC (size_t, d->vpathlv, d->vpaths_size);
|
|
290 }
|
|
291 d->vpathv[d->nvpaths] = copy;
|
|
292 d->vpathlv[d->nvpaths] = len;
|
|
293 d->nvpaths++;
|
|
294 }
|
|
295 }
|
|
296
|
|
297 void
|
|
298 deps_write (const struct deps *d, FILE *fp, unsigned int colmax)
|
|
299 {
|
|
300 unsigned int size, i, column;
|
|
301
|
|
302 column = 0;
|
|
303 if (colmax && colmax < 34)
|
|
304 colmax = 34;
|
|
305
|
|
306 for (i = 0; i < d->ntargets; i++)
|
|
307 {
|
|
308 size = strlen (d->targetv[i]);
|
|
309 column += size;
|
|
310 if (i)
|
|
311 {
|
|
312 if (colmax && column > colmax)
|
|
313 {
|
|
314 fputs (" \\\n ", fp);
|
|
315 column = 1 + size;
|
|
316 }
|
|
317 else
|
|
318 {
|
|
319 putc (' ', fp);
|
|
320 column++;
|
|
321 }
|
|
322 }
|
|
323 fputs (d->targetv[i], fp);
|
|
324 }
|
|
325
|
|
326 putc (':', fp);
|
|
327 column++;
|
|
328
|
|
329 for (i = 0; i < d->ndeps; i++)
|
|
330 {
|
|
331 size = strlen (d->depv[i]);
|
|
332 column += size;
|
|
333 if (colmax && column > colmax)
|
|
334 {
|
|
335 fputs (" \\\n ", fp);
|
|
336 column = 1 + size;
|
|
337 }
|
|
338 else
|
|
339 {
|
|
340 putc (' ', fp);
|
|
341 column++;
|
|
342 }
|
|
343 fputs (d->depv[i], fp);
|
|
344 }
|
|
345 putc ('\n', fp);
|
|
346 }
|
|
347
|
|
348 void
|
|
349 deps_phony_targets (const struct deps *d, FILE *fp)
|
|
350 {
|
|
351 unsigned int i;
|
|
352
|
|
353 for (i = 1; i < d->ndeps; i++)
|
|
354 {
|
|
355 putc ('\n', fp);
|
|
356 fputs (d->depv[i], fp);
|
|
357 putc (':', fp);
|
|
358 putc ('\n', fp);
|
|
359 }
|
|
360 }
|
|
361
|
|
362 /* Write out a deps buffer to a file, in a form that can be read back
|
|
363 with deps_restore. Returns nonzero on error, in which case the
|
|
364 error number will be in errno. */
|
|
365
|
|
366 int
|
|
367 deps_save (struct deps *deps, FILE *f)
|
|
368 {
|
|
369 unsigned int i;
|
|
370
|
|
371 /* The cppreader structure contains makefile dependences. Write out this
|
|
372 structure. */
|
|
373
|
|
374 /* The number of dependences. */
|
|
375 if (fwrite (&deps->ndeps, sizeof (deps->ndeps), 1, f) != 1)
|
|
376 return -1;
|
|
377 /* The length of each dependence followed by the string. */
|
|
378 for (i = 0; i < deps->ndeps; i++)
|
|
379 {
|
|
380 size_t num_to_write = strlen (deps->depv[i]);
|
|
381 if (fwrite (&num_to_write, sizeof (size_t), 1, f) != 1)
|
|
382 return -1;
|
|
383 if (fwrite (deps->depv[i], num_to_write, 1, f) != 1)
|
|
384 return -1;
|
|
385 }
|
|
386
|
|
387 return 0;
|
|
388 }
|
|
389
|
|
390 /* Read back dependency information written with deps_save into
|
|
391 the deps buffer. The third argument may be NULL, in which case
|
|
392 the dependency information is just skipped, or it may be a filename,
|
|
393 in which case that filename is skipped. */
|
|
394
|
|
395 int
|
|
396 deps_restore (struct deps *deps, FILE *fd, const char *self)
|
|
397 {
|
|
398 unsigned int i, count;
|
|
399 size_t num_to_read;
|
|
400 size_t buf_size = 512;
|
111
|
401 char *buf;
|
0
|
402
|
|
403 /* Number of dependences. */
|
|
404 if (fread (&count, 1, sizeof (count), fd) != sizeof (count))
|
|
405 return -1;
|
|
406
|
111
|
407 buf = XNEWVEC (char, buf_size);
|
|
408
|
0
|
409 /* The length of each dependence string, followed by the string. */
|
|
410 for (i = 0; i < count; i++)
|
|
411 {
|
|
412 /* Read in # bytes in string. */
|
|
413 if (fread (&num_to_read, 1, sizeof (size_t), fd) != sizeof (size_t))
|
111
|
414 {
|
|
415 free (buf);
|
|
416 return -1;
|
|
417 }
|
0
|
418 if (buf_size < num_to_read + 1)
|
|
419 {
|
|
420 buf_size = num_to_read + 1 + 127;
|
|
421 buf = XRESIZEVEC (char, buf, buf_size);
|
|
422 }
|
|
423 if (fread (buf, 1, num_to_read, fd) != num_to_read)
|
111
|
424 {
|
|
425 free (buf);
|
|
426 return -1;
|
|
427 }
|
0
|
428 buf[num_to_read] = '\0';
|
|
429
|
|
430 /* Generate makefile dependencies from .pch if -nopch-deps. */
|
111
|
431 if (self != NULL && filename_cmp (buf, self) != 0)
|
0
|
432 deps_add_dep (deps, buf);
|
|
433 }
|
|
434
|
|
435 free (buf);
|
|
436 return 0;
|
|
437 }
|