0
|
1 /* Dependency generator for Makefile fragments.
|
145
|
2 Copyright (C) 2000-2020 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
|
145
|
27 /* Not set up to just include std::vector et al, here's a simple
|
|
28 implementation. */
|
|
29
|
0
|
30 /* Keep this structure local to this file, so clients don't find it
|
|
31 easy to start making assumptions. */
|
145
|
32 class mkdeps
|
0
|
33 {
|
145
|
34 public:
|
|
35 /* T has trivial cctor & dtor. */
|
|
36 template <typename T>
|
|
37 class vec
|
|
38 {
|
|
39 private:
|
|
40 T *ary;
|
|
41 unsigned num;
|
|
42 unsigned alloc;
|
|
43
|
|
44 public:
|
|
45 vec ()
|
|
46 : ary (NULL), num (0), alloc (0)
|
|
47 {}
|
|
48 ~vec ()
|
|
49 {
|
|
50 XDELETEVEC (ary);
|
|
51 }
|
0
|
52
|
145
|
53 public:
|
|
54 unsigned size () const
|
|
55 {
|
|
56 return num;
|
|
57 }
|
|
58 const T &operator[] (unsigned ix) const
|
|
59 {
|
|
60 return ary[ix];
|
|
61 }
|
|
62 T &operator[] (unsigned ix)
|
|
63 {
|
|
64 return ary[ix];
|
|
65 }
|
|
66 void push (const T &elt)
|
|
67 {
|
|
68 if (num == alloc)
|
|
69 {
|
|
70 alloc = alloc ? alloc * 2 : 16;
|
|
71 ary = XRESIZEVEC (T, ary, alloc);
|
|
72 }
|
|
73 ary[num++] = elt;
|
|
74 }
|
|
75 };
|
|
76 struct velt
|
|
77 {
|
|
78 const char *str;
|
|
79 size_t len;
|
|
80 };
|
0
|
81
|
145
|
82 mkdeps ()
|
|
83 : quote_lwm (0)
|
|
84 {
|
|
85 }
|
|
86 ~mkdeps ()
|
|
87 {
|
|
88 unsigned int i;
|
|
89
|
|
90 for (i = targets.size (); i--;)
|
|
91 free (const_cast <char *> (targets[i]));
|
|
92 for (i = deps.size (); i--;)
|
|
93 free (const_cast <char *> (deps[i]));
|
|
94 for (i = vpath.size (); i--;)
|
|
95 XDELETEVEC (vpath[i].str);
|
|
96 }
|
|
97
|
|
98 public:
|
|
99 vec<const char *> targets;
|
|
100 vec<const char *> deps;
|
|
101 vec<velt> vpath;
|
|
102
|
|
103 public:
|
|
104 unsigned short quote_lwm;
|
0
|
105 };
|
|
106
|
145
|
107 /* Apply Make quoting to STR, TRAIL etc. Note that it's not possible
|
|
108 to quote all such characters - e.g. \n, %, *, ?, [, \ (in some
|
|
109 contexts), and ~ are not properly handled. It isn't possible to
|
|
110 get this right in any current version of Make. (??? Still true?
|
|
111 Old comment referred to 3.76.1.) */
|
0
|
112
|
|
113 static const char *
|
145
|
114 munge (const char *str, const char *trail = NULL, ...)
|
0
|
115 {
|
145
|
116 static unsigned alloc;
|
|
117 static char *buf;
|
|
118 unsigned dst = 0;
|
|
119 va_list args;
|
|
120 if (trail)
|
|
121 va_start (args, trail);
|
0
|
122
|
145
|
123 for (bool first = true; str; first = false)
|
0
|
124 {
|
145
|
125 unsigned slashes = 0;
|
|
126 char c;
|
|
127 for (const char *probe = str; (c = *probe++);)
|
0
|
128 {
|
145
|
129 if (alloc < dst + 4 + slashes)
|
|
130 {
|
|
131 alloc = alloc * 2 + 32;
|
|
132 buf = XRESIZEVEC (char, buf, alloc);
|
|
133 }
|
|
134
|
|
135 switch (c)
|
|
136 {
|
|
137 case '\\':
|
|
138 slashes++;
|
|
139 break;
|
|
140
|
|
141 case '$':
|
|
142 buf[dst++] = '$';
|
|
143 goto def;
|
0
|
144
|
145
|
145 case ' ':
|
|
146 case '\t':
|
|
147 /* GNU make uses a weird quoting scheme for white space.
|
|
148 A space or tab preceded by 2N+1 backslashes
|
|
149 represents N backslashes followed by space; a space
|
|
150 or tab preceded by 2N backslashes represents N
|
|
151 backslashes at the end of a file name; and
|
|
152 backslashes in other contexts should not be
|
|
153 doubled. */
|
|
154 while (slashes--)
|
|
155 buf[dst++] = '\\';
|
|
156 /* FALLTHROUGH */
|
0
|
157
|
145
|
158 case '#':
|
|
159 case ':':
|
|
160 buf[dst++] = '\\';
|
|
161 /* FALLTHROUGH */
|
|
162
|
|
163 default:
|
|
164 def:
|
|
165 slashes = 0;
|
|
166 break;
|
|
167 }
|
|
168
|
|
169 buf[dst++] = c;
|
0
|
170 }
|
|
171
|
145
|
172 if (first)
|
|
173 str = trail;
|
|
174 else
|
|
175 str = va_arg (args, const char *);
|
|
176 }
|
|
177 if (trail)
|
|
178 va_end (args);
|
0
|
179
|
145
|
180 buf[dst] = 0;
|
|
181 return buf;
|
0
|
182 }
|
|
183
|
|
184 /* If T begins with any of the partial pathnames listed in d->vpathv,
|
|
185 then advance T to point beyond that pathname. */
|
|
186 static const char *
|
145
|
187 apply_vpath (class mkdeps *d, const char *t)
|
0
|
188 {
|
145
|
189 if (unsigned len = d->vpath.size ())
|
|
190 for (unsigned i = len; i--;)
|
|
191 {
|
|
192 if (!filename_ncmp (d->vpath[i].str, t, d->vpath[i].len))
|
|
193 {
|
|
194 const char *p = t + d->vpath[i].len;
|
|
195 if (!IS_DIR_SEPARATOR (*p))
|
|
196 goto not_this_one;
|
0
|
197
|
145
|
198 /* Do not simplify $(vpath)/../whatever. ??? Might not
|
|
199 be necessary. */
|
|
200 if (p[1] == '.' && p[2] == '.' && IS_DIR_SEPARATOR (p[3]))
|
|
201 goto not_this_one;
|
0
|
202
|
145
|
203 /* found a match */
|
|
204 t = t + d->vpath[i].len + 1;
|
|
205 break;
|
|
206 }
|
|
207 not_this_one:;
|
|
208 }
|
0
|
209
|
|
210 /* Remove leading ./ in any case. */
|
|
211 while (t[0] == '.' && IS_DIR_SEPARATOR (t[1]))
|
|
212 {
|
|
213 t += 2;
|
|
214 /* If we removed a leading ./, then also remove any /s after the
|
|
215 first. */
|
|
216 while (IS_DIR_SEPARATOR (t[0]))
|
|
217 ++t;
|
|
218 }
|
|
219
|
|
220 return t;
|
|
221 }
|
|
222
|
|
223 /* Public routines. */
|
|
224
|
145
|
225 class mkdeps *
|
0
|
226 deps_init (void)
|
|
227 {
|
145
|
228 return new mkdeps ();
|
0
|
229 }
|
|
230
|
|
231 void
|
145
|
232 deps_free (class mkdeps *d)
|
0
|
233 {
|
145
|
234 delete d;
|
0
|
235 }
|
|
236
|
|
237 /* Adds a target T. We make a copy, so it need not be a permanent
|
|
238 string. QUOTE is true if the string should be quoted. */
|
|
239 void
|
145
|
240 deps_add_target (class mkdeps *d, const char *t, int quote)
|
0
|
241 {
|
145
|
242 t = xstrdup (apply_vpath (d, t));
|
|
243
|
|
244 if (!quote)
|
0
|
245 {
|
145
|
246 /* Sometimes unquoted items are added after quoted ones.
|
|
247 Swap out the lowest quoted. */
|
|
248 if (d->quote_lwm != d->targets.size ())
|
|
249 {
|
|
250 const char *lowest = d->targets[d->quote_lwm];
|
|
251 d->targets[d->quote_lwm] = t;
|
|
252 t = lowest;
|
|
253 }
|
|
254 d->quote_lwm++;
|
0
|
255 }
|
|
256
|
145
|
257 d->targets.push (t);
|
0
|
258 }
|
|
259
|
|
260 /* Sets the default target if none has been given already. An empty
|
|
261 string as the default target in interpreted as stdin. The string
|
|
262 is quoted for MAKE. */
|
|
263 void
|
145
|
264 deps_add_default_target (class mkdeps *d, const char *tgt)
|
0
|
265 {
|
|
266 /* Only if we have no targets. */
|
145
|
267 if (d->targets.size ())
|
0
|
268 return;
|
|
269
|
|
270 if (tgt[0] == '\0')
|
145
|
271 d->targets.push (xstrdup ("-"));
|
0
|
272 else
|
|
273 {
|
|
274 #ifndef TARGET_OBJECT_SUFFIX
|
|
275 # define TARGET_OBJECT_SUFFIX ".o"
|
|
276 #endif
|
|
277 const char *start = lbasename (tgt);
|
|
278 char *o = (char *) alloca (strlen (start)
|
|
279 + strlen (TARGET_OBJECT_SUFFIX) + 1);
|
|
280 char *suffix;
|
|
281
|
|
282 strcpy (o, start);
|
|
283
|
|
284 suffix = strrchr (o, '.');
|
|
285 if (!suffix)
|
|
286 suffix = o + strlen (o);
|
|
287 strcpy (suffix, TARGET_OBJECT_SUFFIX);
|
|
288
|
|
289 deps_add_target (d, o, 1);
|
|
290 }
|
|
291 }
|
|
292
|
|
293 void
|
145
|
294 deps_add_dep (class mkdeps *d, const char *t)
|
0
|
295 {
|
145
|
296 gcc_assert (*t);
|
0
|
297
|
145
|
298 t = apply_vpath (d, t);
|
|
299
|
|
300 d->deps.push (xstrdup (t));
|
0
|
301 }
|
|
302
|
|
303 void
|
145
|
304 deps_add_vpath (class mkdeps *d, const char *vpath)
|
0
|
305 {
|
|
306 const char *elem, *p;
|
|
307
|
|
308 for (elem = vpath; *elem; elem = p)
|
|
309 {
|
145
|
310 for (p = elem; *p && *p != ':'; p++)
|
|
311 continue;
|
|
312 mkdeps::velt elt;
|
|
313 elt.len = p - elem;
|
|
314 char *str = XNEWVEC (char, elt.len + 1);
|
|
315 elt.str = str;
|
|
316 memcpy (str, elem, elt.len);
|
|
317 str[elt.len] = '\0';
|
0
|
318 if (*p == ':')
|
|
319 p++;
|
|
320
|
145
|
321 d->vpath.push (elt);
|
0
|
322 }
|
|
323 }
|
|
324
|
145
|
325 /* Write NAME, with a leading space to FP, a Makefile. Advance COL as
|
|
326 appropriate, wrap at COLMAX, returning new column number. Iff
|
|
327 QUOTE apply quoting. Append TRAIL. */
|
|
328
|
|
329 static unsigned
|
|
330 make_write_name (const char *name, FILE *fp, unsigned col, unsigned colmax,
|
|
331 bool quote = true, const char *trail = NULL)
|
0
|
332 {
|
145
|
333 if (quote)
|
|
334 name = munge (name, trail, NULL);
|
|
335 unsigned size = strlen (name);
|
|
336
|
|
337 if (col)
|
|
338 {
|
|
339 if (colmax && col + size> colmax)
|
|
340 {
|
|
341 fputs (" \\\n", fp);
|
|
342 col = 0;
|
|
343 }
|
|
344 col++;
|
|
345 fputs (" ", fp);
|
|
346 }
|
|
347
|
|
348 col += size;
|
|
349 fputs (name, fp);
|
0
|
350
|
145
|
351 return col;
|
|
352 }
|
|
353
|
|
354 /* Write all the names in VEC via make_write_name. */
|
|
355
|
|
356 static unsigned
|
|
357 make_write_vec (const mkdeps::vec<const char *> &vec, FILE *fp,
|
|
358 unsigned col, unsigned colmax, unsigned quote_lwm = 0,
|
|
359 const char *trail = NULL)
|
|
360 {
|
|
361 for (unsigned ix = 0; ix != vec.size (); ix++)
|
|
362 col = make_write_name (vec[ix], fp, col, colmax, ix >= quote_lwm, trail);
|
|
363 return col;
|
|
364 }
|
|
365
|
|
366 /* Write the dependencies to a Makefile. If PHONY is true, add
|
|
367 .PHONY targets for all the dependencies too. */
|
|
368
|
|
369 static void
|
|
370 make_write (const class mkdeps *d, FILE *fp, bool phony, unsigned int colmax)
|
|
371 {
|
|
372 unsigned column = 0;
|
0
|
373 if (colmax && colmax < 34)
|
|
374 colmax = 34;
|
|
375
|
145
|
376 if (d->deps.size ())
|
0
|
377 {
|
145
|
378 column = make_write_vec (d->targets, fp, 0, colmax, d->quote_lwm);
|
|
379 fputs (":", fp);
|
|
380 column++;
|
|
381 make_write_vec (d->deps, fp, column, colmax);
|
|
382 fputs ("\n", fp);
|
|
383 if (phony)
|
|
384 for (unsigned i = 1; i < d->deps.size (); i++)
|
|
385 fprintf (fp, "%s:\n", munge (d->deps[i]));
|
0
|
386 }
|
|
387 }
|
|
388
|
145
|
389 /* Write out dependencies according to the selected format (which is
|
|
390 only Make at the moment). */
|
0
|
391
|
145
|
392 void
|
|
393 deps_write (const class mkdeps *d, FILE *fp, bool phony, unsigned int colmax)
|
|
394 {
|
|
395 make_write (d, fp, phony, colmax);
|
0
|
396 }
|
|
397
|
|
398 /* Write out a deps buffer to a file, in a form that can be read back
|
|
399 with deps_restore. Returns nonzero on error, in which case the
|
|
400 error number will be in errno. */
|
|
401
|
|
402 int
|
145
|
403 deps_save (class mkdeps *deps, FILE *f)
|
0
|
404 {
|
|
405 unsigned int i;
|
145
|
406 size_t size;
|
0
|
407
|
|
408 /* The cppreader structure contains makefile dependences. Write out this
|
|
409 structure. */
|
|
410
|
|
411 /* The number of dependences. */
|
145
|
412 size = deps->deps.size ();
|
|
413 if (fwrite (&size, sizeof (size), 1, f) != 1)
|
|
414 return -1;
|
|
415
|
0
|
416 /* The length of each dependence followed by the string. */
|
145
|
417 for (i = 0; i < deps->deps.size (); i++)
|
0
|
418 {
|
145
|
419 size = strlen (deps->deps[i]);
|
|
420 if (fwrite (&size, sizeof (size), 1, f) != 1)
|
|
421 return -1;
|
|
422 if (fwrite (deps->deps[i], size, 1, f) != 1)
|
|
423 return -1;
|
0
|
424 }
|
|
425
|
|
426 return 0;
|
|
427 }
|
|
428
|
|
429 /* Read back dependency information written with deps_save into
|
145
|
430 the deps sizefer. The third argument may be NULL, in which case
|
0
|
431 the dependency information is just skipped, or it may be a filename,
|
|
432 in which case that filename is skipped. */
|
|
433
|
|
434 int
|
145
|
435 deps_restore (class mkdeps *deps, FILE *fd, const char *self)
|
0
|
436 {
|
145
|
437 size_t size;
|
|
438 char *buf = NULL;
|
|
439 size_t buf_size = 0;
|
0
|
440
|
|
441 /* Number of dependences. */
|
145
|
442 if (fread (&size, sizeof (size), 1, fd) != 1)
|
0
|
443 return -1;
|
|
444
|
|
445 /* The length of each dependence string, followed by the string. */
|
145
|
446 for (unsigned i = size; i--;)
|
0
|
447 {
|
|
448 /* Read in # bytes in string. */
|
145
|
449 if (fread (&size, sizeof (size), 1, fd) != 1)
|
|
450 return -1;
|
|
451
|
|
452 if (size >= buf_size)
|
111
|
453 {
|
145
|
454 buf_size = size + 512;
|
|
455 buf = XRESIZEVEC (char, buf, buf_size);
|
|
456 }
|
|
457 if (fread (buf, 1, size, fd) != size)
|
|
458 {
|
|
459 XDELETEVEC (buf);
|
111
|
460 return -1;
|
|
461 }
|
145
|
462 buf[size] = 0;
|
0
|
463
|
|
464 /* Generate makefile dependencies from .pch if -nopch-deps. */
|
111
|
465 if (self != NULL && filename_cmp (buf, self) != 0)
|
0
|
466 deps_add_dep (deps, buf);
|
|
467 }
|
|
468
|
145
|
469 XDELETEVEC (buf);
|
0
|
470 return 0;
|
|
471 }
|