mirror of
https://git.savannah.gnu.org/git/make.git
synced 2024-12-25 05:29:46 +00:00
Add support for the POSIX :::= assignment operator.
POSIX Issue 8 will require a new assignment operator, :::=. This operator behaves similarly to the BSD make := operator: the right-hand side is expanded immediately, but then the value is re-escaped (all '$' are converted to '$$') and the resulting variable is considered a recursive variable: the value is re-expanded on use. * src/variable.h (enum variable_flavor): Add f_expand flavor. * src/variable.c (do_variable_definition): When defining f_expand, post-process the result to re-escape '$' characters. Remove default: to the compiler warns about un-handled enum values. Set recursive values for both f_recursive and f_expand. (parse_variable_definition): Rewrite this method. The previous version was annoying to extend to ':::='. (print_variable): Remove default: so the compiler warns us about un-handled enum values. * src/function.c (func_origin): Remove default: so the compiler warns us about un-handled enum values. * doc/make.texi: Add documentation for :::=. * tests/scripts/variables/define: Add a test for define :::=. * tests/scripts/variables/flavors: Add tests for :::=. * tests/scripts/variables/negative: Add tests for :::=.
This commit is contained in:
parent
c5d4b7b2f2
commit
6c06c547dc
8 changed files with 363 additions and 160 deletions
227
doc/make.texi
227
doc/make.texi
|
@ -258,6 +258,13 @@ How to Use Variables
|
|||
* Suppressing Inheritance:: Suppress inheritance of variables.
|
||||
* Special Variables:: Variables with special meaning or behavior.
|
||||
|
||||
The Two Flavors of Variables
|
||||
|
||||
* Recursive Assignment:: Setting recursively expanded variables.
|
||||
* Simple Assignment:: Setting simply expanded variables.
|
||||
* Immediate Assignment:: Setting immediately expanded variables.
|
||||
* Conditional Assignment:: Assigning variable values conditionally.
|
||||
|
||||
Advanced Features for Reference to Variables
|
||||
|
||||
* Substitution Refs:: Referencing a variable with
|
||||
|
@ -1528,6 +1535,7 @@ Variable definitions are parsed as follows:
|
|||
@var{immediate} ?= @var{deferred}
|
||||
@var{immediate} := @var{immediate}
|
||||
@var{immediate} ::= @var{immediate}
|
||||
@var{immediate} :::= @var{immediate-with-escape}
|
||||
@var{immediate} += @var{deferred} or @var{immediate}
|
||||
@var{immediate} != @var{immediate}
|
||||
|
||||
|
@ -1551,6 +1559,10 @@ define @var{immediate} ::=
|
|||
@var{immediate}
|
||||
endef
|
||||
|
||||
define @var{immediate} :::=
|
||||
@var{immediate-with-escape}
|
||||
endef
|
||||
|
||||
define @var{immediate} +=
|
||||
@var{deferred} or @var{immediate}
|
||||
endef
|
||||
|
@ -1564,6 +1576,11 @@ For the append operator @samp{+=}, the right-hand side is considered
|
|||
immediate if the variable was previously set as a simple variable
|
||||
(@samp{:=} or @samp{::=}), and deferred otherwise.
|
||||
|
||||
For the @var{immediate-with-escape} operator @samp{:::=}, the value on
|
||||
the right-hand side is immediately expanded but then escaped (that is,
|
||||
all instances of @code{$} in the result of the expansion are replaced
|
||||
with @code{$$}).
|
||||
|
||||
For the shell assignment operator @samp{!=}, the right-hand side is
|
||||
evaluated immediately and handed to the shell. The result is stored
|
||||
in the variable named on the left, and that variable is considered a
|
||||
|
@ -5357,10 +5374,20 @@ often improved is automatic variables (@pxref{Automatic Variables}).
|
|||
@cindex recursively expanded variables
|
||||
@cindex variables, recursively expanded
|
||||
|
||||
There are two ways that a variable in GNU @code{make} can have a value;
|
||||
we call them the two @dfn{flavors} of variables. The two flavors are
|
||||
distinguished in how they are defined and in what they do when expanded.
|
||||
There are different ways that a variable in GNU @code{make} can get a value;
|
||||
we call them the @dfn{flavors} of variables. The flavors are distinguished in
|
||||
how they handle the values they are assigned in the makefile, and in how those
|
||||
values are managed when the variable is later used and expanded.
|
||||
|
||||
@menu
|
||||
* Recursive Assignment:: Setting recursively expanded variables.
|
||||
* Simple Assignment:: Setting simply expanded variables.
|
||||
* Immediate Assignment:: Setting immediately expanded variables.
|
||||
* Conditional Assignment:: Assigning variable values conditionally.
|
||||
@end menu
|
||||
|
||||
@node Recursive Assignment, Simple Assignment, Flavors, Flavors
|
||||
@subsection Recursively Expanded Variable Assignment
|
||||
@cindex =
|
||||
The first flavor of variable is a @dfn{recursively expanded} variable.
|
||||
Variables of this sort are defined by lines using @samp{=}
|
||||
|
@ -5417,7 +5444,9 @@ expanded. This makes @code{make} run slower; worse, it causes the
|
|||
because you cannot easily control when they are called, or even how many
|
||||
times.
|
||||
|
||||
To avoid all the problems and inconveniences of recursively expanded
|
||||
@node Simple Assignment, Immediate Assignment, Recursive Assignment, Flavors
|
||||
@subsection Simply Expanded Variable Assignment
|
||||
To avoid the problems and inconveniences of recursively expanded
|
||||
variables, there is another flavor: simply expanded variables.
|
||||
|
||||
@cindex simply expanded variables
|
||||
|
@ -5427,34 +5456,35 @@ variables, there is another flavor: simply expanded variables.
|
|||
@dfn{Simply expanded variables} are defined by lines using @samp{:=}
|
||||
or @samp{::=} (@pxref{Setting, ,Setting Variables}). Both forms are
|
||||
equivalent in GNU @code{make}; however only the @samp{::=} form is
|
||||
described by the POSIX standard (support for @samp{::=} was added to
|
||||
the POSIX standard in 2012, so older versions of @code{make} won't
|
||||
accept this form either).
|
||||
described by the POSIX standard (support for @samp{::=} is added to
|
||||
the POSIX standard for POSIX Issue 8).
|
||||
|
||||
The value of a simply expanded variable is scanned
|
||||
once and for all, expanding any references to other variables and
|
||||
functions, when the variable is defined. The actual value of the simply
|
||||
expanded variable is the result of expanding the text that you write.
|
||||
It does not contain any references to other variables; it contains their
|
||||
values @emph{as of the time this variable was defined}. Therefore,
|
||||
The value of a simply expanded variable is scanned once, expanding any
|
||||
references to other variables and functions, when the variable is
|
||||
defined. Once that expansion is complete the value of the variable is
|
||||
never expanded again: when the variable is used the value is copied
|
||||
verbatim as the expansion. If the value contained variable references
|
||||
the result of the expansion will contain their values @emph{as of the
|
||||
time this variable was defined}. Therefore,
|
||||
|
||||
@example
|
||||
@group
|
||||
x := foo
|
||||
y := $(x) bar
|
||||
x := later
|
||||
@end group
|
||||
@end example
|
||||
|
||||
@noindent
|
||||
is equivalent to
|
||||
|
||||
@example
|
||||
@group
|
||||
y := foo bar
|
||||
x := later
|
||||
@end group
|
||||
@end example
|
||||
|
||||
When a simply expanded variable is referenced, its value is substituted
|
||||
verbatim.
|
||||
|
||||
Here is a somewhat more complicated example, illustrating the use of
|
||||
@samp{:=} in conjunction with the @code{shell} function.
|
||||
(@xref{Shell Function, , The @code{shell} Function}.) This example
|
||||
|
@ -5503,8 +5533,10 @@ this means you can include leading spaces in a variable value by
|
|||
protecting them with variable references, like this:
|
||||
|
||||
@example
|
||||
@group
|
||||
nullstring :=
|
||||
space := $(nullstring) # end of the line
|
||||
@end group
|
||||
@end example
|
||||
|
||||
@noindent
|
||||
|
@ -5528,6 +5560,84 @@ Here the value of the variable @code{dir} is @w{@samp{/foo/bar }}
|
|||
(with four trailing spaces), which was probably not the intention.
|
||||
(Imagine something like @w{@samp{$(dir)/file}} with this definition!)
|
||||
|
||||
@node Immediate Assignment, Conditional Assignment, Simple Assignment, Flavors
|
||||
@subsection Immediately Expanded Variable Assignment
|
||||
@cindex immediate variable assignment
|
||||
@cindex variables, immediate assignment
|
||||
@cindex :::=
|
||||
|
||||
Another form of assignment allows for immediate expansion, but unlike simple
|
||||
assignment the resulting variable is recursive: it will be re-expanded again
|
||||
on every use. In order to avoid unexpected results, after the value is
|
||||
immediately expanded it will automatically be quoted: all instances of
|
||||
@code{$} in the value after expansion will be converted into @code{$$}. This
|
||||
type of assignment uses the @samp{:::=} operator. For example,
|
||||
|
||||
@example
|
||||
@group
|
||||
var = first
|
||||
OUT :::= $(var)
|
||||
var = second
|
||||
@end group
|
||||
@end example
|
||||
|
||||
@noindent
|
||||
results in the @code{OUT} variable containing the text @samp{first}, while here:
|
||||
|
||||
@example
|
||||
@group
|
||||
var = one$$two
|
||||
OUT :::= $(var)
|
||||
var = three$$four
|
||||
@end group
|
||||
@end example
|
||||
|
||||
@noindent
|
||||
results in the @code{OUT} variable containing the text @samp{one$$two}. The
|
||||
value is expanded when the variable is assigned, so the result is the
|
||||
expansion of the first value of @code{var}, @samp{one$two}; then the value is
|
||||
re-escaped before the assignment is complete giving the final result of
|
||||
@samp{one$$two}.
|
||||
|
||||
The variable @code{OUT} is thereafter considered a recursive variable, so it
|
||||
will be re-expanded when it is used.
|
||||
|
||||
This seems functionally equivalent to the @samp{:=} / @samp{::=} operators,
|
||||
but there are a few differences:
|
||||
|
||||
First, after assignment the variable is a normal recursive variable; when you
|
||||
append to it with @samp{+=} the value on the right-hand side is not expanded
|
||||
immediately. If you prefer the @samp{+=} operator to expand the right-hand
|
||||
side immediately you should use the @samp{:=} / @samp{::=} assignment instead.
|
||||
|
||||
Second, these variables are slightly less efficient than simply expanded
|
||||
variables since they do need to be re-expanded when they are used, rather than
|
||||
merely copied. However since all variable references are escaped this
|
||||
expansion simply un-escapes the value, it won't expand any variables or run
|
||||
any functions.
|
||||
|
||||
Here is another example:
|
||||
|
||||
@example
|
||||
@group
|
||||
var = one$$two
|
||||
OUT :::= $(var)
|
||||
OUT += $(var)
|
||||
var = three$$four
|
||||
@end group
|
||||
@end example
|
||||
|
||||
After this, the value of @code{OUT} is the text @samp{one$$two $(var)}. When
|
||||
this variable is used it will be expanded and the result will be
|
||||
@samp{one$two three$four}.
|
||||
|
||||
This style of assignment is equivalent to the traditional BSD @code{make}
|
||||
@samp{:=} operator; as you can see it works slightly differently than the GNU
|
||||
@code{make} @samp{:=} operator. The @code{:::=} operator is added to the
|
||||
POSIX specification in Issue 8 to provide portability.
|
||||
|
||||
@node Conditional Assignment, , Immediate Assignment, Flavors
|
||||
@subsection Conditional Variable Assignment
|
||||
@cindex conditional variable assignment
|
||||
@cindex variables, conditional assignment
|
||||
@cindex ?=
|
||||
|
@ -5632,12 +5742,9 @@ sets @samp{bar} to @samp{a.c b.c l.a c.c}.
|
|||
@cindex @code{$}, in variable name
|
||||
@cindex dollar sign (@code{$}), in variable name
|
||||
|
||||
Computed variable names are a complicated concept needed only for
|
||||
sophisticated makefile programming. For most purposes you need not
|
||||
consider them, except to know that making a variable with a dollar sign
|
||||
in its name might have strange results. However, if you are the type
|
||||
that wants to understand everything, or you are actually interested in
|
||||
what they do, read on.
|
||||
Computed variable names are an advanced concept, very useful in more
|
||||
sophisticated makefile programming. In simple situations you need not
|
||||
consider them, but they can be extremely useful.
|
||||
|
||||
Variables may be referenced inside the name of a variable. This is
|
||||
called a @dfn{computed variable name} or a @dfn{nested variable
|
||||
|
@ -5685,10 +5792,9 @@ a := $($(x))
|
|||
defines @code{a} as @samp{Hello}: @samp{$($(x))} becomes @samp{$($(y))}
|
||||
which becomes @samp{$(z)} which becomes @samp{Hello}.
|
||||
|
||||
Nested variable references can also contain modified references and
|
||||
function invocations (@pxref{Functions, ,Functions for Transforming Text}),
|
||||
just like any other reference.
|
||||
For example, using the @code{subst} function
|
||||
Nested variable references can also contain modified references and function
|
||||
invocations (@pxref{Functions, ,Functions for Transforming Text}), just like
|
||||
any other reference. For example, using the @code{subst} function
|
||||
(@pxref{Text Functions, ,Functions for String Substitution and Analysis}):
|
||||
|
||||
@example
|
||||
|
@ -5857,27 +5963,30 @@ Several variables have constant initial values.
|
|||
@cindex =
|
||||
@cindex :=
|
||||
@cindex ::=
|
||||
@cindex :::=
|
||||
@cindex ?=
|
||||
@cindex !=
|
||||
|
||||
To set a variable from the makefile, write a line starting with the
|
||||
variable name followed by @samp{=}, @samp{:=}, or @samp{::=}. Whatever
|
||||
follows the @samp{=}, @samp{:=}, or @samp{::=} on the line becomes the
|
||||
value. For example,
|
||||
To set a variable from the makefile, write a line starting with the variable
|
||||
name followed by one of the assignment operators @samp{=}, @samp{:=},
|
||||
@samp{::=}, or @samp{:::=}. Whatever follows the operator and any initial
|
||||
whitespace on the line becomes the value. For example,
|
||||
|
||||
@example
|
||||
objects = main.o foo.o bar.o utils.o
|
||||
@end example
|
||||
|
||||
@noindent
|
||||
defines a variable named @code{objects}. Whitespace around the variable
|
||||
name and immediately after the @samp{=} is ignored.
|
||||
defines a variable named @code{objects} to contain the value @samp{main.o
|
||||
foo.o bar.o utils.o}. Whitespace around the variable name and immediately
|
||||
after the @samp{=} is ignored.
|
||||
|
||||
Variables defined with @samp{=} are @dfn{recursively expanded}
|
||||
variables. Variables defined with @samp{:=} or @samp{::=} are
|
||||
@dfn{simply expanded} variables; these definitions can contain
|
||||
variable references which will be expanded before the definition is
|
||||
made. @xref{Flavors, ,The Two Flavors of Variables}.
|
||||
Variables defined with @samp{=} are @dfn{recursively expanded} variables.
|
||||
Variables defined with @samp{:=} or @samp{::=} are @dfn{simply expanded}
|
||||
variables; these definitions can contain variable references which will be
|
||||
expanded before the definition is made. Variables defined with @samp{:::=}
|
||||
are @dfn{immediately expanded} variables. The different assignment operators
|
||||
are described in @xref{Flavors, ,The Two Flavors of Variables}.
|
||||
|
||||
The variable name may contain function and variable references, which
|
||||
are expanded when the line is read to find the actual variable name to use.
|
||||
|
@ -5987,13 +6096,12 @@ originally. @xref{Flavors, ,The Two Flavors of Variables}, for an
|
|||
explanation of the two flavors of variables.
|
||||
|
||||
When you add to a variable's value with @samp{+=}, @code{make} acts
|
||||
essentially as if you had included the extra text in the initial
|
||||
definition of the variable. If you defined it first with @samp{:=} or
|
||||
@samp{::=}, making it a simply-expanded variable, @samp{+=} adds to
|
||||
that simply-expanded definition, and expands the new text before
|
||||
appending it to the old value just as @samp{:=} does (see
|
||||
@ref{Setting, ,Setting Variables}, for a full explanation of
|
||||
@samp{:=} or @samp{::=}). In fact,
|
||||
essentially as if you had included the extra text in the initial definition of
|
||||
the variable. If you defined it first with @samp{:=} or @samp{::=}, making it
|
||||
a simply-expanded variable, @samp{+=} adds to that simply-expanded definition,
|
||||
and expands the new text before appending it to the old value just as
|
||||
@samp{:=} does (see @ref{Setting, ,Setting Variables}, for a full explanation
|
||||
of @samp{:=} or @samp{::=}). In fact,
|
||||
|
||||
@example
|
||||
variable := value
|
||||
|
@ -6010,15 +6118,9 @@ variable := $(variable) more
|
|||
@end example
|
||||
|
||||
On the other hand, when you use @samp{+=} with a variable that you defined
|
||||
first to be recursively-expanded using plain @samp{=}, @code{make} does
|
||||
something a bit different. Recall that when you define a
|
||||
recursively-expanded variable, @code{make} does not expand the value you set
|
||||
for variable and function references immediately. Instead it stores the text
|
||||
verbatim, and saves these variable and function references to be expanded
|
||||
later, when you refer to the new variable (@pxref{Flavors, ,The Two Flavors
|
||||
of Variables}). When you use @samp{+=} on a recursively-expanded variable,
|
||||
it is this unexpanded text to which @code{make} appends the new text you
|
||||
specify.
|
||||
first to be recursively-expanded using plain @samp{=} or @samp{:::=},
|
||||
@code{make} appends the un-expanded text to the existing value, whatever it
|
||||
is. This means that
|
||||
|
||||
@example
|
||||
@group
|
||||
|
@ -6247,6 +6349,7 @@ In such situations you may want to use the @code{undefine} directive to
|
|||
make a variable appear as if it was never set. For example:
|
||||
|
||||
@example
|
||||
@group
|
||||
foo := foo
|
||||
bar = bar
|
||||
|
||||
|
@ -6255,6 +6358,7 @@ undefine bar
|
|||
|
||||
$(info $(origin foo))
|
||||
$(info $(flavor bar))
|
||||
@end group
|
||||
@end example
|
||||
|
||||
This example will print ``undefined'' for both variables.
|
||||
|
@ -6342,14 +6446,14 @@ variable only.
|
|||
Multiple @var{target} values create a target-specific variable value for
|
||||
each member of the target list individually.
|
||||
|
||||
The @var{variable-assignment} can be any valid form of assignment;
|
||||
recursive (@samp{=}), simple (@samp{:=} or @samp{::=}), appending
|
||||
(@samp{+=}), or conditional (@samp{?=}). All variables that appear
|
||||
within the @var{variable-assignment} are evaluated within the context
|
||||
of the target: thus, any previously-defined target-specific variable
|
||||
values will be in effect. Note that this variable is actually
|
||||
distinct from any ``global'' value: the two variables do not have to
|
||||
have the same flavor (recursive vs.@: simple).
|
||||
The @var{variable-assignment} can be any valid form of assignment; recursive
|
||||
(@samp{=}), simple (@samp{:=} or @samp{::=}), immediate (@samp{::=}),
|
||||
appending (@samp{+=}), or conditional (@samp{?=}). All variables that appear
|
||||
within the @var{variable-assignment} are evaluated within the context of the
|
||||
target: thus, any previously-defined target-specific variable values will be
|
||||
in effect. Note that this variable is actually distinct from any ``global''
|
||||
value: the two variables do not have to have the same flavor (recursive vs.@:
|
||||
simple).
|
||||
|
||||
Target-specific variables have the same priority as any other makefile
|
||||
variable. Variables provided on the command line (and in the
|
||||
|
@ -12362,6 +12466,7 @@ Here is a summary of the directives GNU @code{make} recognizes:
|
|||
@itemx define @var{variable} =
|
||||
@itemx define @var{variable} :=
|
||||
@itemx define @var{variable} ::=
|
||||
@itemx define @var{variable} :::=
|
||||
@itemx define @var{variable} +=
|
||||
@itemx define @var{variable} ?=
|
||||
@itemx endef
|
||||
|
|
|
@ -465,7 +465,6 @@ func_origin (char *o, char **argv, const char *funcname UNUSED)
|
|||
else
|
||||
switch (v->origin)
|
||||
{
|
||||
default:
|
||||
case o_invalid:
|
||||
abort ();
|
||||
break;
|
||||
|
|
|
@ -407,7 +407,7 @@ extern int unixy_shell;
|
|||
#define NONE_SET(_v,_m) (! ANY_SET ((_v),(_m)))
|
||||
|
||||
#define MAP_NUL 0x0001
|
||||
#define MAP_BLANK 0x0002
|
||||
#define MAP_BLANK 0x0002 /* space, TAB */
|
||||
#define MAP_NEWLINE 0x0004
|
||||
#define MAP_COMMENT 0x0008
|
||||
#define MAP_SEMI 0x0010
|
||||
|
|
223
src/variable.c
223
src/variable.c
|
@ -1194,7 +1194,6 @@ do_variable_definition (const floc *flocp, const char *varname,
|
|||
|
||||
switch (flavor)
|
||||
{
|
||||
default:
|
||||
case f_bogus:
|
||||
/* Should not be possible. */
|
||||
abort ();
|
||||
|
@ -1205,6 +1204,25 @@ do_variable_definition (const floc *flocp, const char *varname,
|
|||
target-specific variable. */
|
||||
p = alloc_value = allocated_variable_expand (value);
|
||||
break;
|
||||
case f_expand:
|
||||
{
|
||||
/* A POSIX "var :::= value" assignment. Expand the value, then it
|
||||
becomes a recursive variable. After expansion convert all '$'
|
||||
tokens to '$$' to resolve to '$' when recursively expanded. */
|
||||
char *t = allocated_variable_expand (value);
|
||||
char *np = alloc_value = xmalloc (strlen (t) * 2 + 1);
|
||||
p = t;
|
||||
while (p[0] != '\0')
|
||||
{
|
||||
if (p[0] == '$')
|
||||
*(np++) = '$';
|
||||
*(np++) = *(p++);
|
||||
}
|
||||
*np = '\0';
|
||||
p = alloc_value;
|
||||
free (t);
|
||||
break;
|
||||
}
|
||||
case f_shell:
|
||||
{
|
||||
/* A shell definition "var != value". Expand value, pass it to
|
||||
|
@ -1440,8 +1458,8 @@ do_variable_definition (const floc *flocp, const char *varname,
|
|||
invoked in places where we want to define globally visible variables,
|
||||
make sure we define this variable in the global set. */
|
||||
|
||||
v = define_variable_in_set (varname, strlen (varname), p,
|
||||
origin, flavor == f_recursive,
|
||||
v = define_variable_in_set (varname, strlen (varname), p, origin,
|
||||
flavor == f_recursive || flavor == f_expand,
|
||||
(target_var
|
||||
? current_variable_set_list->set : NULL),
|
||||
flocp);
|
||||
|
@ -1456,7 +1474,7 @@ do_variable_definition (const floc *flocp, const char *varname,
|
|||
/* Parse P (a null-terminated string) as a variable definition.
|
||||
|
||||
If it is not a variable definition, return NULL and the contents of *VAR
|
||||
are undefined, except NAME is set to the first non-space character or NIL.
|
||||
are undefined, except NAME points to the first non-space character or EOS.
|
||||
|
||||
If it is a variable definition, return a pointer to the char after the
|
||||
assignment token and set the following fields (only) of *VAR:
|
||||
|
@ -1468,15 +1486,17 @@ do_variable_definition (const floc *flocp, const char *varname,
|
|||
*/
|
||||
|
||||
char *
|
||||
parse_variable_definition (const char *p, struct variable *var)
|
||||
parse_variable_definition (const char *str, struct variable *var)
|
||||
{
|
||||
int wspace = 0;
|
||||
const char *e = NULL;
|
||||
const char *p = str;
|
||||
const char *end = NULL;
|
||||
|
||||
NEXT_TOKEN (p);
|
||||
var->name = (char *)p;
|
||||
var->length = 0;
|
||||
|
||||
/* Walk through STR until we find a valid assignment operator. Each time
|
||||
through this loop P points to the next character to consider. */
|
||||
while (1)
|
||||
{
|
||||
int c = *p++;
|
||||
|
@ -1485,26 +1505,112 @@ parse_variable_definition (const char *p, struct variable *var)
|
|||
if (STOP_SET (c, MAP_COMMENT|MAP_NUL))
|
||||
return NULL;
|
||||
|
||||
if (ISBLANK (c))
|
||||
{
|
||||
/* Variable names can't contain spaces so if this is the second set
|
||||
of spaces we know it's not a variable assignment. */
|
||||
if (end)
|
||||
return NULL;
|
||||
end = p - 1;
|
||||
NEXT_TOKEN (p);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If we found = we're done! */
|
||||
if (c == '=')
|
||||
{
|
||||
if (!end)
|
||||
end = p - 1;
|
||||
var->flavor = f_recursive;
|
||||
break;
|
||||
}
|
||||
|
||||
if (c == ':')
|
||||
{
|
||||
if (!end)
|
||||
end = p - 1;
|
||||
|
||||
/* We need to distinguish :=, ::=, and :::=, and : outside of an
|
||||
assignment (which means this is not a variable definition). */
|
||||
c = *p++;
|
||||
if (c == '=')
|
||||
{
|
||||
var->flavor = f_simple;
|
||||
break;
|
||||
}
|
||||
if (c == ':')
|
||||
{
|
||||
c = *p++;
|
||||
if (c == '=')
|
||||
{
|
||||
var->flavor = f_simple;
|
||||
break;
|
||||
}
|
||||
if (c == ':' && *p++ == '=')
|
||||
{
|
||||
var->flavor = f_expand;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* See if it's one of the other two-byte operators. */
|
||||
if (*p == '=')
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '+':
|
||||
var->flavor = f_append;
|
||||
break;
|
||||
case '?':
|
||||
var->flavor = f_conditional;
|
||||
break;
|
||||
case '!':
|
||||
var->flavor = f_shell;
|
||||
break;
|
||||
default:
|
||||
goto other;
|
||||
}
|
||||
|
||||
if (!end)
|
||||
end = p - 1;
|
||||
++p;
|
||||
break;
|
||||
}
|
||||
|
||||
other:
|
||||
/* We found a char which is not part of an assignment operator.
|
||||
If we've seen whitespace, then we know this is not a variable
|
||||
assignment since variable names cannot contain whitespace. */
|
||||
if (end)
|
||||
return NULL;
|
||||
|
||||
if (c == '$')
|
||||
{
|
||||
/* This begins a variable expansion reference. Make sure we don't
|
||||
treat chars inside the reference as assignment tokens. */
|
||||
/* Skip any variable reference, to ensure we don't treat chars
|
||||
inside the reference as assignment operators. */
|
||||
char closeparen;
|
||||
unsigned int count;
|
||||
|
||||
c = *p++;
|
||||
if (c == '(')
|
||||
closeparen = ')';
|
||||
else if (c == '{')
|
||||
closeparen = '}';
|
||||
else if (c == '\0')
|
||||
return NULL;
|
||||
else
|
||||
/* '$$' or '$X'. Either way, nothing special to do here. */
|
||||
continue;
|
||||
switch (c)
|
||||
{
|
||||
case '(':
|
||||
closeparen = ')';
|
||||
break;
|
||||
case '{':
|
||||
closeparen = '}';
|
||||
break;
|
||||
case '\0':
|
||||
return NULL;
|
||||
default:
|
||||
/* '$$' or '$X': skip it. */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* P now points past the opening paren or brace.
|
||||
Count parens or braces until it is matched. */
|
||||
/* P now points past the opening paren or brace. Count parens or
|
||||
braces until we find the closing paren/brace. */
|
||||
for (count = 1; *p != '\0'; ++p)
|
||||
{
|
||||
if (*p == closeparen && --count == 0)
|
||||
|
@ -1515,82 +1621,12 @@ parse_variable_definition (const char *p, struct variable *var)
|
|||
if (*p == c)
|
||||
++count;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If we find whitespace skip it, and remember we found it. */
|
||||
if (ISBLANK (c))
|
||||
{
|
||||
wspace = 1;
|
||||
e = p - 1;
|
||||
NEXT_TOKEN (p);
|
||||
c = *p;
|
||||
if (c == '\0')
|
||||
return NULL;
|
||||
++p;
|
||||
}
|
||||
|
||||
|
||||
if (c == '=')
|
||||
{
|
||||
var->flavor = f_recursive;
|
||||
if (! e)
|
||||
e = p - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Match assignment variants (:=, +=, ?=, !=) */
|
||||
if (*p == '=')
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case ':':
|
||||
var->flavor = f_simple;
|
||||
break;
|
||||
case '+':
|
||||
var->flavor = f_append;
|
||||
break;
|
||||
case '?':
|
||||
var->flavor = f_conditional;
|
||||
break;
|
||||
case '!':
|
||||
var->flavor = f_shell;
|
||||
break;
|
||||
default:
|
||||
/* If we skipped whitespace, non-assignments means no var. */
|
||||
if (wspace)
|
||||
return NULL;
|
||||
|
||||
/* Might be assignment, or might be $= or #=. Check. */
|
||||
continue;
|
||||
}
|
||||
if (! e)
|
||||
e = p - 1;
|
||||
++p;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check for POSIX ::= syntax */
|
||||
if (c == ':')
|
||||
{
|
||||
/* A colon other than :=/::= is not a variable defn. */
|
||||
if (*p != ':' || p[1] != '=')
|
||||
return NULL;
|
||||
|
||||
/* POSIX allows ::= to be the same as GNU make's := */
|
||||
var->flavor = f_simple;
|
||||
if (! e)
|
||||
e = p - 1;
|
||||
p += 2;
|
||||
break;
|
||||
}
|
||||
|
||||
/* If we skipped whitespace, non-assignments means no var. */
|
||||
if (wspace)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
var->length = (unsigned int) (e - var->name);
|
||||
/* We found a valid variable assignment: END points to the char after the
|
||||
end of the variable name and P points to the char after the =. */
|
||||
var->length = (unsigned int) (end - var->name);
|
||||
var->value = next_token (p);
|
||||
return (char *)p;
|
||||
}
|
||||
|
@ -1690,7 +1726,6 @@ print_variable (const void *item, void *arg)
|
|||
origin = _("'override' directive");
|
||||
break;
|
||||
case o_invalid:
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
fputs ("# ", stdout);
|
||||
|
|
|
@ -35,6 +35,7 @@ enum variable_flavor
|
|||
f_bogus, /* Bogus (error) */
|
||||
f_simple, /* Simple definition (:= or ::=) */
|
||||
f_recursive, /* Recursive definition (=) */
|
||||
f_expand, /* POSIX :::= assignment */
|
||||
f_append, /* Appending definition (+=) */
|
||||
f_conditional, /* Conditional definition (?=) */
|
||||
f_shell, /* Shell assignment (!=) */
|
||||
|
|
|
@ -61,7 +61,7 @@ all: ; $(multi)
|
|||
|
||||
# TEST 1a: Various new-style define/endef, with no spaces
|
||||
|
||||
run_make_test('
|
||||
run_make_test(q!
|
||||
FOO = foo
|
||||
|
||||
define multi=
|
||||
|
@ -77,6 +77,10 @@ define posix::=
|
|||
@echo $(FOO)
|
||||
endef
|
||||
|
||||
define posixbsd:::=
|
||||
@echo '$(FOO)$$bar'
|
||||
endef
|
||||
|
||||
append = @echo a
|
||||
|
||||
define append+=
|
||||
|
@ -97,10 +101,11 @@ FOO = there
|
|||
all: ; $(multi)
|
||||
$(simple)
|
||||
$(posix)
|
||||
$(posixbsd)
|
||||
$(append)
|
||||
$(cond)
|
||||
',
|
||||
'', "echo hi\nhi\nthere\nfoo\nfoo\na\nb\nfirst\n");
|
||||
!,
|
||||
'', "echo hi\nhi\nthere\nfoo\nfoo\nfoo\$bar\na\nb\nfirst\n");
|
||||
|
||||
# TEST 2: define in true section of conditional (containing conditional)
|
||||
|
||||
|
|
|
@ -153,4 +153,48 @@ dep: ; @: $(info recur=/$(recur)/ simple=/$(simple)/)
|
|||
!,
|
||||
'', "recur=/onetwothree/ simple=/fourfivesix/\n");
|
||||
|
||||
# Test POSIX :::=
|
||||
# This creates a recursive variable, but it expands the RHS first. Any
|
||||
# variable escapes ('$$') are preserved so that this recursive variable can be
|
||||
# expanded again without changing its contents.
|
||||
run_make_test('
|
||||
bar = Goodbye
|
||||
foo :::= $(bar)
|
||||
bar = ${ugh}
|
||||
ugh = Hello
|
||||
all: ; @echo $(foo)
|
||||
',
|
||||
'', "Goodbye");
|
||||
|
||||
# POSIX :::= no spaces
|
||||
run_make_test(q!
|
||||
bar = Goodbye
|
||||
foo:::=$(bar)
|
||||
bar = ${ugh}
|
||||
ugh = Hello
|
||||
all: ; @echo $(foo)
|
||||
!,
|
||||
'', "Goodbye");
|
||||
|
||||
# Variable escapes ('$$') are preserved.
|
||||
run_make_test(q!
|
||||
bar = Good$$bye
|
||||
foo :::= $(bar) $$what
|
||||
bar = ${ugh}
|
||||
ugh = Hello
|
||||
all: ; @echo '$(foo)'
|
||||
!,
|
||||
'', 'Good$bye $what');
|
||||
|
||||
# Append works as expected
|
||||
run_make_test(q!
|
||||
bar = Good$$bye
|
||||
foo :::= $(bar)
|
||||
foo += $$what $(bar)
|
||||
bar = ${ugh}
|
||||
ugh = Hello
|
||||
all: ; @echo '$(foo)'
|
||||
!,
|
||||
'', 'Good$bye $what Hello');
|
||||
|
||||
1;
|
||||
|
|
|
@ -43,4 +43,18 @@ run_make_test(undef,
|
|||
'#MAKEFILE#:4: *** unterminated variable reference. Stop.',
|
||||
512);
|
||||
|
||||
# Whitespace not allowed in variable names
|
||||
run_make_test('x y =', '',
|
||||
'#MAKEFILE#:1: *** missing separator. Stop.', 512);
|
||||
|
||||
run_make_test('x y=', '',
|
||||
'#MAKEFILE#:1: *** missing separator. Stop.', 512);
|
||||
|
||||
# In theory an empty variable should be ignored, but during parsing it's a
|
||||
# real token and so this fails. I'm not 100% sure if this is right or not.
|
||||
|
||||
run_make_test('x $X=', '',
|
||||
'#MAKEFILE#:1: *** missing separator. Stop.', 512);
|
||||
|
||||
|
||||
1;
|
||||
|
|
Loading…
Reference in a new issue