marc@sun-valley.mit.edu (Marc Ullman) (07/06/89)
B U G R E P O R T
Program: GNU Make
Version: 3.48
Computer: Sun 3
Operating System: SunOS 4.0.1
Reported By: Marc Ullman (marc@sun-valley.stanford.edu)
Date: July 5, 1989
gnumake has a bug with nested variable references when text strings contain
parentheses "(",")" and/or braces "{", "}" as the following example makefile
shows:
SOURCES = src1.c src2.c src3.c
LIB_NAME = testlib.a
LIB_OBJS = ${SOURCES:%.c=$(LIB_NAME)(%.o)}
all :
@echo "$(LIB_OBJS)"
running gnumake on this file produces the following result:
testlib.a(src1.o testlib.a(src2.o testlib.a(src3.o)
^ ^
| |
Missing parentheses
The bug results from an incorrect assumption in the function variable_expand()
in the file variable.c. A fragment of this function is shown below:
/* Is there a variable reference inside the parens or braces?
If so, expand it before expanding the entire reference. */
p1 = index (beg, closeparen);
if (p1 != 0)
p1 = lindex (beg, p1, '$');
if (p1 != 0)
{
/* BEG now points past the opening paren or brace.
Count parens or braces until it is matched. */
int count = 0;
for (p = beg; *p != '\0'; ++p)
{
if (*p == openparen)
++count;
else if (*p == closeparen && --count < 0)
break;
}
/* If count is >= 0, there were unmatched opening parens
or braces, so we go to the simple case of a variable name
such as `$($(a)'. */
if (count < 0)
{
char *name = expand_argument (beg, p);
p1 = concat ("$(", name, ")");
free (name);
name = expand_argument (p1, p1 + strlen (p1));
o = variable_buffer_output (o, name, strlen (name));
free (name);
break;
}
}
The line
p1 = concat ("$(", name, ")");
blindly restores parentheses around the previously evaluated expression
rather than restoring the appropriate delimiters depending on the current
state of the variables "openparen" and "closeparen". A possible fix is shown below:
if (count < 0)
{
char var_start_str[3] = {'$', openparen, '\0' }; /* NEW */
char var_end_str[2] = {closeparen, '\0'}; /* NEW */
char *name = expand_argument (beg, p);
p1 = concat (var_start_str, name, var_end_str); /* REVISED */
free (name);
name = expand_argument (p1, p1 + strlen (p1));
o = variable_buffer_output (o, name, strlen (name));
free (name);
break;
}
With this revision, the sample makefile shown above yields the desirerd result:
testlib.a(src1.o) testlib.a(src2.o) testlib.a(src3.o)