123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438 |
- /* Dependency generator for Makefile fragments.
- Copyright (C) 2000-2015 Free Software Foundation, Inc.
- Contributed by Zack Weinberg, Mar 2000
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 3, or (at your option) any
- later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING3. If not see
- <http://www.gnu.org/licenses/>.
- In other words, you are welcome to use, share and improve this program.
- You are forbidden to forbid anyone else to use, share and improve
- what you give them. Help stamp out software-hoarding! */
- #include "config.h"
- #include "system.h"
- #include "mkdeps.h"
- /* Keep this structure local to this file, so clients don't find it
- easy to start making assumptions. */
- struct deps
- {
- const char **targetv;
- unsigned int ntargets; /* number of slots actually occupied */
- unsigned int targets_size; /* amt of allocated space - in words */
- const char **depv;
- unsigned int ndeps;
- unsigned int deps_size;
- const char **vpathv;
- size_t *vpathlv;
- unsigned int nvpaths;
- unsigned int vpaths_size;
- };
- static const char *munge (const char *);
- /* Given a filename, quote characters in that filename which are
- significant to Make. Note that it's not possible to quote all such
- characters - e.g. \n, %, *, ?, [, \ (in some contexts), and ~ are
- not properly handled. It isn't possible to get this right in any
- current version of Make. (??? Still true? Old comment referred to
- 3.76.1.) */
- static const char *
- munge (const char *filename)
- {
- int len;
- const char *p, *q;
- char *dst, *buffer;
- for (p = filename, len = 0; *p; p++, len++)
- {
- switch (*p)
- {
- case ' ':
- case '\t':
- /* GNU make uses a weird quoting scheme for white space.
- A space or tab preceded by 2N+1 backslashes represents
- N backslashes followed by space; a space or tab
- preceded by 2N backslashes represents N backslashes at
- the end of a file name; and backslashes in other
- contexts should not be doubled. */
- for (q = p - 1; filename <= q && *q == '\\'; q--)
- len++;
- len++;
- break;
- case '$':
- /* '$' is quoted by doubling it. */
- len++;
- break;
- case '#':
- /* '#' is quoted with a backslash. */
- len++;
- break;
- }
- }
- /* Now we know how big to make the buffer. */
- buffer = XNEWVEC (char, len + 1);
- for (p = filename, dst = buffer; *p; p++, dst++)
- {
- switch (*p)
- {
- case ' ':
- case '\t':
- for (q = p - 1; filename <= q && *q == '\\'; q--)
- *dst++ = '\\';
- *dst++ = '\\';
- break;
- case '$':
- *dst++ = '$';
- break;
- case '#':
- *dst++ = '\\';
- break;
- default:
- /* nothing */;
- }
- *dst = *p;
- }
- *dst = '\0';
- return buffer;
- }
- /* If T begins with any of the partial pathnames listed in d->vpathv,
- then advance T to point beyond that pathname. */
- static const char *
- apply_vpath (struct deps *d, const char *t)
- {
- if (d->vpathv)
- {
- unsigned int i;
- for (i = 0; i < d->nvpaths; i++)
- {
- if (!filename_ncmp (d->vpathv[i], t, d->vpathlv[i]))
- {
- const char *p = t + d->vpathlv[i];
- if (!IS_DIR_SEPARATOR (*p))
- goto not_this_one;
- /* Do not simplify $(vpath)/../whatever. ??? Might not
- be necessary. */
- if (p[1] == '.' && p[2] == '.' && IS_DIR_SEPARATOR (p[3]))
- goto not_this_one;
- /* found a match */
- t = t + d->vpathlv[i] + 1;
- break;
- }
- not_this_one:;
- }
- }
- /* Remove leading ./ in any case. */
- while (t[0] == '.' && IS_DIR_SEPARATOR (t[1]))
- {
- t += 2;
- /* If we removed a leading ./, then also remove any /s after the
- first. */
- while (IS_DIR_SEPARATOR (t[0]))
- ++t;
- }
- return t;
- }
- /* Public routines. */
- struct deps *
- deps_init (void)
- {
- return XCNEW (struct deps);
- }
- void
- deps_free (struct deps *d)
- {
- unsigned int i;
- if (d->targetv)
- {
- for (i = 0; i < d->ntargets; i++)
- free ((void *) d->targetv[i]);
- free (d->targetv);
- }
- if (d->depv)
- {
- for (i = 0; i < d->ndeps; i++)
- free ((void *) d->depv[i]);
- free (d->depv);
- }
- if (d->vpathv)
- {
- for (i = 0; i < d->nvpaths; i++)
- free ((void *) d->vpathv[i]);
- free (d->vpathv);
- free (d->vpathlv);
- }
- free (d);
- }
- /* Adds a target T. We make a copy, so it need not be a permanent
- string. QUOTE is true if the string should be quoted. */
- void
- deps_add_target (struct deps *d, const char *t, int quote)
- {
- if (d->ntargets == d->targets_size)
- {
- d->targets_size = d->targets_size * 2 + 4;
- d->targetv = XRESIZEVEC (const char *, d->targetv, d->targets_size);
- }
- t = apply_vpath (d, t);
- if (quote)
- t = munge (t); /* Also makes permanent copy. */
- else
- t = xstrdup (t);
- d->targetv[d->ntargets++] = t;
- }
- /* Sets the default target if none has been given already. An empty
- string as the default target in interpreted as stdin. The string
- is quoted for MAKE. */
- void
- deps_add_default_target (struct deps *d, const char *tgt)
- {
- /* Only if we have no targets. */
- if (d->ntargets)
- return;
- if (tgt[0] == '\0')
- deps_add_target (d, "-", 1);
- else
- {
- #ifndef TARGET_OBJECT_SUFFIX
- # define TARGET_OBJECT_SUFFIX ".o"
- #endif
- const char *start = lbasename (tgt);
- char *o = (char *) alloca (strlen (start)
- + strlen (TARGET_OBJECT_SUFFIX) + 1);
- char *suffix;
- strcpy (o, start);
- suffix = strrchr (o, '.');
- if (!suffix)
- suffix = o + strlen (o);
- strcpy (suffix, TARGET_OBJECT_SUFFIX);
- deps_add_target (d, o, 1);
- }
- }
- void
- deps_add_dep (struct deps *d, const char *t)
- {
- t = munge (apply_vpath (d, t)); /* Also makes permanent copy. */
- if (d->ndeps == d->deps_size)
- {
- d->deps_size = d->deps_size * 2 + 8;
- d->depv = XRESIZEVEC (const char *, d->depv, d->deps_size);
- }
- d->depv[d->ndeps++] = t;
- }
- void
- deps_add_vpath (struct deps *d, const char *vpath)
- {
- const char *elem, *p;
- char *copy;
- size_t len;
- for (elem = vpath; *elem; elem = p)
- {
- for (p = elem; *p && *p != ':'; p++);
- len = p - elem;
- copy = XNEWVEC (char, len + 1);
- memcpy (copy, elem, len);
- copy[len] = '\0';
- if (*p == ':')
- p++;
- if (d->nvpaths == d->vpaths_size)
- {
- d->vpaths_size = d->vpaths_size * 2 + 8;
- d->vpathv = XRESIZEVEC (const char *, d->vpathv, d->vpaths_size);
- d->vpathlv = XRESIZEVEC (size_t, d->vpathlv, d->vpaths_size);
- }
- d->vpathv[d->nvpaths] = copy;
- d->vpathlv[d->nvpaths] = len;
- d->nvpaths++;
- }
- }
- void
- deps_write (const struct deps *d, FILE *fp, unsigned int colmax)
- {
- unsigned int size, i, column;
- column = 0;
- if (colmax && colmax < 34)
- colmax = 34;
- for (i = 0; i < d->ntargets; i++)
- {
- size = strlen (d->targetv[i]);
- column += size;
- if (i)
- {
- if (colmax && column > colmax)
- {
- fputs (" \\\n ", fp);
- column = 1 + size;
- }
- else
- {
- putc (' ', fp);
- column++;
- }
- }
- fputs (d->targetv[i], fp);
- }
- putc (':', fp);
- column++;
- for (i = 0; i < d->ndeps; i++)
- {
- size = strlen (d->depv[i]);
- column += size;
- if (colmax && column > colmax)
- {
- fputs (" \\\n ", fp);
- column = 1 + size;
- }
- else
- {
- putc (' ', fp);
- column++;
- }
- fputs (d->depv[i], fp);
- }
- putc ('\n', fp);
- }
- void
- deps_phony_targets (const struct deps *d, FILE *fp)
- {
- unsigned int i;
- for (i = 1; i < d->ndeps; i++)
- {
- putc ('\n', fp);
- fputs (d->depv[i], fp);
- putc (':', fp);
- putc ('\n', fp);
- }
- }
- /* Write out a deps buffer to a file, in a form that can be read back
- with deps_restore. Returns nonzero on error, in which case the
- error number will be in errno. */
- int
- deps_save (struct deps *deps, FILE *f)
- {
- unsigned int i;
- /* The cppreader structure contains makefile dependences. Write out this
- structure. */
- /* The number of dependences. */
- if (fwrite (&deps->ndeps, sizeof (deps->ndeps), 1, f) != 1)
- return -1;
- /* The length of each dependence followed by the string. */
- for (i = 0; i < deps->ndeps; i++)
- {
- size_t num_to_write = strlen (deps->depv[i]);
- if (fwrite (&num_to_write, sizeof (size_t), 1, f) != 1)
- return -1;
- if (fwrite (deps->depv[i], num_to_write, 1, f) != 1)
- return -1;
- }
- return 0;
- }
- /* Read back dependency information written with deps_save into
- the deps buffer. The third argument may be NULL, in which case
- the dependency information is just skipped, or it may be a filename,
- in which case that filename is skipped. */
- int
- deps_restore (struct deps *deps, FILE *fd, const char *self)
- {
- unsigned int i, count;
- size_t num_to_read;
- size_t buf_size = 512;
- char *buf;
- /* Number of dependences. */
- if (fread (&count, 1, sizeof (count), fd) != sizeof (count))
- return -1;
- buf = XNEWVEC (char, buf_size);
- /* The length of each dependence string, followed by the string. */
- for (i = 0; i < count; i++)
- {
- /* Read in # bytes in string. */
- if (fread (&num_to_read, 1, sizeof (size_t), fd) != sizeof (size_t))
- {
- free (buf);
- return -1;
- }
- if (buf_size < num_to_read + 1)
- {
- buf_size = num_to_read + 1 + 127;
- buf = XRESIZEVEC (char, buf, buf_size);
- }
- if (fread (buf, 1, num_to_read, fd) != num_to_read)
- {
- free (buf);
- return -1;
- }
- buf[num_to_read] = '\0';
- /* Generate makefile dependencies from .pch if -nopch-deps. */
- if (self != NULL && filename_cmp (buf, self) != 0)
- deps_add_dep (deps, buf);
- }
- free (buf);
- return 0;
- }
|