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