]> git.ipfire.org Git - thirdparty/gcc.git/blame - libcpp/mkdeps.c
Update copyright years.
[thirdparty/gcc.git] / libcpp / mkdeps.c
CommitLineData
49e6c08e 1/* Dependency generator for Makefile fragments.
8d9254fc 2 Copyright (C) 2000-2020 Free Software Foundation, Inc.
49e6c08e
ZW
3 Contributed by Zack Weinberg, Mar 2000
4
5This program is free software; you can redistribute it and/or modify it
6under the terms of the GNU General Public License as published by the
748086b7 7Free Software Foundation; either version 3, or (at your option) any
49e6c08e
ZW
8later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
748086b7
JJ
16along with this program; see the file COPYING3. If not see
17<http://www.gnu.org/licenses/>.
49e6c08e
ZW
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
d7b6aee8
NS
27/* Not set up to just include std::vector et al, here's a simple
28 implementation. */
29
03b9ab42
NB
30/* Keep this structure local to this file, so clients don't find it
31 easy to start making assumptions. */
6c1dae73 32class mkdeps
03b9ab42 33{
d7b6aee8
NS
34public:
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
49e6c08e 55 {
d7b6aee8 56 return num;
49e6c08e 57 }
d7b6aee8 58 const T &operator[] (unsigned ix) const
49e6c08e 59 {
d7b6aee8
NS
60 return ary[ix];
61 }
66d7749b
NS
62 T &operator[] (unsigned ix)
63 {
64 return ary[ix];
65 }
d7b6aee8
NS
66 void push (const T &elt)
67 {
68 if (num == alloc)
49e6c08e 69 {
d7b6aee8
NS
70 alloc = alloc ? alloc * 2 : 16;
71 ary = XRESIZEVEC (T, ary, alloc);
49e6c08e 72 }
d7b6aee8 73 ary[num++] = elt;
49e6c08e 74 }
d7b6aee8
NS
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
98public:
99 vec<const char *> targets;
100 vec<const char *> deps;
101 vec<velt> vpath;
102
103public:
104 unsigned short quote_lwm;
105};
49e6c08e 106
d7b6aee8
NS
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.) */
49e6c08e 112
c6e83800 113static const char *
d7b6aee8 114munge (const char *str, const char *trail = NULL, ...)
49e6c08e 115{
d7b6aee8
NS
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)
c6e83800 124 {
d7b6aee8
NS
125 unsigned slashes = 0;
126 char c;
127 for (const char *probe = str; (c = *probe++);)
c6e83800 128 {
d7b6aee8 129 if (alloc < dst + 4 + slashes)
c6e83800 130 {
d7b6aee8
NS
131 alloc = alloc * 2 + 32;
132 buf = XRESIZEVEC (char, buf, alloc);
133 }
c6e83800 134
d7b6aee8
NS
135 switch (c)
136 {
137 case '\\':
138 slashes++;
139 break;
c6e83800 140
d7b6aee8
NS
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;
c6e83800
ZW
166 break;
167 }
d7b6aee8
NS
168
169 buf[dst++] = c;
c6e83800 170 }
d7b6aee8
NS
171
172 if (first)
173 str = trail;
174 else
175 str = va_arg (args, const char *);
c6e83800 176 }
d7b6aee8
NS
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. */
186static const char *
99b1c316 187apply_vpath (class mkdeps *d, const char *t)
d7b6aee8
NS
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 }
49e6c08e 209
c6e83800
ZW
210 /* Remove leading ./ in any case. */
211 while (t[0] == '.' && IS_DIR_SEPARATOR (t[1]))
67e64439
TT
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 }
49e6c08e 219
c6e83800
ZW
220 return t;
221}
49e6c08e 222
c6e83800 223/* Public routines. */
49e6c08e 224
99b1c316 225class mkdeps *
c6e83800
ZW
226deps_init (void)
227{
d7b6aee8 228 return new mkdeps ();
49e6c08e
ZW
229}
230
231void
99b1c316 232deps_free (class mkdeps *d)
49e6c08e 233{
d7b6aee8 234 delete d;
49e6c08e
ZW
235}
236
a5a4ce3c
NB
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. */
49e6c08e 239void
99b1c316 240deps_add_target (class mkdeps *d, const char *t, int quote)
49e6c08e 241{
66d7749b
NS
242 t = xstrdup (apply_vpath (d, t));
243
d7b6aee8 244 if (!quote)
49e6c08e 245 {
66d7749b
NS
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 }
d7b6aee8 254 d->quote_lwm++;
49e6c08e 255 }
05bccae2 256
66d7749b 257 d->targets.push (t);
49e6c08e
ZW
258}
259
03b9ab42 260/* Sets the default target if none has been given already. An empty
a5a4ce3c
NB
261 string as the default target in interpreted as stdin. The string
262 is quoted for MAKE. */
49e6c08e 263void
99b1c316 264deps_add_default_target (class mkdeps *d, const char *tgt)
49e6c08e 265{
03b9ab42 266 /* Only if we have no targets. */
d7b6aee8 267 if (d->targets.size ())
03b9ab42 268 return;
49e6c08e 269
03b9ab42 270 if (tgt[0] == '\0')
a5a4ce3c 271 deps_add_target (d, "-", 1);
49e6c08e 272 else
03b9ab42 273 {
45936a85
DD
274#ifndef TARGET_OBJECT_SUFFIX
275# define TARGET_OBJECT_SUFFIX ".o"
03b9ab42 276#endif
0821bff7 277 const char *start = lbasename (tgt);
c3f829c1
GDR
278 char *o = (char *) alloca (strlen (start)
279 + strlen (TARGET_OBJECT_SUFFIX) + 1);
48ce6bbb 280 char *suffix;
03b9ab42 281
48ce6bbb 282 strcpy (o, start);
0c20a65f 283
48ce6bbb
NS
284 suffix = strrchr (o, '.');
285 if (!suffix)
286 suffix = o + strlen (o);
45936a85 287 strcpy (suffix, TARGET_OBJECT_SUFFIX);
0c20a65f 288
a5a4ce3c 289 deps_add_target (d, o, 1);
03b9ab42 290 }
49e6c08e
ZW
291}
292
293void
99b1c316 294deps_add_dep (class mkdeps *d, const char *t)
49e6c08e 295{
61145d93
NS
296 gcc_assert (*t);
297
d7b6aee8 298 t = apply_vpath (d, t);
49e6c08e 299
d7b6aee8 300 d->deps.push (xstrdup (t));
49e6c08e
ZW
301}
302
c6e83800 303void
99b1c316 304deps_add_vpath (class mkdeps *d, const char *vpath)
c6e83800
ZW
305{
306 const char *elem, *p;
c6e83800
ZW
307
308 for (elem = vpath; *elem; elem = p)
309 {
d7b6aee8
NS
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';
c6e83800
ZW
318 if (*p == ':')
319 p++;
320
d7b6aee8 321 d->vpath.push (elt);
c6e83800
ZW
322 }
323}
324
d7b6aee8
NS
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. */
49e6c08e 328
d7b6aee8
NS
329static unsigned
330make_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);
49e6c08e 336
d7b6aee8 337 if (col)
49e6c08e 338 {
d7b6aee8 339 if (colmax && col + size> colmax)
49e6c08e 340 {
d7b6aee8
NS
341 fputs (" \\\n", fp);
342 col = 0;
49e6c08e 343 }
d7b6aee8
NS
344 col++;
345 fputs (" ", fp);
49e6c08e
ZW
346 }
347
d7b6aee8
NS
348 col += size;
349 fputs (name, fp);
49e6c08e 350
d7b6aee8 351 return col;
49e6c08e 352}
0c20a65f 353
d7b6aee8
NS
354/* Write all the names in VEC via make_write_name. */
355
356static unsigned
357make_write_vec (const mkdeps::vec<const char *> &vec, FILE *fp,
358 unsigned col, unsigned colmax, unsigned quote_lwm = 0,
359 const char *trail = NULL)
49e6c08e 360{
d7b6aee8
NS
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}
49e6c08e 365
d7b6aee8
NS
366/* Write the dependencies to a Makefile. If PHONY is true, add
367 .PHONY targets for all the dependencies too. */
368
369static void
99b1c316 370make_write (const class mkdeps *d, FILE *fp, bool phony, unsigned int colmax)
d7b6aee8
NS
371{
372 unsigned column = 0;
373 if (colmax && colmax < 34)
374 colmax = 34;
375
376 if (d->deps.size ())
49e6c08e 377 {
d7b6aee8
NS
378 column = make_write_vec (d->targets, fp, 0, colmax, d->quote_lwm);
379 fputs (":", fp);
380 column++;
8ba6ea87 381 make_write_vec (d->deps, fp, column, colmax);
d7b6aee8
NS
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]));
49e6c08e
ZW
386 }
387}
17211ab5 388
d7b6aee8
NS
389/* Write out dependencies according to the selected format (which is
390 only Make at the moment). */
391
392void
99b1c316 393deps_write (const class mkdeps *d, FILE *fp, bool phony, unsigned int colmax)
d7b6aee8
NS
394{
395 make_write (d, fp, phony, colmax);
396}
397
17211ab5
GK
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
402int
99b1c316 403deps_save (class mkdeps *deps, FILE *f)
17211ab5
GK
404{
405 unsigned int i;
d7b6aee8 406 size_t size;
17211ab5
GK
407
408 /* The cppreader structure contains makefile dependences. Write out this
409 structure. */
410
411 /* The number of dependences. */
d7b6aee8
NS
412 size = deps->deps.size ();
413 if (fwrite (&size, sizeof (size), 1, f) != 1)
414 return -1;
415
17211ab5 416 /* The length of each dependence followed by the string. */
d7b6aee8 417 for (i = 0; i < deps->deps.size (); i++)
17211ab5 418 {
d7b6aee8
NS
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;
17211ab5
GK
424 }
425
426 return 0;
427}
428
429/* Read back dependency information written with deps_save into
d7b6aee8 430 the deps sizefer. The third argument may be NULL, in which case
17211ab5
GK
431 the dependency information is just skipped, or it may be a filename,
432 in which case that filename is skipped. */
433
434int
99b1c316 435deps_restore (class mkdeps *deps, FILE *fd, const char *self)
17211ab5 436{
d7b6aee8
NS
437 size_t size;
438 char *buf = NULL;
439 size_t buf_size = 0;
17211ab5
GK
440
441 /* Number of dependences. */
d7b6aee8 442 if (fread (&size, sizeof (size), 1, fd) != 1)
17211ab5
GK
443 return -1;
444
445 /* The length of each dependence string, followed by the string. */
d7b6aee8 446 for (unsigned i = size; i--;)
17211ab5
GK
447 {
448 /* Read in # bytes in string. */
d7b6aee8
NS
449 if (fread (&size, sizeof (size), 1, fd) != 1)
450 return -1;
451
452 if (size >= buf_size)
17211ab5 453 {
d7b6aee8 454 buf_size = size + 512;
c3f829c1 455 buf = XRESIZEVEC (char, buf, buf_size);
17211ab5 456 }
d7b6aee8 457 if (fread (buf, 1, size, fd) != size)
55e7f907 458 {
d7b6aee8 459 XDELETEVEC (buf);
55e7f907
TB
460 return -1;
461 }
d7b6aee8 462 buf[size] = 0;
17211ab5 463
0c20a65f 464 /* Generate makefile dependencies from .pch if -nopch-deps. */
4489800d 465 if (self != NULL && filename_cmp (buf, self) != 0)
17211ab5
GK
466 deps_add_dep (deps, buf);
467 }
468
d7b6aee8 469 XDELETEVEC (buf);
17211ab5
GK
470 return 0;
471}