1*38fd1498Szrj /* Dependency generator for Makefile fragments.
2*38fd1498Szrj Copyright (C) 2000-2018 Free Software Foundation, Inc.
3*38fd1498Szrj Contributed by Zack Weinberg, Mar 2000
4*38fd1498Szrj
5*38fd1498Szrj This program is free software; you can redistribute it and/or modify it
6*38fd1498Szrj under the terms of the GNU General Public License as published by the
7*38fd1498Szrj Free Software Foundation; either version 3, or (at your option) any
8*38fd1498Szrj later version.
9*38fd1498Szrj
10*38fd1498Szrj This program is distributed in the hope that it will be useful,
11*38fd1498Szrj but WITHOUT ANY WARRANTY; without even the implied warranty of
12*38fd1498Szrj MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13*38fd1498Szrj GNU General Public License for more details.
14*38fd1498Szrj
15*38fd1498Szrj You should have received a copy of the GNU General Public License
16*38fd1498Szrj along with this program; see the file COPYING3. If not see
17*38fd1498Szrj <http://www.gnu.org/licenses/>.
18*38fd1498Szrj
19*38fd1498Szrj In other words, you are welcome to use, share and improve this program.
20*38fd1498Szrj You are forbidden to forbid anyone else to use, share and improve
21*38fd1498Szrj what you give them. Help stamp out software-hoarding! */
22*38fd1498Szrj
23*38fd1498Szrj #include "config.h"
24*38fd1498Szrj #include "system.h"
25*38fd1498Szrj #include "mkdeps.h"
26*38fd1498Szrj
27*38fd1498Szrj /* Keep this structure local to this file, so clients don't find it
28*38fd1498Szrj easy to start making assumptions. */
29*38fd1498Szrj struct deps
30*38fd1498Szrj {
31*38fd1498Szrj const char **targetv;
32*38fd1498Szrj unsigned int ntargets; /* number of slots actually occupied */
33*38fd1498Szrj unsigned int targets_size; /* amt of allocated space - in words */
34*38fd1498Szrj
35*38fd1498Szrj const char **depv;
36*38fd1498Szrj unsigned int ndeps;
37*38fd1498Szrj unsigned int deps_size;
38*38fd1498Szrj
39*38fd1498Szrj const char **vpathv;
40*38fd1498Szrj size_t *vpathlv;
41*38fd1498Szrj unsigned int nvpaths;
42*38fd1498Szrj unsigned int vpaths_size;
43*38fd1498Szrj };
44*38fd1498Szrj
45*38fd1498Szrj static const char *munge (const char *);
46*38fd1498Szrj
47*38fd1498Szrj /* Given a filename, quote characters in that filename which are
48*38fd1498Szrj significant to Make. Note that it's not possible to quote all such
49*38fd1498Szrj characters - e.g. \n, %, *, ?, [, \ (in some contexts), and ~ are
50*38fd1498Szrj not properly handled. It isn't possible to get this right in any
51*38fd1498Szrj current version of Make. (??? Still true? Old comment referred to
52*38fd1498Szrj 3.76.1.) */
53*38fd1498Szrj
54*38fd1498Szrj static const char *
munge(const char * filename)55*38fd1498Szrj munge (const char *filename)
56*38fd1498Szrj {
57*38fd1498Szrj int len;
58*38fd1498Szrj const char *p, *q;
59*38fd1498Szrj char *dst, *buffer;
60*38fd1498Szrj
61*38fd1498Szrj for (p = filename, len = 0; *p; p++, len++)
62*38fd1498Szrj {
63*38fd1498Szrj switch (*p)
64*38fd1498Szrj {
65*38fd1498Szrj case ' ':
66*38fd1498Szrj case '\t':
67*38fd1498Szrj /* GNU make uses a weird quoting scheme for white space.
68*38fd1498Szrj A space or tab preceded by 2N+1 backslashes represents
69*38fd1498Szrj N backslashes followed by space; a space or tab
70*38fd1498Szrj preceded by 2N backslashes represents N backslashes at
71*38fd1498Szrj the end of a file name; and backslashes in other
72*38fd1498Szrj contexts should not be doubled. */
73*38fd1498Szrj for (q = p - 1; filename <= q && *q == '\\'; q--)
74*38fd1498Szrj len++;
75*38fd1498Szrj len++;
76*38fd1498Szrj break;
77*38fd1498Szrj
78*38fd1498Szrj case '$':
79*38fd1498Szrj /* '$' is quoted by doubling it. */
80*38fd1498Szrj len++;
81*38fd1498Szrj break;
82*38fd1498Szrj
83*38fd1498Szrj case '#':
84*38fd1498Szrj /* '#' is quoted with a backslash. */
85*38fd1498Szrj len++;
86*38fd1498Szrj break;
87*38fd1498Szrj }
88*38fd1498Szrj }
89*38fd1498Szrj
90*38fd1498Szrj /* Now we know how big to make the buffer. */
91*38fd1498Szrj buffer = XNEWVEC (char, len + 1);
92*38fd1498Szrj
93*38fd1498Szrj for (p = filename, dst = buffer; *p; p++, dst++)
94*38fd1498Szrj {
95*38fd1498Szrj switch (*p)
96*38fd1498Szrj {
97*38fd1498Szrj case ' ':
98*38fd1498Szrj case '\t':
99*38fd1498Szrj for (q = p - 1; filename <= q && *q == '\\'; q--)
100*38fd1498Szrj *dst++ = '\\';
101*38fd1498Szrj *dst++ = '\\';
102*38fd1498Szrj break;
103*38fd1498Szrj
104*38fd1498Szrj case '$':
105*38fd1498Szrj *dst++ = '$';
106*38fd1498Szrj break;
107*38fd1498Szrj
108*38fd1498Szrj case '#':
109*38fd1498Szrj *dst++ = '\\';
110*38fd1498Szrj break;
111*38fd1498Szrj
112*38fd1498Szrj default:
113*38fd1498Szrj /* nothing */;
114*38fd1498Szrj }
115*38fd1498Szrj *dst = *p;
116*38fd1498Szrj }
117*38fd1498Szrj
118*38fd1498Szrj *dst = '\0';
119*38fd1498Szrj return buffer;
120*38fd1498Szrj }
121*38fd1498Szrj
122*38fd1498Szrj /* If T begins with any of the partial pathnames listed in d->vpathv,
123*38fd1498Szrj then advance T to point beyond that pathname. */
124*38fd1498Szrj static const char *
apply_vpath(struct deps * d,const char * t)125*38fd1498Szrj apply_vpath (struct deps *d, const char *t)
126*38fd1498Szrj {
127*38fd1498Szrj if (d->vpathv)
128*38fd1498Szrj {
129*38fd1498Szrj unsigned int i;
130*38fd1498Szrj for (i = 0; i < d->nvpaths; i++)
131*38fd1498Szrj {
132*38fd1498Szrj if (!filename_ncmp (d->vpathv[i], t, d->vpathlv[i]))
133*38fd1498Szrj {
134*38fd1498Szrj const char *p = t + d->vpathlv[i];
135*38fd1498Szrj if (!IS_DIR_SEPARATOR (*p))
136*38fd1498Szrj goto not_this_one;
137*38fd1498Szrj
138*38fd1498Szrj /* Do not simplify $(vpath)/../whatever. ??? Might not
139*38fd1498Szrj be necessary. */
140*38fd1498Szrj if (p[1] == '.' && p[2] == '.' && IS_DIR_SEPARATOR (p[3]))
141*38fd1498Szrj goto not_this_one;
142*38fd1498Szrj
143*38fd1498Szrj /* found a match */
144*38fd1498Szrj t = t + d->vpathlv[i] + 1;
145*38fd1498Szrj break;
146*38fd1498Szrj }
147*38fd1498Szrj not_this_one:;
148*38fd1498Szrj }
149*38fd1498Szrj }
150*38fd1498Szrj
151*38fd1498Szrj /* Remove leading ./ in any case. */
152*38fd1498Szrj while (t[0] == '.' && IS_DIR_SEPARATOR (t[1]))
153*38fd1498Szrj {
154*38fd1498Szrj t += 2;
155*38fd1498Szrj /* If we removed a leading ./, then also remove any /s after the
156*38fd1498Szrj first. */
157*38fd1498Szrj while (IS_DIR_SEPARATOR (t[0]))
158*38fd1498Szrj ++t;
159*38fd1498Szrj }
160*38fd1498Szrj
161*38fd1498Szrj return t;
162*38fd1498Szrj }
163*38fd1498Szrj
164*38fd1498Szrj /* Public routines. */
165*38fd1498Szrj
166*38fd1498Szrj struct deps *
deps_init(void)167*38fd1498Szrj deps_init (void)
168*38fd1498Szrj {
169*38fd1498Szrj return XCNEW (struct deps);
170*38fd1498Szrj }
171*38fd1498Szrj
172*38fd1498Szrj void
deps_free(struct deps * d)173*38fd1498Szrj deps_free (struct deps *d)
174*38fd1498Szrj {
175*38fd1498Szrj unsigned int i;
176*38fd1498Szrj
177*38fd1498Szrj if (d->targetv)
178*38fd1498Szrj {
179*38fd1498Szrj for (i = 0; i < d->ntargets; i++)
180*38fd1498Szrj free ((void *) d->targetv[i]);
181*38fd1498Szrj free (d->targetv);
182*38fd1498Szrj }
183*38fd1498Szrj
184*38fd1498Szrj if (d->depv)
185*38fd1498Szrj {
186*38fd1498Szrj for (i = 0; i < d->ndeps; i++)
187*38fd1498Szrj free ((void *) d->depv[i]);
188*38fd1498Szrj free (d->depv);
189*38fd1498Szrj }
190*38fd1498Szrj
191*38fd1498Szrj if (d->vpathv)
192*38fd1498Szrj {
193*38fd1498Szrj for (i = 0; i < d->nvpaths; i++)
194*38fd1498Szrj free ((void *) d->vpathv[i]);
195*38fd1498Szrj free (d->vpathv);
196*38fd1498Szrj free (d->vpathlv);
197*38fd1498Szrj }
198*38fd1498Szrj
199*38fd1498Szrj free (d);
200*38fd1498Szrj }
201*38fd1498Szrj
202*38fd1498Szrj /* Adds a target T. We make a copy, so it need not be a permanent
203*38fd1498Szrj string. QUOTE is true if the string should be quoted. */
204*38fd1498Szrj void
deps_add_target(struct deps * d,const char * t,int quote)205*38fd1498Szrj deps_add_target (struct deps *d, const char *t, int quote)
206*38fd1498Szrj {
207*38fd1498Szrj if (d->ntargets == d->targets_size)
208*38fd1498Szrj {
209*38fd1498Szrj d->targets_size = d->targets_size * 2 + 4;
210*38fd1498Szrj d->targetv = XRESIZEVEC (const char *, d->targetv, d->targets_size);
211*38fd1498Szrj }
212*38fd1498Szrj
213*38fd1498Szrj t = apply_vpath (d, t);
214*38fd1498Szrj if (quote)
215*38fd1498Szrj t = munge (t); /* Also makes permanent copy. */
216*38fd1498Szrj else
217*38fd1498Szrj t = xstrdup (t);
218*38fd1498Szrj
219*38fd1498Szrj d->targetv[d->ntargets++] = t;
220*38fd1498Szrj }
221*38fd1498Szrj
222*38fd1498Szrj /* Sets the default target if none has been given already. An empty
223*38fd1498Szrj string as the default target in interpreted as stdin. The string
224*38fd1498Szrj is quoted for MAKE. */
225*38fd1498Szrj void
deps_add_default_target(struct deps * d,const char * tgt)226*38fd1498Szrj deps_add_default_target (struct deps *d, const char *tgt)
227*38fd1498Szrj {
228*38fd1498Szrj /* Only if we have no targets. */
229*38fd1498Szrj if (d->ntargets)
230*38fd1498Szrj return;
231*38fd1498Szrj
232*38fd1498Szrj if (tgt[0] == '\0')
233*38fd1498Szrj deps_add_target (d, "-", 1);
234*38fd1498Szrj else
235*38fd1498Szrj {
236*38fd1498Szrj #ifndef TARGET_OBJECT_SUFFIX
237*38fd1498Szrj # define TARGET_OBJECT_SUFFIX ".o"
238*38fd1498Szrj #endif
239*38fd1498Szrj const char *start = lbasename (tgt);
240*38fd1498Szrj char *o = (char *) alloca (strlen (start)
241*38fd1498Szrj + strlen (TARGET_OBJECT_SUFFIX) + 1);
242*38fd1498Szrj char *suffix;
243*38fd1498Szrj
244*38fd1498Szrj strcpy (o, start);
245*38fd1498Szrj
246*38fd1498Szrj suffix = strrchr (o, '.');
247*38fd1498Szrj if (!suffix)
248*38fd1498Szrj suffix = o + strlen (o);
249*38fd1498Szrj strcpy (suffix, TARGET_OBJECT_SUFFIX);
250*38fd1498Szrj
251*38fd1498Szrj deps_add_target (d, o, 1);
252*38fd1498Szrj }
253*38fd1498Szrj }
254*38fd1498Szrj
255*38fd1498Szrj void
deps_add_dep(struct deps * d,const char * t)256*38fd1498Szrj deps_add_dep (struct deps *d, const char *t)
257*38fd1498Szrj {
258*38fd1498Szrj t = munge (apply_vpath (d, t)); /* Also makes permanent copy. */
259*38fd1498Szrj
260*38fd1498Szrj if (d->ndeps == d->deps_size)
261*38fd1498Szrj {
262*38fd1498Szrj d->deps_size = d->deps_size * 2 + 8;
263*38fd1498Szrj d->depv = XRESIZEVEC (const char *, d->depv, d->deps_size);
264*38fd1498Szrj }
265*38fd1498Szrj d->depv[d->ndeps++] = t;
266*38fd1498Szrj }
267*38fd1498Szrj
268*38fd1498Szrj void
deps_add_vpath(struct deps * d,const char * vpath)269*38fd1498Szrj deps_add_vpath (struct deps *d, const char *vpath)
270*38fd1498Szrj {
271*38fd1498Szrj const char *elem, *p;
272*38fd1498Szrj char *copy;
273*38fd1498Szrj size_t len;
274*38fd1498Szrj
275*38fd1498Szrj for (elem = vpath; *elem; elem = p)
276*38fd1498Szrj {
277*38fd1498Szrj for (p = elem; *p && *p != ':'; p++);
278*38fd1498Szrj len = p - elem;
279*38fd1498Szrj copy = XNEWVEC (char, len + 1);
280*38fd1498Szrj memcpy (copy, elem, len);
281*38fd1498Szrj copy[len] = '\0';
282*38fd1498Szrj if (*p == ':')
283*38fd1498Szrj p++;
284*38fd1498Szrj
285*38fd1498Szrj if (d->nvpaths == d->vpaths_size)
286*38fd1498Szrj {
287*38fd1498Szrj d->vpaths_size = d->vpaths_size * 2 + 8;
288*38fd1498Szrj d->vpathv = XRESIZEVEC (const char *, d->vpathv, d->vpaths_size);
289*38fd1498Szrj d->vpathlv = XRESIZEVEC (size_t, d->vpathlv, d->vpaths_size);
290*38fd1498Szrj }
291*38fd1498Szrj d->vpathv[d->nvpaths] = copy;
292*38fd1498Szrj d->vpathlv[d->nvpaths] = len;
293*38fd1498Szrj d->nvpaths++;
294*38fd1498Szrj }
295*38fd1498Szrj }
296*38fd1498Szrj
297*38fd1498Szrj void
deps_write(const struct deps * d,FILE * fp,unsigned int colmax)298*38fd1498Szrj deps_write (const struct deps *d, FILE *fp, unsigned int colmax)
299*38fd1498Szrj {
300*38fd1498Szrj unsigned int size, i, column;
301*38fd1498Szrj
302*38fd1498Szrj column = 0;
303*38fd1498Szrj if (colmax && colmax < 34)
304*38fd1498Szrj colmax = 34;
305*38fd1498Szrj
306*38fd1498Szrj for (i = 0; i < d->ntargets; i++)
307*38fd1498Szrj {
308*38fd1498Szrj size = strlen (d->targetv[i]);
309*38fd1498Szrj column += size;
310*38fd1498Szrj if (i)
311*38fd1498Szrj {
312*38fd1498Szrj if (colmax && column > colmax)
313*38fd1498Szrj {
314*38fd1498Szrj fputs (" \\\n ", fp);
315*38fd1498Szrj column = 1 + size;
316*38fd1498Szrj }
317*38fd1498Szrj else
318*38fd1498Szrj {
319*38fd1498Szrj putc (' ', fp);
320*38fd1498Szrj column++;
321*38fd1498Szrj }
322*38fd1498Szrj }
323*38fd1498Szrj fputs (d->targetv[i], fp);
324*38fd1498Szrj }
325*38fd1498Szrj
326*38fd1498Szrj putc (':', fp);
327*38fd1498Szrj column++;
328*38fd1498Szrj
329*38fd1498Szrj for (i = 0; i < d->ndeps; i++)
330*38fd1498Szrj {
331*38fd1498Szrj size = strlen (d->depv[i]);
332*38fd1498Szrj column += size;
333*38fd1498Szrj if (colmax && column > colmax)
334*38fd1498Szrj {
335*38fd1498Szrj fputs (" \\\n ", fp);
336*38fd1498Szrj column = 1 + size;
337*38fd1498Szrj }
338*38fd1498Szrj else
339*38fd1498Szrj {
340*38fd1498Szrj putc (' ', fp);
341*38fd1498Szrj column++;
342*38fd1498Szrj }
343*38fd1498Szrj fputs (d->depv[i], fp);
344*38fd1498Szrj }
345*38fd1498Szrj putc ('\n', fp);
346*38fd1498Szrj }
347*38fd1498Szrj
348*38fd1498Szrj void
deps_phony_targets(const struct deps * d,FILE * fp)349*38fd1498Szrj deps_phony_targets (const struct deps *d, FILE *fp)
350*38fd1498Szrj {
351*38fd1498Szrj unsigned int i;
352*38fd1498Szrj
353*38fd1498Szrj for (i = 1; i < d->ndeps; i++)
354*38fd1498Szrj {
355*38fd1498Szrj putc ('\n', fp);
356*38fd1498Szrj fputs (d->depv[i], fp);
357*38fd1498Szrj putc (':', fp);
358*38fd1498Szrj putc ('\n', fp);
359*38fd1498Szrj }
360*38fd1498Szrj }
361*38fd1498Szrj
362*38fd1498Szrj /* Write out a deps buffer to a file, in a form that can be read back
363*38fd1498Szrj with deps_restore. Returns nonzero on error, in which case the
364*38fd1498Szrj error number will be in errno. */
365*38fd1498Szrj
366*38fd1498Szrj int
deps_save(struct deps * deps,FILE * f)367*38fd1498Szrj deps_save (struct deps *deps, FILE *f)
368*38fd1498Szrj {
369*38fd1498Szrj unsigned int i;
370*38fd1498Szrj
371*38fd1498Szrj /* The cppreader structure contains makefile dependences. Write out this
372*38fd1498Szrj structure. */
373*38fd1498Szrj
374*38fd1498Szrj /* The number of dependences. */
375*38fd1498Szrj if (fwrite (&deps->ndeps, sizeof (deps->ndeps), 1, f) != 1)
376*38fd1498Szrj return -1;
377*38fd1498Szrj /* The length of each dependence followed by the string. */
378*38fd1498Szrj for (i = 0; i < deps->ndeps; i++)
379*38fd1498Szrj {
380*38fd1498Szrj size_t num_to_write = strlen (deps->depv[i]);
381*38fd1498Szrj if (fwrite (&num_to_write, sizeof (size_t), 1, f) != 1)
382*38fd1498Szrj return -1;
383*38fd1498Szrj if (fwrite (deps->depv[i], num_to_write, 1, f) != 1)
384*38fd1498Szrj return -1;
385*38fd1498Szrj }
386*38fd1498Szrj
387*38fd1498Szrj return 0;
388*38fd1498Szrj }
389*38fd1498Szrj
390*38fd1498Szrj /* Read back dependency information written with deps_save into
391*38fd1498Szrj the deps buffer. The third argument may be NULL, in which case
392*38fd1498Szrj the dependency information is just skipped, or it may be a filename,
393*38fd1498Szrj in which case that filename is skipped. */
394*38fd1498Szrj
395*38fd1498Szrj int
deps_restore(struct deps * deps,FILE * fd,const char * self)396*38fd1498Szrj deps_restore (struct deps *deps, FILE *fd, const char *self)
397*38fd1498Szrj {
398*38fd1498Szrj unsigned int i, count;
399*38fd1498Szrj size_t num_to_read;
400*38fd1498Szrj size_t buf_size = 512;
401*38fd1498Szrj char *buf;
402*38fd1498Szrj
403*38fd1498Szrj /* Number of dependences. */
404*38fd1498Szrj if (fread (&count, 1, sizeof (count), fd) != sizeof (count))
405*38fd1498Szrj return -1;
406*38fd1498Szrj
407*38fd1498Szrj buf = XNEWVEC (char, buf_size);
408*38fd1498Szrj
409*38fd1498Szrj /* The length of each dependence string, followed by the string. */
410*38fd1498Szrj for (i = 0; i < count; i++)
411*38fd1498Szrj {
412*38fd1498Szrj /* Read in # bytes in string. */
413*38fd1498Szrj if (fread (&num_to_read, 1, sizeof (size_t), fd) != sizeof (size_t))
414*38fd1498Szrj {
415*38fd1498Szrj free (buf);
416*38fd1498Szrj return -1;
417*38fd1498Szrj }
418*38fd1498Szrj if (buf_size < num_to_read + 1)
419*38fd1498Szrj {
420*38fd1498Szrj buf_size = num_to_read + 1 + 127;
421*38fd1498Szrj buf = XRESIZEVEC (char, buf, buf_size);
422*38fd1498Szrj }
423*38fd1498Szrj if (fread (buf, 1, num_to_read, fd) != num_to_read)
424*38fd1498Szrj {
425*38fd1498Szrj free (buf);
426*38fd1498Szrj return -1;
427*38fd1498Szrj }
428*38fd1498Szrj buf[num_to_read] = '\0';
429*38fd1498Szrj
430*38fd1498Szrj /* Generate makefile dependencies from .pch if -nopch-deps. */
431*38fd1498Szrj if (self != NULL && filename_cmp (buf, self) != 0)
432*38fd1498Szrj deps_add_dep (deps, buf);
433*38fd1498Szrj }
434*38fd1498Szrj
435*38fd1498Szrj free (buf);
436*38fd1498Szrj return 0;
437*38fd1498Szrj }
438