summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Smith <psmith@gnu.org>2012-01-30 00:21:57 +0000
committerPaul Smith <psmith@gnu.org>2012-01-30 00:21:57 +0000
commitef6461611b8fb7cd4a92168d4c319153462afb5a (patch)
tree715f4d6f1177ce9bb4e5d2d84bf89575c7906175
parentfca11f60390cf607f68b497c3909b1fb40251070 (diff)
downloadgunmake-ef6461611b8fb7cd4a92168d4c319153462afb5a.tar.gz
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.
-rw-r--r--ChangeLog12
-rw-r--r--NEWS6
-rw-r--r--doc/make.texi77
-rw-r--r--read.c37
-rw-r--r--tests/ChangeLog3
-rw-r--r--tests/scripts/variables/define50
-rw-r--r--tests/scripts/variables/flavors20
-rw-r--r--variable.c76
-rw-r--r--variable.h6
9 files changed, 208 insertions, 79 deletions
diff --git a/ChangeLog b/ChangeLog
index facb4cc..9cbb1e6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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.
diff --git a/NEWS b/NEWS
index 20b8704..b07ab98 100644
--- a/NEWS
+++ b/NEWS
@@ -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.
diff --git a/doc/make.texi b/doc/make.texi
index 9b8faee..d723d2d 100644
--- a/doc/make.texi
+++ b/doc/make.texi
@@ -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
diff --git a/read.c b/read.c
index 634eb4c..4378d1b 100644
--- a/read.c
+++ b/read.c
@@ -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;
- wtype = w_dcolon;
+ if (p[1] != '=')
+ wtype = w_dcolon;
+ else
+ {
+ wtype = w_varassign;
+ ++p;
+ }
break;
case '=':
diff --git a/tests/ChangeLog b/tests/ChangeLog
index 3e0643c..7ad4085 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -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>
diff --git a/tests/scripts/variables/define b/tests/scripts/variables/define
index f91519e..68d493b 100644
--- a/tests/scripts/variables/define
+++ b/tests/scripts/variables/define
@@ -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\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\na\nb\nfirst\n");
+ '', "echo hi\nhi\nthere\nfoo\nfoo\na\nb\nfirst\n");
# TEST 2: define in true section of conditional (containing conditional)
diff --git a/tests/scripts/variables/flavors b/tests/scripts/variables/flavors
index 92feed6..ba133ea 100644
--- a/tests/scripts/variables/flavors
+++ b/tests/scripts/variables/flavors
@@ -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;
diff --git a/variable.c b/variable.c
index a0eef9b..839aa5a 100644
--- a/variable.c
+++ b/variable.c
@@ -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;
+ }
+
+ /* 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;
}
- else if (c == ':')
- /* A colon other than := is a rule line, not a variable defn. */
- return NULL;
/* 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')
diff --git a/variable.h b/variable.h
index 1fd1b66..1fe3d1e 100644
--- a/variable.h
+++ b/variable.h
@@ -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,