Add support for "::=" simple assignment operator.

The next POSIX standard will define "::=" to have the same behavior
as GNU make's ":=", so add support for this new operator.
This commit is contained in:
Paul Smith 2012-01-30 00:21:57 +00:00
parent fca11f6039
commit ef6461611b
9 changed files with 208 additions and 79 deletions

View File

@ -1,5 +1,17 @@
2012-01-29 Paul Smith <psmith@gnu.org>
* variable.c (parse_variable_definition): New POSIX assignment ::=
Take a struct variable to return more information after parsing.
(assign_variable_definition): New parse_variable_definition() call.
* variable.h: New declaration of parse_variable_definition().
* read.c (do_define): New parse_variable_definition() call.
(parse_var_assignment): Ditto.
(get_next_mword): Parse ::= as a variable assignment.
* doc/make.texi (Flavors): Describe the new ::= syntax.
* NEWS: Mention the ::= operator.
* variable.h (struct variable): Rearrange elts to reduce struct size.
* function.c (func_file): Create a new function, $(file ...)
* doc/make.texi (File Function): Document the $(file ..) function.
* NEWS: Announce it.

6
NEWS
View File

@ -38,6 +38,12 @@ http://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=101&set
interpreted as shell assignment. Change your assignment to add whitespace
between the "!" and "=": "variable! = value"
* New feature: "::=" simple assignment operator as defined by POSIX in 2012.
This operator has identical functionality to ":=" in GNU make, but will be
portable to any implementation of make conforming to a sufficiently new
version of POSIX (see http://austingroupbugs.net/view.php?id=330). It is
not necessary to define the .POSIX target to access this operator.
* New feature: GNU Guile integration
This version of GNU make can be compiled with GNU Guile integration.
GNU Guile serves as an embedded extension language for make.

View File

@ -1399,6 +1399,7 @@ Variable definitions are parsed as follows:
@var{immediate} = @var{deferred}
@var{immediate} ?= @var{deferred}
@var{immediate} := @var{immediate}
@var{immediate} ::= @var{immediate}
@var{immediate} += @var{deferred} or @var{immediate}
@var{immediate} != @var{immediate}
@ -1418,6 +1419,10 @@ define @var{immediate} :=
@var{immediate}
endef
define @var{immediate} ::=
@var{immediate}
endef
define @var{immediate} +=
@var{deferred} or @var{immediate}
endef
@ -1429,7 +1434,7 @@ endef
For the append operator, @samp{+=}, the right-hand side is considered
immediate if the variable was previously set as a simple variable
(@samp{:=}), and deferred otherwise.
(@samp{:=} or @samp{::=}), and deferred otherwise.
For the shell assignment operator, @samp{!=}, the right-hand side is
evaluated immediately and handed to the shell. The result is stored in the
@ -4967,9 +4972,9 @@ all:;echo $(foo)
will echo @samp{Huh?}: @samp{$(foo)} expands to @samp{$(bar)} which
expands to @samp{$(ugh)} which finally expands to @samp{Huh?}.@refill
This flavor of variable is the only sort supported by other versions of
@code{make}. It has its advantages and its disadvantages. An advantage
(most would say) is that:
This flavor of variable is the only sort supported by most other
versions of @code{make}. It has its advantages and its disadvantages.
An advantage (most would say) is that:
@example
CFLAGS = $(include_dirs) -O
@ -5005,8 +5010,14 @@ variables, there is another flavor: simply expanded variables.
@cindex simply expanded variables
@cindex variables, simply expanded
@cindex :=
@cindex ::=
@dfn{Simply expanded variables} are defined by lines using @samp{:=}
(@pxref{Setting, ,Setting Variables}).
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).
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
@ -5425,12 +5436,14 @@ Several variables have constant initial values.
@cindex variables, setting
@cindex =
@cindex :=
@cindex ::=
@cindex ?=
@cindex !=
To set a variable from the makefile, write a line starting with the
variable name followed by @samp{=} or @samp{:=}. Whatever follows the
@samp{=} or @samp{:=} on the line becomes the value. For example,
variable name followed by @samp{=} @samp{:=}, or @samp{::=}. Whatever
follows the @samp{=}, @samp{:=}, or @samp{::=} on the line becomes the
value. For example,
@example
objects = main.o foo.o bar.o utils.o
@ -5440,10 +5453,11 @@ objects = main.o foo.o bar.o utils.o
defines a variable named @code{objects}. 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{:=} 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. @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.
@ -5553,12 +5567,12 @@ 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{:=},
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{:=}).
In fact,
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
@ -5898,13 +5912,13 @@ 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{:=}), 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).
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).
Target-specific variables have the same priority as any other makefile
variable. Variables provided on the command line (and in the
@ -8463,10 +8477,10 @@ makefile works by changing the variables.
When you override a variable with a command line argument, you can
define either a recursively-expanded variable or a simply-expanded
variable. The examples shown above make a recursively-expanded
variable; to make a simply-expanded variable, write @samp{:=} instead
of @samp{=}. But, unless you want to include a variable reference or
function call in the @emph{value} that you specify, it makes no
difference which kind of variable you create.
variable; to make a simply-expanded variable, write @samp{:=} or
@samp{::=} instead of @samp{=}. But, unless you want to include a
variable reference or function call in the @emph{value} that you
specify, it makes no difference which kind of variable you create.
There is one way that the makefile can change a variable that you have
overridden. This is to use the @code{override} directive, which is a line
@ -11024,6 +11038,7 @@ Here is a summary of the directives GNU @code{make} recognizes:
@item 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
@ -11479,9 +11494,9 @@ prerequisites, etc., one of them depended on @var{xxx} again.
@item Recursive variable `@var{xxx}' references itself (eventually). Stop.
This means you've defined a normal (recursive) @code{make} variable
@var{xxx} that, when it's expanded, will refer to itself (@var{xxx}).
This is not allowed; either use simply-expanded variables (@code{:=}) or
use the append operator (@code{+=}). @xref{Using Variables, ,How to Use
Variables}.
This is not allowed; either use simply-expanded variables (@samp{:=}
or @samp{::=}) or use the append operator (@samp{+=}). @xref{Using
Variables, ,How to Use Variables}.
@item Unterminated variable reference. Stop.
This means you forgot to provide the proper closing parenthesis

35
read.c
View File

@ -495,9 +495,9 @@ parse_var_assignment (const char *line, struct vmodifiers *vmod)
{
int wlen;
const char *p2;
enum variable_flavor flavor;
struct variable v;
p2 = parse_variable_definition (p, &flavor);
p2 = parse_variable_definition (p, &v);
/* If this is a variable assignment, we're done. */
if (p2)
@ -1342,33 +1342,33 @@ static struct variable *
do_define (char *name, enum variable_origin origin, struct ebuffer *ebuf)
{
struct variable *v;
enum variable_flavor flavor;
struct variable var;
struct floc defstart;
int nlevels = 1;
unsigned int length = 100;
char *definition = xmalloc (length);
unsigned int idx = 0;
char *p, *var;
char *p, *n;
defstart = ebuf->floc;
p = parse_variable_definition (name, &flavor);
p = parse_variable_definition (name, &var);
if (p == NULL)
/* No assignment token, so assume recursive. */
flavor = f_recursive;
var.flavor = f_recursive;
else
{
if (*(next_token (p)) != '\0')
if (var.value[0] != '\0')
error (&defstart, _("extraneous text after `define' directive"));
/* Chop the string before the assignment token to get the name. */
p[flavor == f_recursive ? -1 : -2] = '\0';
var.name[var.length] = '\0';
}
/* Expand the variable name and find the beginning (NAME) and end. */
var = allocated_variable_expand (name);
name = next_token (var);
if (*name == '\0')
n = allocated_variable_expand (name);
name = next_token (n);
if (name[0] == '\0')
fatal (&defstart, _("empty variable name"));
p = name + strlen (name) - 1;
while (p > name && isblank ((unsigned char)*p))
@ -1439,9 +1439,10 @@ do_define (char *name, enum variable_origin origin, struct ebuffer *ebuf)
else
definition[idx - 1] = '\0';
v = do_variable_definition (&defstart, name, definition, origin, flavor, 0);
v = do_variable_definition (&defstart, name,
definition, origin, var.flavor, 0);
free (definition);
free (var);
free (n);
return (v);
}
@ -2467,7 +2468,7 @@ readline (struct ebuffer *ebuf)
w_colon A colon
w_dcolon A double-colon
w_semicolon A semicolon
w_varassign A variable assignment operator (=, :=, +=, ?=, or !=)
w_varassign A variable assignment operator (=, :=, ::=, +=, ?=, or !=)
Note that this function is only used when reading certain parts of the
makefile. Don't use it where special rules hold sway (RHS of a variable,
@ -2506,7 +2507,13 @@ get_next_mword (char *buffer, char *delim, char **startp, unsigned int *length)
{
case ':':
++p;
if (p[1] != '=')
wtype = w_dcolon;
else
{
wtype = w_varassign;
++p;
}
break;
case '=':

View File

@ -1,5 +1,8 @@
2012-01-29 Paul Smith <psmith@gnu.org>
* scripts/variables/flavors: Add tests for ::=
* scripts/variables/define: Ditto
* scripts/functions/file: Test the new $(file ...) function.
2012-01-12 Paul Smith <psmith@gnu.org>

View File

@ -30,6 +30,10 @@ define simple :=
@echo $(FOO)
endef
define posix ::=
@echo $(FOO)
endef
append = @echo a
define append +=
@ -49,10 +53,54 @@ FOO = there
all: ; $(multi)
$(simple)
$(posix)
$(append)
$(cond)
',
'', "echo hi\nhi\nthere\nfoo\na\nb\nfirst\n");
'', "echo hi\nhi\nthere\nfoo\nfoo\na\nb\nfirst\n");
# TEST 1a: Various new-style define/endef, with no spaces
run_make_test('
FOO = foo
define multi=
echo hi
@echo $(FOO)
endef # this is the end
define simple:=
@echo $(FOO)
endef
define posix::=
@echo $(FOO)
endef
append = @echo a
define append+=
@echo b
endef
define cond?= # this is a conditional
@echo first
endef
define cond?=
@echo second
endef
FOO = there
all: ; $(multi)
$(simple)
$(posix)
$(append)
$(cond)
',
'', "echo hi\nhi\nthere\nfoo\nfoo\na\nb\nfirst\n");
# TEST 2: define in true section of conditional (containing conditional)

