Some bug fixes and document updates.

This commit is contained in:
Paul Smith 2001-01-21 06:49:11 +00:00
parent e5324a8c6a
commit 8f2b1e2c7c
9 changed files with 214 additions and 145 deletions

View file

@ -1,3 +1,37 @@
2001-01-17 Paul D. Smith <psmith@gnu.org>
* variable.c (lookup_variable) [VMS]: When getting values from the
environment, allocate enough space for the _value_ plus escapes,
not enough space for the name plus escapes :-/.
Reported by John Fowler <jfowler@nyx.net>.
* remake.c (f_mtime): Removed the "***" prefix from the mod time
warnings that make generates, so it doesn't look like an error.
Reported by Karl Berry <karl@gnu.org>.
Fix for PR/2020: Rework appended target-specific variables. I'm
fairly confident this algorithm is finally correct.
* expand.c (allocated_variable_append): Rewrite. Instead of
expanding each appended variable then adding all the expanded
strings together, we append all the unexpanded values going up
through the variable set contexts, then expand the final result.
This behaves just like non-target-specific appended variable
values, while the old way didn't in various corner cases.
(variable_append): New function: recursively append the unexpanded
value of a variable, walking from the outermost variable scope to
the innermost.
* variable.c (lookup_variable): Remove the code that looked up the
variable set list if the found variable was "append". We don't
need this anymore.
(lookup_variable_in_set): Make this non-static so we can use it
elsewhere.
(try_variable_definition): Use lookup_variable_in_set() rather
than faking out current_variable_set_list by hand (cleanup).
* variable.h: Add a prototype for the now non-static
lookup_variable_in_set().
2000-11-17 Paul D. Smith <psmith@gnu.org>
* remake.c (f_mtime) [WINDOWS32]: On various advice, I changed the
@ -11,6 +45,12 @@
the need for len or lastlen at all. Problem description with
sample code chages provided by Chris Faylor <cgf@redhat.com>.
2000-10-24 Paul D. Smith <psmith@gnu.org>
* gettext.c (SWAP): Declare this with the prototype, otherwise
some systems don't work (non-32-bit? Reported for Cray T3E).
Reported by Thorstein Thorsteinsson <thor@signe.teokem.lu.se>.
2000-10-05 Paul D. Smith <psmith@gnu.org>
* acinclude.m4 (AM_LC_MESSAGES): Remove undefined macro

View file

@ -1,4 +1,5 @@
set make=gnumake
+if not exist config.h copy config.h.W32 config.h
cd w32\subproc
echo "Creating the subproc library"
%ComSpec% /c build.bat

View file

@ -92,7 +92,7 @@ initialize_variable_output ()
/* Recursively expand V. The returned string is malloc'd. */
static char *allocated_variable_append PARAMS ((struct variable *v));
static char *allocated_variable_append PARAMS ((const struct variable *v));
char *
recursively_expand (v)
@ -469,52 +469,72 @@ variable_expand_for_file (line, file)
return result;
}
/* Like allocated_variable_expand, but we first expand this variable in the
context of the next variable set, then we append the expanded value. */
/* Like allocated_variable_expand, but for += target-specific variables.
First recursively construct the variable value from its appended parts in
any upper variable sets. Then expand the resulting value. */
static char *
variable_append (name, length, set)
const char *name;
unsigned int length;
const struct variable_set_list *set;
{
const struct variable *v;
char *buf = 0;
/* If there's nothing left to check, return the empty buffer. */
if (!set)
return initialize_variable_output ();
/* Try to find the variable in this variable set. */
v = lookup_variable_in_set (name, length, set->set);
/* If there isn't one, look to see if there's one in a set above us. */
if (!v)
return variable_append (name, length, set->next);
/* If this variable type is append, first get any upper values.
If not, initialize the buffer. */
if (v->append)
buf = variable_append (name, length, set->next);
else
buf = initialize_variable_output ();
/* Append this value to the buffer, and return it.
If we already have a value, first add a space. */
if (buf > variable_buffer)
buf = variable_buffer_output (buf, " ", 1);
return variable_buffer_output (buf, v->value, strlen (v->value));
}
static char *
allocated_variable_append (v)
struct variable *v;
const struct variable *v;
{
struct variable_set_list *save;
int len = strlen (v->name);
char *var = alloca (len + 4);
char *value;
char *val, *retval;
/* Construct the appended variable value. */
char *obuf = variable_buffer;
unsigned int olen = variable_buffer_length;
variable_buffer = 0;
assert(current_variable_set_list->next != 0);
save = current_variable_set_list;
current_variable_set_list = current_variable_set_list->next;
var[0] = '$';
var[1] = '(';
strcpy (&var[2], v->name);
var[len+2] = ')';
var[len+3] = '\0';
value = variable_expand_for_file (var, 0);
current_variable_set_list = save;
value += strlen (value);
value = variable_buffer_output (value, " ", 1);
value = variable_expand_string (value, v->value, (long)-1);
value = variable_buffer;
#if 0
/* Waste a little memory and save time. */
value = xrealloc (value, strlen (value))
#endif
val = variable_append (v->name, strlen (v->name), current_variable_set_list);
variable_buffer_output (val, "", 1);
val = variable_buffer;
variable_buffer = obuf;
variable_buffer_length = olen;
return value;
/* Now expand it and return that. */
retval = allocated_variable_expand (val);
free (val);
return retval;
}
/* Like variable_expand_for_file, but the returned string is malloc'd.

View file

@ -786,9 +786,14 @@ struct string_desc
#else
static nls_uint32 SWAP PARAMS ((nls_uint32 i));
/* Apparently on some (non-32-bit?) systems it's important to use the right
prototype. Reported for a CRAY T3E. */
static inline nls_uint32
SWAP (i)
nls_uint32 i;
#if __STDC__
SWAP (nls_uint32 i)
#else
SWAP (i) nls_uint32 i;
#endif
{
return (i << 24) | ((i & 0xff00) << 8) | ((i >> 8) & 0xff00) | (i >> 24);
}

