Commit d7b6aee8 by Nathan Sidwell Committed by Nathan Sidwell

[libcpp] Reimplement mkdeps data structures

https://gcc.gnu.org/ml/gcc-patches/2019-05/msg00293.html
	* include/mkdeps.h (deps_write): Add PHONY arg.
	(deps_phony_targets): Delete.
	* init.c (cpp_finish): Just call deps_write.
	* mkdeps.c (struct mkdeps): Add local vector class.  Reimplement
	vector handling.
	(munge): Munge to static buffer.
	(apply_vpath): Adjust vector handling.
	(deps_init, deps_free): Use new, delete.
	(deps_add_target): Do not munge here.  Record quoting low water mark.
	(deps_add_dep): Do not munge here.
	(deps_add_vpath): Adjust vector handling.
	(make_write_name): New.  Munge on demand here.
	(make_write_vec): New.
	(deps_phony_targets): Delete.
	(make_write): New.
	(deps_write): Forward to deps_Write.
	(deps_save, deps_restore): Adjust vector handling.

From-SVN: r270943
parent 7664eeb7
2019-05-07 Nathan Sidwell <nathan@acm.org>
* include/mkdeps.h (deps_write): Add PHONY arg.
(deps_phony_targets): Delete.
* init.c (cpp_finish): Just call deps_write.
* mkdeps.c (struct mkdeps): Add local vector class. Reimplement
vector handling.
(munge): Munge to static buffer.
(apply_vpath): Adjust vector handling.
(deps_init, deps_free): Use new, delete.
(deps_add_target): Do not munge here. Record quoting low water mark.
(deps_add_dep): Do not munge here.
(deps_add_vpath): Adjust vector handling.
(make_write_name): New. Munge on demand here.
(make_write_vec): New.
(deps_phony_targets): Delete.
(make_write): New.
(deps_write): Forward to deps_Write.
(deps_save, deps_restore): Adjust vector handling.
2019-05-06 Nathan Sidwell <nathan@acm.org> 2019-05-06 Nathan Sidwell <nathan@acm.org>
* include/mkdeps.h: Rename struct deps to struct mkdeps. * include/mkdeps.h: Rename struct deps to struct mkdeps.
......
...@@ -57,7 +57,7 @@ extern void deps_add_dep (struct mkdeps *, const char *); ...@@ -57,7 +57,7 @@ extern void deps_add_dep (struct mkdeps *, const char *);
/* Write out a deps buffer to a specified file. The third argument /* Write out a deps buffer to a specified file. The third argument
is the number of columns to word-wrap at (0 means don't wrap). */ is the number of columns to word-wrap at (0 means don't wrap). */
extern void deps_write (const struct mkdeps *, FILE *, unsigned int); extern void deps_write (const struct mkdeps *, FILE *, bool, unsigned int);
/* Write out a deps buffer to a file, in a form that can be read back /* 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 with deps_restore. Returns nonzero on error, in which case the
...@@ -70,10 +70,4 @@ extern int deps_save (struct mkdeps *, FILE *); ...@@ -70,10 +70,4 @@ extern int deps_save (struct mkdeps *, FILE *);
in which case that filename is skipped. */ in which case that filename is skipped. */
extern int deps_restore (struct mkdeps *, FILE *, const char *); extern int deps_restore (struct mkdeps *, FILE *, const char *);
/* For each dependency *except the first*, emit a dummy rule for that
file, causing it to depend on nothing. This is used to work around
the intermediate-file deletion misfeature in Make, in some
automatic dependency schemes. */
extern void deps_phony_targets (const struct mkdeps *, FILE *);
#endif /* ! LIBCPP_MKDEPS_H */ #endif /* ! LIBCPP_MKDEPS_H */
...@@ -764,14 +764,9 @@ cpp_finish (cpp_reader *pfile, FILE *deps_stream) ...@@ -764,14 +764,9 @@ cpp_finish (cpp_reader *pfile, FILE *deps_stream)
while (pfile->buffer) while (pfile->buffer)
_cpp_pop_buffer (pfile); _cpp_pop_buffer (pfile);
if (CPP_OPTION (pfile, deps.style) != DEPS_NONE if (CPP_OPTION (pfile, deps.style) != DEPS_NONE && deps_stream)
&& deps_stream) deps_write (pfile->deps, deps_stream,
{ CPP_OPTION (pfile, deps.phony_targets), 72);
deps_write (pfile->deps, deps_stream, 72);
if (CPP_OPTION (pfile, deps.phony_targets))
deps_phony_targets (pfile->deps, deps_stream);
}
/* Report on headers that could use multiple include guards. */ /* Report on headers that could use multiple include guards. */
if (CPP_OPTION (pfile, print_include_names)) if (CPP_OPTION (pfile, print_include_names))
......
...@@ -24,99 +24,157 @@ along with this program; see the file COPYING3. If not see ...@@ -24,99 +24,157 @@ along with this program; see the file COPYING3. If not see
#include "system.h" #include "system.h"
#include "mkdeps.h" #include "mkdeps.h"
/* Not set up to just include std::vector et al, here's a simple
implementation. */
/* Keep this structure local to this file, so clients don't find it /* Keep this structure local to this file, so clients don't find it
easy to start making assumptions. */ easy to start making assumptions. */
struct mkdeps struct mkdeps
{ {
const char **targetv; public:
unsigned int ntargets; /* number of slots actually occupied */ /* T has trivial cctor & dtor. */
unsigned int targets_size; /* amt of allocated space - in words */ template <typename T>
class vec
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) private:
T *ary;
unsigned num;
unsigned alloc;
public:
vec ()
: ary (NULL), num (0), alloc (0)
{}
~vec ()
{ {
case ' ': XDELETEVEC (ary);
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 '$': public:
/* '$' is quoted by doubling it. */ unsigned size () const
len++; {
break; return num;
}
const T &operator[] (unsigned ix) const
{
return ary[ix];
}
void push (const T &elt)
{
if (num == alloc)
{
alloc = alloc ? alloc * 2 : 16;
ary = XRESIZEVEC (T, ary, alloc);
}
ary[num++] = elt;
}
};
struct velt
{
const char *str;
size_t len;
};
case '#': mkdeps ()
/* '#' is quoted with a backslash. */ : quote_lwm (0)
len++; {
break;
} }
~mkdeps ()
{
unsigned int i;
for (i = targets.size (); i--;)
free (const_cast <char *> (targets[i]));
for (i = deps.size (); i--;)
free (const_cast <char *> (deps[i]));
for (i = vpath.size (); i--;)
XDELETEVEC (vpath[i].str);
} }
/* Now we know how big to make the buffer. */ public:
buffer = XNEWVEC (char, len + 1); vec<const char *> targets;
vec<const char *> deps;
vec<velt> vpath;
public:
unsigned short quote_lwm;
};
/* Apply Make quoting to STR, TRAIL etc. 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.) */
for (p = filename, dst = buffer; *p; p++, dst++) static const char *
munge (const char *str, const char *trail = NULL, ...)
{
static unsigned alloc;
static char *buf;
unsigned dst = 0;
va_list args;
if (trail)
va_start (args, trail);
for (bool first = true; str; first = false)
{ {
switch (*p) unsigned slashes = 0;
char c;
for (const char *probe = str; (c = *probe++);)
{ {
case ' ': if (alloc < dst + 4 + slashes)
case '\t': {
for (q = p - 1; filename <= q && *q == '\\'; q--) alloc = alloc * 2 + 32;
*dst++ = '\\'; buf = XRESIZEVEC (char, buf, alloc);
*dst++ = '\\'; }
switch (c)
{
case '\\':
slashes++;
break; break;
case '$': case '$':
*dst++ = '$'; buf[dst++] = '$';
break; goto def;
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. */
while (slashes--)
buf[dst++] = '\\';
/* FALLTHROUGH */
case '#': case '#':
*dst++ = '\\'; case ':':
break; buf[dst++] = '\\';
/* FALLTHROUGH */
default: default:
/* nothing */; def:
slashes = 0;
break;
} }
*dst = *p;
buf[dst++] = c;
}
if (first)
str = trail;
else
str = va_arg (args, const char *);
} }
if (trail)
va_end (args);
*dst = '\0'; buf[dst] = 0;
return buffer; return buf;
} }
/* If T begins with any of the partial pathnames listed in d->vpathv, /* If T begins with any of the partial pathnames listed in d->vpathv,
...@@ -124,14 +182,12 @@ munge (const char *filename) ...@@ -124,14 +182,12 @@ munge (const char *filename)
static const char * static const char *
apply_vpath (struct mkdeps *d, const char *t) apply_vpath (struct mkdeps *d, const char *t)
{ {
if (d->vpathv) if (unsigned len = d->vpath.size ())
{ for (unsigned i = len; i--;)
unsigned int i;
for (i = 0; i < d->nvpaths; i++)
{ {
if (!filename_ncmp (d->vpathv[i], t, d->vpathlv[i])) if (!filename_ncmp (d->vpath[i].str, t, d->vpath[i].len))
{ {
const char *p = t + d->vpathlv[i]; const char *p = t + d->vpath[i].len;
if (!IS_DIR_SEPARATOR (*p)) if (!IS_DIR_SEPARATOR (*p))
goto not_this_one; goto not_this_one;
...@@ -141,12 +197,11 @@ apply_vpath (struct mkdeps *d, const char *t) ...@@ -141,12 +197,11 @@ apply_vpath (struct mkdeps *d, const char *t)
goto not_this_one; goto not_this_one;
/* found a match */ /* found a match */
t = t + d->vpathlv[i] + 1; t = t + d->vpath[i].len + 1;
break; break;
} }
not_this_one:; not_this_one:;
} }
}
/* Remove leading ./ in any case. */ /* Remove leading ./ in any case. */
while (t[0] == '.' && IS_DIR_SEPARATOR (t[1])) while (t[0] == '.' && IS_DIR_SEPARATOR (t[1]))
...@@ -166,37 +221,13 @@ apply_vpath (struct mkdeps *d, const char *t) ...@@ -166,37 +221,13 @@ apply_vpath (struct mkdeps *d, const char *t)
struct mkdeps * struct mkdeps *
deps_init (void) deps_init (void)
{ {
return XCNEW (struct mkdeps); return new mkdeps ();
} }
void void
deps_free (struct mkdeps *d) deps_free (struct mkdeps *d)
{ {
unsigned int i; delete d;
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 /* Adds a target T. We make a copy, so it need not be a permanent
...@@ -204,19 +235,14 @@ deps_free (struct mkdeps *d) ...@@ -204,19 +235,14 @@ deps_free (struct mkdeps *d)
void void
deps_add_target (struct mkdeps *d, const char *t, int quote) deps_add_target (struct mkdeps *d, const char *t, int quote)
{ {
if (d->ntargets == d->targets_size) t = apply_vpath (d, t);
if (!quote)
{ {
d->targets_size = d->targets_size * 2 + 4; gcc_assert (d->quote_lwm == d->targets.size ());
d->targetv = XRESIZEVEC (const char *, d->targetv, d->targets_size); d->quote_lwm++;
} }
t = apply_vpath (d, t); d->targets.push (xstrdup (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 /* Sets the default target if none has been given already. An empty
...@@ -226,7 +252,7 @@ void ...@@ -226,7 +252,7 @@ void
deps_add_default_target (struct mkdeps *d, const char *tgt) deps_add_default_target (struct mkdeps *d, const char *tgt)
{ {
/* Only if we have no targets. */ /* Only if we have no targets. */
if (d->ntargets) if (d->targets.size ())
return; return;
if (tgt[0] == '\0') if (tgt[0] == '\0')
...@@ -255,108 +281,104 @@ deps_add_default_target (struct mkdeps *d, const char *tgt) ...@@ -255,108 +281,104 @@ deps_add_default_target (struct mkdeps *d, const char *tgt)
void void
deps_add_dep (struct mkdeps *d, const char *t) deps_add_dep (struct mkdeps *d, const char *t)
{ {
t = munge (apply_vpath (d, t)); /* Also makes permanent copy. */ t = apply_vpath (d, t);
if (d->ndeps == d->deps_size) d->deps.push (xstrdup (t));
{
d->deps_size = d->deps_size * 2 + 8;
d->depv = XRESIZEVEC (const char *, d->depv, d->deps_size);
}
d->depv[d->ndeps++] = t;
} }
void void
deps_add_vpath (struct mkdeps *d, const char *vpath) deps_add_vpath (struct mkdeps *d, const char *vpath)
{ {
const char *elem, *p; const char *elem, *p;
char *copy;
size_t len;
for (elem = vpath; *elem; elem = p) for (elem = vpath; *elem; elem = p)
{ {
for (p = elem; *p && *p != ':'; p++); for (p = elem; *p && *p != ':'; p++)
len = p - elem; continue;
copy = XNEWVEC (char, len + 1); mkdeps::velt elt;
memcpy (copy, elem, len); elt.len = p - elem;
copy[len] = '\0'; char *str = XNEWVEC (char, elt.len + 1);
elt.str = str;
memcpy (str, elem, elt.len);
str[elt.len] = '\0';
if (*p == ':') if (*p == ':')
p++; p++;
if (d->nvpaths == d->vpaths_size) d->vpath.push (elt);
{
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 /* Write NAME, with a leading space to FP, a Makefile. Advance COL as
deps_write (const struct mkdeps *d, FILE *fp, unsigned int colmax) appropriate, wrap at COLMAX, returning new column number. Iff
{ QUOTE apply quoting. Append TRAIL. */
unsigned int size, i, column;
column = 0; static unsigned
if (colmax && colmax < 34) make_write_name (const char *name, FILE *fp, unsigned col, unsigned colmax,
colmax = 34; bool quote = true, const char *trail = NULL)
{
if (quote)
name = munge (name, trail, NULL);
unsigned size = strlen (name);
for (i = 0; i < d->ntargets; i++) if (col)
{
size = strlen (d->targetv[i]);
column += size;
if (i)
{ {
if (colmax && column > colmax) if (colmax && col + size> colmax)
{
fputs (" \\\n ", fp);
column = 1 + size;
}
else
{ {
putc (' ', fp); fputs (" \\\n", fp);
column++; col = 0;
}
} }
fputs (d->targetv[i], fp); col++;
fputs (" ", fp);
} }
putc (':', fp); col += size;
column++; fputs (name, fp);
for (i = 0; i < d->ndeps; i++) return col;
{ }
size = strlen (d->depv[i]);
column += size; /* Write all the names in VEC via make_write_name. */
if (colmax && column > colmax)
{ static unsigned
fputs (" \\\n ", fp); make_write_vec (const mkdeps::vec<const char *> &vec, FILE *fp,
column = 1 + size; unsigned col, unsigned colmax, unsigned quote_lwm = 0,
} const char *trail = NULL)
else {
for (unsigned ix = 0; ix != vec.size (); ix++)
col = make_write_name (vec[ix], fp, col, colmax, ix >= quote_lwm, trail);
return col;
}
/* Write the dependencies to a Makefile. If PHONY is true, add
.PHONY targets for all the dependencies too. */
static void
make_write (const struct mkdeps *d, FILE *fp, bool phony, unsigned int colmax)
{
unsigned column = 0;
if (colmax && colmax < 34)
colmax = 34;
if (d->deps.size ())
{ {
putc (' ', fp); column = make_write_vec (d->targets, fp, 0, colmax, d->quote_lwm);
fputs (":", fp);
column++; column++;
column = make_write_vec (d->deps, fp, column, colmax);
fputs ("\n", fp);
if (phony)
for (unsigned i = 1; i < d->deps.size (); i++)
fprintf (fp, "%s:\n", munge (d->deps[i]));
} }
fputs (d->depv[i], fp);
}
putc ('\n', fp);
} }
/* Write out dependencies according to the selected format (which is
only Make at the moment). */
void void
deps_phony_targets (const struct mkdeps *d, FILE *fp) deps_write (const struct mkdeps *d, FILE *fp, bool phony, unsigned int colmax)
{ {
unsigned int i; make_write (d, fp, phony, colmax);
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 /* Write out a deps buffer to a file, in a form that can be read back
...@@ -367,20 +389,23 @@ int ...@@ -367,20 +389,23 @@ int
deps_save (struct mkdeps *deps, FILE *f) deps_save (struct mkdeps *deps, FILE *f)
{ {
unsigned int i; unsigned int i;
size_t size;
/* The cppreader structure contains makefile dependences. Write out this /* The cppreader structure contains makefile dependences. Write out this
structure. */ structure. */
/* The number of dependences. */ /* The number of dependences. */
if (fwrite (&deps->ndeps, sizeof (deps->ndeps), 1, f) != 1) size = deps->deps.size ();
if (fwrite (&size, sizeof (size), 1, f) != 1)
return -1; return -1;
/* The length of each dependence followed by the string. */ /* The length of each dependence followed by the string. */
for (i = 0; i < deps->ndeps; i++) for (i = 0; i < deps->deps.size (); i++)
{ {
size_t num_to_write = strlen (deps->depv[i]); size = strlen (deps->deps[i]);
if (fwrite (&num_to_write, sizeof (size_t), 1, f) != 1) if (fwrite (&size, sizeof (size), 1, f) != 1)
return -1; return -1;
if (fwrite (deps->depv[i], num_to_write, 1, f) != 1) if (fwrite (deps->deps[i], size, 1, f) != 1)
return -1; return -1;
} }
...@@ -388,50 +413,45 @@ deps_save (struct mkdeps *deps, FILE *f) ...@@ -388,50 +413,45 @@ deps_save (struct mkdeps *deps, FILE *f)
} }
/* Read back dependency information written with deps_save into /* Read back dependency information written with deps_save into
the deps buffer. The third argument may be NULL, in which case the deps sizefer. The third argument may be NULL, in which case
the dependency information is just skipped, or it may be a filename, the dependency information is just skipped, or it may be a filename,
in which case that filename is skipped. */ in which case that filename is skipped. */
int int
deps_restore (struct mkdeps *deps, FILE *fd, const char *self) deps_restore (struct mkdeps *deps, FILE *fd, const char *self)
{ {
unsigned int i, count; size_t size;
size_t num_to_read; char *buf = NULL;
size_t buf_size = 512; size_t buf_size = 0;
char *buf;
/* Number of dependences. */ /* Number of dependences. */
if (fread (&count, 1, sizeof (count), fd) != sizeof (count)) if (fread (&size, sizeof (size), 1, fd) != 1)
return -1; return -1;
buf = XNEWVEC (char, buf_size);
/* The length of each dependence string, followed by the string. */ /* The length of each dependence string, followed by the string. */
for (i = 0; i < count; i++) for (unsigned i = size; i--;)
{ {
/* Read in # bytes in string. */ /* Read in # bytes in string. */
if (fread (&num_to_read, 1, sizeof (size_t), fd) != sizeof (size_t)) if (fread (&size, sizeof (size), 1, fd) != 1)
{
free (buf);
return -1; return -1;
}
if (buf_size < num_to_read + 1) if (size >= buf_size)
{ {
buf_size = num_to_read + 1 + 127; buf_size = size + 512;
buf = XRESIZEVEC (char, buf, buf_size); buf = XRESIZEVEC (char, buf, buf_size);
} }
if (fread (buf, 1, num_to_read, fd) != num_to_read) if (fread (buf, 1, size, fd) != size)
{ {
free (buf); XDELETEVEC (buf);
return -1; return -1;
} }
buf[num_to_read] = '\0'; buf[size] = 0;
/* Generate makefile dependencies from .pch if -nopch-deps. */ /* Generate makefile dependencies from .pch if -nopch-deps. */
if (self != NULL && filename_cmp (buf, self) != 0) if (self != NULL && filename_cmp (buf, self) != 0)
deps_add_dep (deps, buf); deps_add_dep (deps, buf);
} }
free (buf); XDELETEVEC (buf);
return 0; return 0;
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment