]> git.ipfire.org Git - thirdparty/gcc.git/blob - libcpp/mkdeps.c
Update copyright years.
[thirdparty/gcc.git] / libcpp / mkdeps.c
1 /* Dependency generator for Makefile fragments.
2 Copyright (C) 2000-2020 Free Software Foundation, Inc.
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 /* Not set up to just include std::vector et al, here's a simple
28 implementation. */
29
30 /* Keep this structure local to this file, so clients don't find it
31 easy to start making assumptions. */
32 class mkdeps
33 {
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 }
52
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 };
81
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;
105 };
106
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.) */
112
113 static const char *
114 munge (const char *str, const char *trail = NULL, ...)
115 {
116 static unsigned alloc;
117 static char *buf;
118 unsigned dst = 0;
119 va_list args;
120 if (trail)
121 va_start (args, trail);
122
123 for (bool first = true; str; first = false)
124 {
125 unsigned slashes = 0;
126 char c;
127 for (const char *probe = str; (c = *probe++);)
128 {
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;
144
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 */
157
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;
170 }
171
172 if (first)
173 str = trail;
174 else
175 str = va_arg (args, const char *);
176 }
177 if (trail)
178 va_end (args);
179
180 buf[dst] = 0;
181 return buf;
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 *
187 apply_vpath (class mkdeps *d, const char *t)
188 {
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;
197
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;
202
203 /* found a match */
204 t = t + d->vpath[i].len + 1;
205 break;
206 }
207 not_this_one:;
208 }
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
225 class mkdeps *
226 deps_init (void)
227 {
228 return new mkdeps ();
229 }
230
231 void
232 deps_free (class mkdeps *d)
233 {
234 delete d;
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
240 deps_add_target (class mkdeps *d, const char *t, int quote)
241 {
242 t = xstrdup (apply_vpath (d, t));
243
244 if (!quote)
245 {
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++;
255 }
256
257 d->targets.push (t);
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
264 deps_add_default_target (class mkdeps *d, const char *tgt)
265 {
266 /* Only if we have no targets. */
267 if (d->targets.size ())
268 return;
269
270 if (tgt[0] == '\0')
271 deps_add_target (d, "-", 1);
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
294 deps_add_dep (class mkdeps *d, const char *t)
295 {
296 gcc_assert (*t);
297
298 t = apply_vpath (d, t);
299
300 d->deps.push (xstrdup (t));
301 }
302
303 void
304 deps_add_vpath (class mkdeps *d, const char *vpath)
305 {
306 const char *elem, *p;
307
308 for (elem = vpath; *elem; elem = p)
309 {
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';
318 if (*p == ':')
319 p++;
320
321 d->vpath.push (elt);
322 }
323 }
324
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)
332 {
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);
350
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;
373 if (colmax && colmax < 34)
374 colmax = 34;
375
376 if (d->deps.size ())
377 {
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]));
386 }
387 }
388
389 /* Write out dependencies according to the selected format (which is
390 only Make at the moment). */
391
392 void
393 deps_write (const class mkdeps *d, FILE *fp, bool phony, unsigned int colmax)
394 {
395 make_write (d, fp, phony, colmax);
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
403 deps_save (class mkdeps *deps, FILE *f)
404 {
405 unsigned int i;
406 size_t size;
407
408 /* The cppreader structure contains makefile dependences. Write out this
409 structure. */
410
411 /* The number of dependences. */
412 size = deps->deps.size ();
413 if (fwrite (&size, sizeof (size), 1, f) != 1)
414 return -1;
415
416 /* The length of each dependence followed by the string. */
417 for (i = 0; i < deps->deps.size (); i++)
418 {
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;
424 }
425
426 return 0;
427 }
428
429 /* Read back dependency information written with deps_save into
430 the deps sizefer. The third argument may be NULL, in which case
431 the dependency information is just skipped, or it may be a filename,
432 in which case that filename is skipped. */
433
434 int
435 deps_restore (class mkdeps *deps, FILE *fd, const char *self)
436 {
437 size_t size;
438 char *buf = NULL;
439 size_t buf_size = 0;
440
441 /* Number of dependences. */
442 if (fread (&size, sizeof (size), 1, fd) != 1)
443 return -1;
444
445 /* The length of each dependence string, followed by the string. */
446 for (unsigned i = size; i--;)
447 {
448 /* Read in # bytes in string. */
449 if (fread (&size, sizeof (size), 1, fd) != 1)
450 return -1;
451
452 if (size >= buf_size)
453 {
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);
460 return -1;
461 }
462 buf[size] = 0;
463
464 /* Generate makefile dependencies from .pch if -nopch-deps. */
465 if (self != NULL && filename_cmp (buf, self) != 0)
466 deps_add_dep (deps, buf);
467 }
468
469 XDELETEVEC (buf);
470 return 0;
471 }