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