View file

@ -1,4 +1,4 @@
\input texinfo @c -*- Texinfo -*-
input texinfo @c -*- Texinfo -*-
@c %**start of header
@setfilename make.info
@settitle GNU @code{make}
@ -2465,9 +2465,9 @@ chance of @command{make} incorrectly concluding that a file is up to
date. Unfortunately, these hosts provide no way to set a high
resolution file time stamp, so commands like @samp{cp -p} that
explicitly set a file's time stamp must discard its subsecond part. If
a file is created by such a command, you should list it as a dependency
of @code{.LOW_RESOLUTION_TIME} so that @command{make} does not
mistakenly conclude that the file is out of date. For example:
a file is created by such a command, you should list it as a
prerequisite of @code{.LOW_RESOLUTION_TIME} so that @command{make} does
not mistakenly conclude that the file is out of date. For example:
@example
@group
@ -2485,7 +2485,7 @@ is at the start of the same second that @file{src}'s time stamp is in.
Due to a limitation of the archive format, archive member time stamps
are always low resolution. You need not list archive members as
dependencies of @code{.LOW_RESOLUTION_TIME}, as @command{make} does this
prerequisites of @code{.LOW_RESOLUTION_TIME}, as @command{make} does this
automatically.
@findex .SILENT
@ -2682,7 +2682,7 @@ be @emph{analogous}, but not necessarily @emph{identical}.
Here is the syntax of a static pattern rule:
@example
@var{targets} @dots{}: @var{target-pattern}: @var{dep-patterns} @dots{}
@var{targets} @dots{}: @var{target-pattern}: @var{prereq-patterns} @dots{}
@var{commands}
@dots{}
@end example
@ -2695,11 +2695,11 @@ Names}).
@cindex target pattern, static (not implicit)
@cindex stem
The @var{target-pattern} and @var{dep-patterns} say how to compute the
The @var{target-pattern} and @var{prereq-patterns} say how to compute the
prerequisites of each target. Each target is matched against the
@var{target-pattern} to extract a part of the target name, called the
@dfn{stem}. This stem is substituted into each of the @var{dep-patterns}
to make the prerequisite names (one from each @var{dep-pattern}).
@dfn{stem}. This stem is substituted into each of the @var{prereq-patterns}
to make the prerequisite names (one from each @var{prereq-pattern}).
Each pattern normally contains the character @samp{%} just once. When the
@var{target-pattern} matches a target, the @samp{%} can match any part of
@ -2838,10 +2838,12 @@ to precisely the targets specified.
ordinary rules when the same target appears in more than one rule.
When a target appears in multiple rules, all the rules must be the same
type: all ordinary, or all double-colon. If they are double-colon, each of
them is independent of the others. Each double-colon rule's commands are
executed if the target is older than any prerequisites of that rule. This
can result in executing none, any, or all of the double-colon rules.
type: all ordinary, or all double-colon. If they are double-colon, each
of them is independent of the others. Each double-colon rule's commands
are executed if the target is older than any prerequisites of that rule.
If there are no prerequisites for that rule, its commands are always
executed (even if the target already exists). This can result in
executing none, any, or all of the double-colon rules.
Double-colon rules with the same target are in fact completely separate
from one another. Each double-colon rule is processed individually, just
@ -5481,7 +5483,9 @@ Finds whitespace-separated words in @var{text} that match
@var{pattern} may contain a @samp{%} which acts as a wildcard,
matching any number of any characters within a word. If
@var{replacement} also contains a @samp{%}, the @samp{%} is replaced
by the text that matched the @samp{%} in @var{pattern}.@refill
by the text that matched the @samp{%} in @var{pattern}. Only the first
@samp{%} in the @var{pattern} and @var{replacement} is treated this
way; any subsequent @samp{%} is unchanged.@refill
@cindex @code{%}, quoting in @code{patsubst}
@cindex @code{%}, quoting with @code{\} (backslash)
@ -8125,7 +8129,7 @@ appending @samp{D} or @samp{F}, respectively. These variants are
semi-obsolete in GNU @code{make} since the functions @code{dir} and
@code{notdir} can be used to get a similar effect (@pxref{File Name
Functions, , Functions for File Names}). Note, however, that the
@samp{F} variants all omit the trailing slash which always appears in
@samp{D} variants all omit the trailing slash which always appears in
the output of the @code{dir} function. Here is a table of the variants:
@table @samp