View File

@ -73,4 +73,24 @@ all: ; @echo $(foo)
',
'', "Hello\n");
# TEST 6: Simple using POSIX syntax
run_make_test('
bar = Goodbye
foo ::= $(bar)
bar = ${ugh}
ugh = Hello
all: ; @echo $(foo)
',
'', "Goodbye\n");
# TEST 7: POSIX syntax no spaces
run_make_test('
bar = Goodbye
foo::=$(bar)
bar = ${ugh}
ugh = Hello
all: ; @echo $(foo)
',
'', "Goodbye\n");
1;

View File

@ -1396,17 +1396,27 @@ do_variable_definition (const struct floc *flocp, const char *varname,
/* Parse P (a null-terminated string) as a variable definition.
If it is not a variable definition, return NULL.
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.
If it is a variable definition, return a pointer to the char after the
assignment token and set *FLAVOR to the type of variable assignment. */
assignment token and set the following fields (only) of *VAR:
name : name of the variable (ALWAYS SET) (NOT NUL-TERMINATED!)
length : length of the variable name
value : value of the variable (nul-terminated)
flavor : flavor of the variable
Other values in *VAR are unchanged.
*/
char *
parse_variable_definition (const char *p, enum variable_flavor *flavor)
parse_variable_definition (const char *p, struct variable *var)
{
int wspace = 0;
const char *e = NULL;
p = next_token (p);
var->name = (char *)p;
var->length = 0;
while (1)
{
@ -1451,6 +1461,7 @@ parse_variable_definition (const char *p, enum variable_flavor *flavor)
if (isblank ((unsigned char)c))
{
wspace = 1;
e = p - 1;
p = next_token (p);
c = *p;
if (c == '\0')
@ -1461,8 +1472,10 @@ parse_variable_definition (const char *p, enum variable_flavor *flavor)
if (c == '=')
{
*flavor = f_recursive;
return (char *)p;
var->flavor = f_recursive;
if (! e)
e = p - 1;
break;
}
/* Match assignment variants (:=, +=, ?=, !=) */
@ -1471,16 +1484,16 @@ parse_variable_definition (const char *p, enum variable_flavor *flavor)
switch (c)
{
case ':':
*flavor = f_simple;
var->flavor = f_simple;
break;
case '+':
*flavor = f_append;
var->flavor = f_append;
break;
case '?':
*flavor = f_conditional;
var->flavor = f_conditional;
break;
case '!':
*flavor = f_shell;
var->flavor = f_shell;
break;
default:
/* If we skipped whitespace, non-assignments means no var. */
@ -1490,17 +1503,34 @@ parse_variable_definition (const char *p, enum variable_flavor *flavor)
/* Might be assignment, or might be $= or #=. Check. */
continue;
}
return (char *)++p;
if (! e)
e = p - 1;
++p;
break;
}
else if (c == ':')
/* A colon other than := is a rule line, not a variable defn. */
/* 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 = e - var->name;
var->value = next_token (p);
return (char *)p;
}
@ -1513,27 +1543,15 @@ parse_variable_definition (const char *p, enum variable_flavor *flavor)
struct variable *
assign_variable_definition (struct variable *v, char *line)
{
char *beg;
char *end;
enum variable_flavor flavor;
char *name;
beg = next_token (line);
line = parse_variable_definition (beg, &flavor);
if (!line)
if (!parse_variable_definition (line, v))
return NULL;
end = line - (flavor == f_recursive ? 1 : 2);
while (end > beg && isblank ((unsigned char)end[-1]))
--end;
line = next_token (line);
v->value = line;
v->flavor = flavor;
/* Expand the name, so "$(foo)bar = baz" works. */
name = alloca (end - beg + 1);
memcpy (name, beg, end - beg);
name[end - beg] = '\0';
name = alloca (v->length + 1);
memcpy (name, v->name, v->length);
name[v->length] = '\0';
v->name = allocated_variable_expand (name);
if (v->name[0] == '\0')

View File

@ -35,7 +35,7 @@ enum variable_origin
enum variable_flavor
{
f_bogus, /* Bogus (error) */
f_simple, /* Simple definition (:=) */
f_simple, /* Simple definition (:= or ::=) */
f_recursive, /* Recursive definition (=) */
f_append, /* Appending definition (+=) */
f_conditional, /* Conditional definition (?=) */
@ -52,9 +52,9 @@ enum variable_flavor
struct variable
{
char *name; /* Variable name. */
int length; /* strlen (name) */
char *value; /* Variable value. */
struct floc fileinfo; /* Where the variable was defined. */
int length; /* strlen (name) */
unsigned int recursive:1; /* Gets recursively re-evaluated. */
unsigned int append:1; /* Nonzero if an appending target-specific
variable. */
@ -160,7 +160,7 @@ struct variable *do_variable_definition (const struct floc *flocp,
enum variable_flavor flavor,
int target_var);
char *parse_variable_definition (const char *line,
enum variable_flavor *flavor);
struct variable *v);
struct variable *assign_variable_definition (struct variable *v, char *line);
struct variable *try_variable_definition (const struct floc *flocp, char *line,
enum variable_origin origin,