View file

@ -1190,14 +1190,14 @@ f_mtime (file, search)
if (adjusted_now < adjusted_mtime)
{
#ifdef NO_FLOAT
error (NILF, _("*** Warning: File `%s' has modification time in the future"),
error (NILF, _("Warning: File `%s' has modification time in the future"),
file->name);
#else
double from_now =
(FILE_TIMESTAMP_S (mtime) - FILE_TIMESTAMP_S (now)
+ ((FILE_TIMESTAMP_NS (mtime) - FILE_TIMESTAMP_NS (now))
/ 1e9));
error (NILF, _("*** Warning: File `%s' has modification time %.2g s in the future"),
error (NILF, _("Warning: File `%s' has modification time %.2g s in the future"),
file->name, from_now);
#endif
clock_skew_detected = 1;

View file

@ -170,5 +170,29 @@ close(MAKEFILE);
$answer = "; ok\n";
&compare_output($answer, &get_logfile(1));
# Test #12
# PR/2020: More hassles with += target-specific vars. I _really_ think
# I nailed it this time :-/.
$makefile5 = &get_tmpfile;
open(MAKEFILE, "> $makefile5");
print MAKEFILE <<'EOF';
.PHONY: a
BLAH := foo
COMMAND = echo $(BLAH)
a: ; @$(COMMAND)
a: BLAH := bar
a: COMMAND += snafu $(BLAH)
EOF
close(MAKEFILE);
&run_make_with_options("$makefile5", "", &get_logfile);
$answer = "bar snafu bar\n";
&compare_output($answer, &get_logfile(1));
1;

View file

@ -45,9 +45,6 @@ static struct variable_set global_variable_set
static struct variable_set_list global_setlist
= { 0, &global_variable_set };
struct variable_set_list *current_variable_set_list = &global_setlist;
static struct variable *lookup_variable_in_set PARAMS ((char *name,
unsigned int length, struct variable_set *set));
/* Implement variables. */
@ -134,23 +131,17 @@ define_variable_in_set (name, length, value, origin, recursive, set, flocp)
/* Lookup a variable whose name is a string starting at NAME
and with LENGTH chars. NAME need not be null-terminated.
Returns address of the `struct variable' containing all info
on the variable, or nil if no such variable is defined.
If we find a variable which is in the process of being expanded,
try to find one further up the set_list chain. If we don't find
one that isn't being expanded, return a pointer to whatever we
_did_ find. */
on the variable, or nil if no such variable is defined. */
struct variable *
lookup_variable (name, length)
char *name;
const char *name;
unsigned int length;
{
register struct variable_set_list *setlist;
struct variable *firstv = 0;
const struct variable_set_list *setlist;
register unsigned int i;
register unsigned int rawhash = 0;
unsigned int i;
unsigned int rawhash = 0;
for (i = 0; i < length; ++i)
HASH (rawhash, name[i]);
@ -158,88 +149,74 @@ lookup_variable (name, length)
for (setlist = current_variable_set_list;
setlist != 0; setlist = setlist->next)
{
register struct variable_set *set = setlist->set;
register unsigned int hashval = rawhash % set->buckets;
register struct variable *v;
const struct variable_set *set = setlist->set;
unsigned int hashval = rawhash % set->buckets;
struct variable *v;
/* Look through this set list. */
/* Look through this set list; return it if found. */
for (v = set->table[hashval]; v != 0; v = v->next)
if (*v->name == *name
&& strneq (v->name + 1, name + 1, length - 1)
&& v->name[length] == '\0')
break;
/* If we didn't find anything, go to the next set list. */
if (!v)
continue;
/* If it's not being expanded already, we're done. */
if (!v->expanding)
return v;
/* It is, so try to find another one. If this is the first one we've
seen, keep a pointer in case we don't find anything else. */
if (!firstv)
firstv = v;
return v;
}
#ifdef VMS
/* since we don't read envp[] on startup, try to get the
variable via getenv() here. */
if (!firstv)
{
char *vname = alloca (length + 1);
char *value;
strncpy (vname, name, length);
vname[length] = 0;
value = getenv (vname);
if (value != 0)
{
char *sptr;
int scnt;
{
char *vname = alloca (length + 1);
char *value;
strncpy (vname, name, length);
vname[length] = 0;
value = getenv (vname);
if (value != 0)
{
char *sptr;
int scnt;
sptr = value;
scnt = 0;
sptr = value;
scnt = 0;
while ((sptr = strchr (sptr, '$')))
{
scnt++;
sptr++;
}
while ((sptr = strchr (sptr, '$')))
{
scnt++;
sptr++;
}
if (scnt > 0)
{
char *nvalue;
char *nptr;
if (scnt > 0)
{
char *nvalue;
char *nptr;
nvalue = alloca (length + scnt + 1);
sptr = value;
nptr = nvalue;
nvalue = alloca (strlen (value) + scnt + 1);
sptr = value;
nptr = nvalue;
while (*sptr)
{
if (*sptr == '$')
{
*nptr++ = '$';
*nptr++ = '$';
}
else
{
*nptr++ = *sptr;
}
sptr++;
}
while (*sptr)
{
if (*sptr == '$')
{
*nptr++ = '$';
*nptr++ = '$';
}
else
{
*nptr++ = *sptr;
}
sptr++;
}
return define_variable (vname, length, nvalue, o_env, 1);
return define_variable (vname, length, nvalue, o_env, 1);
}
}
return define_variable (vname, length, value, o_env, 1);
}
}
return define_variable (vname, length, value, o_env, 1);
}
}
#endif /* VMS */
return firstv;
return 0;
}
/* Lookup a variable whose name is a string starting at NAME
@ -247,15 +224,15 @@ lookup_variable (name, length)
Returns address of the `struct variable' containing all info
on the variable, or nil if no such variable is defined. */
static struct variable *
struct variable *
lookup_variable_in_set (name, length, set)
char *name;
const char *name;
unsigned int length;
struct variable_set *set;
const struct variable_set *set;
{
register unsigned int i;
register unsigned int hash = 0;
register struct variable *v;
unsigned int i;
unsigned int hash = 0;
struct variable *v;
for (i = 0; i < length; ++i)
HASH (hash, name[i]);
@ -788,7 +765,7 @@ try_variable_definition (flocp, line, origin, target_var)
register char *end;
enum { f_bogus,
f_simple, f_recursive, f_append, f_conditional } flavor = f_bogus;
char *name, *expanded_name, *value, *alloc_value=NULL;
char *name, *expanded_name, *value=0, *alloc_value=NULL;
struct variable *v;
int append = 0;
@ -901,21 +878,16 @@ try_variable_definition (flocp, line, origin, target_var)
break;
case f_append:
{
struct variable_set_list *saved_next = current_variable_set_list->next;
/* If we have += but we're in a target variable context, we want to
append only with other variables in the context of this target. */
if (target_var)
{
append = 1;
current_variable_set_list->next = 0;
v = lookup_variable_in_set (expanded_name, strlen (expanded_name),
current_variable_set_list->set);
}
/* An appending variable definition "var += value".
Extract the old value and append the new one. */
v = lookup_variable (expanded_name, strlen (expanded_name));
current_variable_set_list->next = saved_next;
else
v = lookup_variable (expanded_name, strlen (expanded_name));
if (v == 0)
{

View file

@ -108,7 +108,10 @@ extern void print_variable_set PARAMS ((struct variable_set *set, char *prefix))
extern void merge_variable_set_lists PARAMS ((struct variable_set_list **setlist0, struct variable_set_list *setlist1));
extern struct variable *try_variable_definition PARAMS ((const struct floc *flocp, char *line, enum variable_origin origin, int target_var));
extern struct variable *lookup_variable PARAMS ((char *name, unsigned int length));
extern struct variable *lookup_variable PARAMS ((const char *name, unsigned int length));
extern struct variable *lookup_variable_in_set PARAMS ((const char *name,
unsigned int length,
const struct variable_set *set));
extern struct variable *define_variable_in_set
PARAMS ((char *name, unsigned int length, char *value,