[SV 64185] Clarify handling of directive lines starting with TAB

It's clear that this change causes too many problems to be made
without warning.  Revert the change disallowing conditional lines to
start with TAB.

Instead, generate warnings whenever a directive line begins with a
TAB character.  Make this change for all directives, not just
conditional directives: define, undefine, export, unexport, vpath,
load, include, etc.

* NEWS: Update the backward-compatibility warning.
* src/read.c (eval): Track whether the line starts with a TAB.
If so then whenever we recognize a directive, emit a warning.
Revert the previous change for this bug.
(parse_var_assignment): Accept a file location if the line begins
with TAB; show a warning if we discover a directive.
(conditional_line): Warn about lines starting with TAB.
* tests/scripts/...: Add tests to verify warnings for initial TAB.
This commit is contained in:
Paul Smith 2025-08-25 23:20:16 -04:00
parent fdcaaed8d7
commit c59cc4f932
11 changed files with 354 additions and 121 deletions

14
NEWS
View File

@ -47,6 +47,16 @@ https://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=111&se
when combined with command-line settings or -e overrides.
See https://savannah.gnu.org/bugs/index.php?64822
* WARNING: Backward-incompatibility!
The documentation has always stated that makefile directive lines cannot
begin with a TAB character. However, the parser was lenient and allowed
initial TAB characters outside of a recipe context. Unfortunately this
leads to unresolvable parsing errors in some situations.
This version of GNU Make will continue to parse directives as before, but
will print a warning whenever a makefile directive line begins with a TAB.
In a future version of GNU Make a line beginning with a TAB character will
never be allowed to contain a makefile directive.
* NOTE: Deprecated behavior.
The check in GNU Make 4.3 for suffix rules with prerequisites didn't check
single-suffix rules, only double-suffix rules. Add the missing check.
@ -91,10 +101,6 @@ https://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=111&se
10:43:57.570558743". Previously it used the form "Wed May 10
10:43:57 2023", which has less detail and is harder to compare.
* Conditional statements starting with the recipe prefix were sometimes
interpreted in previous versions. As per the documentation, lines starting
with the recipe prefix are now never considered conditional statements.
* Tests in the regression test suite now are run in their own directory to
avoid cross-contamination and allow cleanup if the tests are interrupted.
More information is printed about failing tests.

View File

@ -1265,15 +1265,13 @@ include @var{filenames}@dots{}
@cindex shell wildcards (in @code{include})
@cindex wildcard, in @code{include}
Extra spaces are allowed and ignored at the beginning of the line, but
the first character must not be a tab (or the value of
@code{.RECIPEPREFIX})---if the line begins with a tab, it will be
considered a recipe line. Whitespace is required between
@code{include} and the file names, and between file names; extra
whitespace is ignored there and at the end of the directive. A
comment starting with @samp{#} is allowed at the end of the line. If
the file names contain any variable or function references, they are
expanded. @xref{Using Variables, ,How to Use Variables}.
Whitespace is allowed, and ignored, at the beginning of the line, but the
first character may not be a tab character. Whitespace is required between
@code{include} and the file names, and between file names; extra whitespace is
ignored there and at the end of the line. A comment starting with @samp{#} is
allowed at the end of the line. If the file names contain any variable or
function references, they are expanded. @xref{Using Variables, ,How to Use
Variables}.
For example, if you have three @file{.mk} files, @file{a.mk},
@file{b.mk}, and @file{c.mk}, and @code{$(bar)} expands to
@ -2501,6 +2499,9 @@ particular pattern. Thus you can supply certain search directories for
one class of file names and other directories (or none) for other file
names.
A @code{vpath} directive can be preceded by whitespace, but the line cannot
begin with a tab character.
There are three forms of the @code{vpath} directive:
@table @code
@ -4992,6 +4993,10 @@ In both of these forms, the arguments to @code{export} and
@code{unexport} are expanded, and so could be variables or functions
which expand to a (list of) variable names to be (un)exported.
As with all directives, @code{export} and @code{unexport} can be preceded by
whitespace, which is ignored, but the first character in the directive line
may not be a tab character.
GNU Make will add any variable you export to the environment of all child
processes. However, be aware that some child processes themselves will not
accept all types of variables. For example, many modern shells will clean the
@ -6582,27 +6587,29 @@ endef
@cindex variables, defining verbatim
Another way to set the value of a variable is to use the @code{define}
directive. This directive has an unusual syntax which allows newline
characters to be included in the value, which is convenient for
defining both canned sequences of commands (@pxref{Canned Recipes,
,Defining Canned Recipes}), and also sections of makefile syntax to
use with @code{eval} (@pxref{Eval Function}).
directive. This directive allows newline characters to be included in the
value, which is convenient for defining both canned sequences of commands
(@pxref{Canned Recipes, ,Defining Canned Recipes}), and also sections of
makefile syntax to use with @code{eval} (@pxref{Eval Function}). Aside from
the difference in syntax, @code{define} behaves like any other variable
definition.
The @code{define} directive is followed on the same line by the name
of the variable being defined and an (optional) assignment operator,
and nothing more. The value to give the variable appears on the
following lines. The end of the value is marked by a line containing
just the word @code{endef}.
The @code{define} directive may be preceded by whitespace, which is ignored.
However, the line @emph{may not} begin with a tab character. The directive is
followed on the same line by whitespace then the name of the variable being
defined, and an (optional) assignment operator. The variable name may contain
function and variable references, which are expanded when the directive is
read to determine the final variable name to use.
Aside from this difference in syntax, @code{define} works just like
any other variable definition. The variable name may contain function
and variable references, which are expanded when the directive is read
to find the actual variable name to use.
The value to be assigned to the variable appears on the subsequent lines. The
end of the value is marked by a line containing just the word @code{endef}
(optionally preceded by whitespace, but again the line cannot begin with a tab
character).
The final newline before the @code{endef} is not included in the
value; if you want your value to contain a trailing newline you must
include a blank line. For example in order to define a variable that
contains a newline character you must use @emph{two} empty lines, not one:
The final newline before the @code{endef} is not included in the value; if you
want your value to contain a trailing newline you must include a blank line.
For example in order to define a variable that contains a newline character
you must use @emph{two} empty lines, not one:
@example
define newline
@ -6611,19 +6618,15 @@ define newline
endef
@end example
You may omit the variable assignment operator if you prefer. If
omitted, @code{make} assumes it to be @samp{=} and creates a
recursively-expanded variable (@pxref{Flavors, ,The Two Flavors of Variables}).
When using a @samp{+=} operator, the value is appended to the previous
value as with any other append operation: with a single space
You may omit the variable assignment operator. If omitted, @code{make}
assumes it to be @samp{=} and creates a recursively-expanded variable
(@pxref{Flavors, ,The Two Flavors of Variables}). When using a @samp{+=}
operator, the value is appended to the previous value with a single space
separating the old and new values.
You may nest @code{define} directives: @code{make} will keep track of
nested directives and report an error if they are not all properly
closed with @code{endef}. Note that lines beginning with the recipe
prefix character are considered part of a recipe, so any @code{define}
or @code{endef} strings appearing on such a line will not be
considered @code{make} directives.
You may nest @code{define} directives: @code{make} will keep track of nested
directives and report an error if any are not properly closed with
@code{endef}.
@example
define two-lines
@ -7216,12 +7219,16 @@ makefile. @xref{Warnings, ,Makefile Warnings}.
@chapter Conditional Parts of Makefiles
@cindex conditionals
A @dfn{conditional} directive causes part of a makefile to be obeyed
or ignored depending on the values of variables. Conditionals can
compare the value of one variable to another, or the value of a
variable to a constant string. Conditionals control what @code{make}
actually ``sees'' in the makefile, so they @emph{cannot} be used to
control recipes at the time of execution.
A @dfn{conditional} directive allows part of a makefile to be parsed or
ignored based on a condition. Conditionals can check whether @code{make}
variables are defined, or compare the results of expanding two strings for
equality.
Conditionals are evaluated @emph{as the makefile is parsed}, so it cannot
access values that are only known when a target is being built. For example,
conditions cannot be based on automatic variables (@pxref{Automatic
Variables}), target-specific variables (@pxref{Target-specific,
,Target-specific Variable Values}), or values set in a recipe.
@menu
* Conditional Example:: Example of a conditional
@ -7232,12 +7239,11 @@ control recipes at the time of execution.
@node Conditional Example
@section Example of a Conditional
The following example of a conditional tells @code{make} to use one
set of libraries if the @code{CC} variable is @samp{gcc}, and a
different set of libraries otherwise. It works by controlling which
of two recipe lines will be used for the rule. The result is that
@samp{CC=gcc} as an argument to @code{make} changes not only which
compiler is used but also which libraries are linked.
The following example causes @code{make} to use one set of libraries if the
@code{CC} variable is @samp{gcc}, and a different set of libraries otherwise.
It works by controlling which of two recipe lines will be used for the rule.
The result is that @samp{CC=gcc} as an argument to @code{make} changes not
only which compiler is used but also which libraries are linked.
@example
libs_for_gcc = -lgnu
@ -7251,8 +7257,8 @@ else
endif
@end example
This conditional uses three directives: one @code{ifeq}, one @code{else}
and one @code{endif}.
This conditional uses three directives: @code{ifeq}, @code{else}, and
@code{endif}.
The @code{ifeq} directive begins the conditional, and specifies the
condition. It contains two arguments, separated by a comma and surrounded
@ -7261,10 +7267,10 @@ then they are compared. The lines of the makefile following the
@code{ifeq} are obeyed if the two arguments match; otherwise they are
ignored.
The @code{else} directive causes the following lines to be obeyed if the
previous conditional failed. In the example above, this means that the
second alternative linking command is used whenever the first alternative
is not used. It is optional to have an @code{else} in a conditional.
The @code{else} directive causes the following lines to be active if the
previous condition was false. In the example above, this means that the
second alternative linking command is used whenever the first alternative is
not used. It is optional to have an @code{else} in a conditional.
The @code{endif} directive ends the conditional. Every conditional must
end with an @code{endif}. Unconditional makefile text follows.
@ -7285,14 +7291,13 @@ foo: $(objects)
@noindent
When the variable @code{CC} has any other value, the effect is this:
@example
foo: $(objects)
$(CC) -o foo $(objects) $(normal_libs)
@end example
Equivalent results can be obtained in another way by conditionally assigning a
variable and then using the variable unconditionally:
Equivalent results can be obtained by conditionally assigning a variable and
then using the variable unconditionally:
@example
libs_for_gcc = -lgnu
@ -7317,6 +7322,17 @@ foo: $(objects)
@findex else
@findex endif
A conditional section begins with one of the four ``if'' directives @code{ifdef}, @code{ifndef}, @code{ifeq}, or @code{ifneq}. Each
conditional section must end with the @code{endif} directive. A section may
contain the @code{else} directive to provide an alternative section if the
original condition is false. The @code{else} directive can be followed (on
the same line) by another ``if'' directive introducing a new condition.
Spaces may appear, and are ignored, at the beginning of a conditional
directive line. However, conditional directive lines @emph{may not} start
with a tab character. The @code{ifeq} and @code{ifneq} directives must be
followed by whitespace, before the conditional expression.
The syntax of a simple conditional with no @code{else} is as follows:
@example
@ -7463,13 +7479,6 @@ if any, is effective. The rules for expansion and testing of
@var{variable-name} are identical to the @code{ifdef} directive.
@end table
Extra spaces are allowed and ignored at the beginning of the
conditional directive line, but a tab is not allowed. (If the line
begins with a tab, it will be considered part of a recipe for a rule.)
Aside from this, extra spaces or tabs may be inserted with no effect
anywhere except within the directive name or within an argument. A
comment starting with @samp{#} may appear at the end of the line.
The other two directives that play a part in a conditional are @code{else}
and @code{endif}. Each of these directives is written as one word, with no
arguments. Extra spaces are allowed and ignored at the beginning of the
@ -12159,8 +12168,10 @@ or:
load @var{object-file}(@var{symbol-name}) @dots{}
@end example
More than one object file may be loaded with a single @code{load} directive,
and both forms of @code{load} arguments may be used in the same directive.
Whitespace can precede the directive and is ignored, but the first character
may not be a tab character. More than one object file may be loaded with a
single @code{load} directive, and both forms of @code{load} arguments may be
used in the same directive.
The file @var{object-file} is dynamically loaded by GNU @code{make}. If
@var{object-file} does not include a directory path then it is first looked

View File

@ -137,7 +137,8 @@ static void do_undefine (char *name, enum variable_origin origin,
struct ebuffer *ebuf);
static struct variable *do_define (char *name, enum variable_origin origin,
struct ebuffer *ebuf);
static int conditional_line (char *line, size_t len, const floc *flocp);
static int conditional_line (char *line, size_t len, const floc *flocp,
unsigned int initial_tab);
static void check_specials (struct nameseq *filep, int set_default);
static void check_special_file (struct file *filep, const floc *flocp);
static void record_files (struct nameseq *filenames, int are_also_makes,
@ -477,6 +478,8 @@ eval_buffer (char *buffer, const floc *flocp)
/* Check LINE to see if it's a variable assignment or undefine.
If flocp is not NULL, then the assignment line begins with TAB.
It might use one of the modifiers "export", "override", "private", or it
might be one of the conditional tokens like "ifdef", "include", etc.
@ -487,7 +490,7 @@ eval_buffer (char *buffer, const floc *flocp)
based on the modifiers found if any, plus V_ASSIGN is 1.
*/
static char *
parse_var_assignment (const char *line, int targvar, struct vmodifiers *vmod)
parse_var_assignment (const char *line, int targvar, const floc *flocp, struct vmodifiers *vmod)
{
const char *p;
memset (vmod, '\0', sizeof (*vmod));
@ -524,6 +527,8 @@ parse_var_assignment (const char *line, int targvar, struct vmodifiers *vmod)
vmod->private_v = 1;
else if (!targvar && word1eq ("define"))
{
if (flocp)
O (error, flocp, _("warning: directive lines cannot start with TAB"));
/* We can't have modifiers after 'define' */
vmod->define_v = 1;
p = next_token (p2);
@ -531,6 +536,8 @@ parse_var_assignment (const char *line, int targvar, struct vmodifiers *vmod)
}
else if (!targvar && word1eq ("undefine"))
{
if (flocp)
O (error, flocp, _("warning: directive lines cannot start with TAB"));
/* We can't have modifiers after 'undefine' */
vmod->undefine_v = 1;
p = next_token (p2);
@ -540,7 +547,14 @@ parse_var_assignment (const char *line, int targvar, struct vmodifiers *vmod)
/* Not a variable or modifier: this is not a variable assignment. */
return (char *) line;
/* It was a modifier. Try the next word. */
/* It was a modifier. Check for TAB and try the next word. */
if (flocp)
{
O (error, flocp, _("warning: directive lines cannot start with TAB"));
/* Only warn about the first directive. */
flocp = NULL;
}
p = next_token (p2);
if (*p == '\0')
return (char *) line;
@ -622,6 +636,7 @@ eval (struct ebuffer *ebuf, int set_default)
char *p;
char *p2;
unsigned int is_rule;
unsigned int initial_tab;
struct vmodifiers vmod;
/* At the top of this loop, we are starting a brand new line. */
@ -652,30 +667,30 @@ eval (struct ebuffer *ebuf, int set_default)
}
}
}
/* If this line is empty, skip it. */
if (line[0] == '\0')
continue;
initial_tab = line[0] == '\t';
linelen = strlen (line);
/* Check for a shell command line first.
If it is not one, we can stop treating cmd_prefix specially. */
if (line[0] == cmd_prefix)
{
/* Ignore recipe lines in a rule with no targets. */
if (no_targets)
/* Ignore the commands in a rule with no targets. */
continue;
if (ignoring)
/* Yep, this is a shell command, and we don't care. */
continue;
/* If there is no preceding rule line, don't treat this line
as a command, even though it begins with a recipe prefix.
SunOS 4 make appears to behave this way. */
/* Only part of a recipe if it appears in a recipe context. */
if (filenames != 0)
{
/* Are we in the un-taken leg of a conditional directive? */
if (ignoring)
continue;
if (commands_idx == 0)
cmds_started = ebuf->floc.lineno;
@ -689,6 +704,8 @@ eval (struct ebuffer *ebuf, int set_default)
memcpy (&commands[commands_idx], line + 1, linelen - 1);
commands_idx += linelen - 1;
commands[commands_idx++] = '\n';
/* This line is fully consumed. */
continue;
}
}
@ -715,7 +732,7 @@ eval (struct ebuffer *ebuf, int set_default)
/* See if this is a variable assignment. We need to do this early, to
allow variables with names like 'ifdef', 'export', 'private', etc. */
p = parse_var_assignment (p, 0, &vmod);
p = parse_var_assignment (p, 0, initial_tab ? &ebuf->floc : NULL, &vmod);
if (vmod.assign_v)
{
struct variable *v;
@ -775,7 +792,7 @@ eval (struct ebuffer *ebuf, int set_default)
/* Check for conditional state changes. */
{
int i = conditional_line (p, wlen, fstart);
int i = conditional_line (p, wlen, fstart, initial_tab);
if (i != -2)
{
if (i == -1)
@ -796,6 +813,11 @@ eval (struct ebuffer *ebuf, int set_default)
{
int exporting = *p == 'u' ? 0 : 1;
if (initial_tab)
OS (error, &ebuf->floc,
_("warning: %s lines cannot start with TAB"),
exporting ? "export" : "unexport");
/* Export/unexport ends the previous rule. */
record_waiting_files ();
@ -833,6 +855,10 @@ eval (struct ebuffer *ebuf, int set_default)
char *vpat;
size_t l;
if (initial_tab)
O (error, &ebuf->floc,
_("warning: vpath directive lines cannot start with TAB"));
/* vpath ends the previous rule. */
record_waiting_files ();
@ -866,6 +892,11 @@ eval (struct ebuffer *ebuf, int set_default)
exist. "sinclude" is an alias for this from SGI. */
int noerror = (p[0] != 'i');
if (initial_tab)
OS (error, &ebuf->floc,
_("warning: %s lines cannot start with TAB"),
*p == 'i' ? "include" : *p == '-' ? "-include" : "sinclude");
/* Include ends the previous rule. */
record_waiting_files ();
@ -920,6 +951,11 @@ eval (struct ebuffer *ebuf, int set_default)
struct nameseq *files;
int noerror = (p[0] == '-');
if (initial_tab)
OS (error, &ebuf->floc,
_("warning: %s lines cannot start with TAB"),
noerror ? "-load" : "load");
/* Load ends the previous rule. */
record_waiting_files ();
@ -1196,7 +1232,7 @@ eval (struct ebuffer *ebuf, int set_default)
p2 = variable_buffer + l;
}
p2 = parse_var_assignment (p2, 1, &vmod);
p2 = parse_var_assignment (p2, 1, NULL, &vmod);
if (vmod.assign_v)
{
/* If there was a semicolon found, add it back, plus anything
@ -1503,7 +1539,7 @@ do_define (char *name, enum variable_origin origin, struct ebuffer *ebuf)
1 if following text should be ignored. */
static int
conditional_line (char *line, size_t len, const floc *flocp)
conditional_line (char *line, size_t len, const floc *flocp, unsigned int initial_tab)
{
const char *cmdname;
enum { c_ifdef, c_ifndef, c_ifeq, c_ifneq, c_else, c_endif } cmdtype;
@ -1524,6 +1560,10 @@ conditional_line (char *line, size_t len, const floc *flocp)
else
return -2;
if (initial_tab)
O (error, flocp,
_("warning: conditional directive lines cannot start with TAB"));
/* Found one: skip past it and any whitespace after it. */
line += len;
NEXT_TOKEN (line);
@ -1583,13 +1623,13 @@ conditional_line (char *line, size_t len, const floc *flocp)
and cannot be an 'else' or 'endif'. */
/* Find the length of the next word. */
for (p = line+1; ! STOP_SET (*p, MAP_SPACE|MAP_NUL); ++p)
for (p = line+1; ! STOP_SET (*p, MAP_BLANK|MAP_NUL); ++p)
;
len = p - line;
/* If it's 'else' or 'endif' or an illegal conditional, fail. */
if (word1eq ("else") || word1eq ("endif")
|| conditional_line (line, len, flocp) < 0)
|| conditional_line (line, len, flocp, 0) < 0)
EXTRATEXT ();
else
{

View File

@ -153,7 +153,59 @@ endif
!,
'', "one\n");
# SV 64085: Ensure recipe prefixed conditionals are never considered
# SV 64085: Ensure tab-prefixed conditional directives are warned about
# In a future release these will become errors: according to the docs this
# was never allowed, but unfortunately the code didn't check for it.
my @defcond = ('ifdef', 'ifndef');
my @eqcond = ('ifeq', 'ifneq');
for my $d (@defcond) {
run_make_test(qq!
blah=1
#TAB#$d blah
endif
all:;
!,
'', "#MAKEFILE#:3: warning: conditional directive lines cannot start with TAB\n#MAKE#: 'all' is up to date.");
}
for my $d (@eqcond) {
run_make_test(qq!
blah=1
#TAB#$d (a,b)
endif
all:;
!,
'', "#MAKEFILE#:3: warning: conditional directive lines cannot start with TAB\n#MAKE#: 'all' is up to date.");
}
run_make_test(q!
ifeq (a, b)
#TAB## noop
else
#TAB#ifeq (a, b)
#TAB##TAB## noop
#TAB#endif
endif
all:
#TAB#@echo foo
!,
'', "#MAKEFILE#:5: warning: conditional directive lines cannot start with TAB\n#MAKEFILE#:7: warning: conditional directive lines cannot start with TAB\nfoo");
run_make_test(q!
all:
$(info hello)
ifdef blah
junk:
#TAB#else
else
endif
!,
'', "hello\n#MAKEFILE#:7: warning: conditional directive lines cannot start with TAB\n#MAKEFILE#:8: *** only one 'else' per conditional. Stop.",
512);
run_make_test(q!
blah=1
ifdef blah
@ -162,7 +214,8 @@ else
endif
all:;
!,
'', "#MAKE#: 'all' is up to date.");
'', "#MAKEFILE#:5: warning: conditional directive lines cannot start with TAB\n#MAKEFILE#:5: *** only one 'else' per conditional. Stop.",
512);
run_make_test(q!
blah=1
@ -172,7 +225,8 @@ else
endif
all:;
!,
'', "#MAKE#: 'all' is up to date.");
'', "#MAKEFILE#:5: warning: conditional directive lines cannot start with TAB\n#MAKEFILE#:6: *** extraneous 'endif'. Stop.",
512);
run_make_test(q!
blah=1
@ -182,7 +236,8 @@ else
endif
all:;
!,
'', "#MAKE#: 'all' is up to date.");
'', "#MAKEFILE#:5: warning: conditional directive lines cannot start with TAB\n#MAKEFILE#:8: *** missing 'endif'. Stop.",
512);
run_make_test(q!
blah=1

View File

@ -489,4 +489,18 @@ test: test.x; touch $@
unlink('test.foo', 'test.x', 'test');
# Verify that include prefixed by TAB gives a warning
my @inctypes = ('include', '-include', 'sinclude');
touch('inc.mk');
for my $inc (@inctypes) {
run_make_test(qq!
#TAB#$inc inc.mk
all:;\@echo hi
!,
'', "#MAKEFILE#:2: warning: $inc lines cannot start with TAB\nhi");
}
1;

View File

@ -166,5 +166,19 @@ load |: ; echo $@
!,
"", "all\n");
# Verify that load does not start with TAB
run_make_test(q!
#TAB#load ./testload.so
all:;@echo hi
!,
'', "#MAKEFILE#:2: warning: load lines cannot start with TAB\nhi\n");
run_make_test(q!
#TAB#-load ./testload.so
all:;@echo hi
!,
'', "#MAKEFILE#:2: warning: -load lines cannot start with TAB\nhi\n");
# This tells the test driver that the perl test script executed properly.
1;

View File

@ -41,5 +41,24 @@ all: ; $(foo)
',
'foo=Hello', "First comes the definition.\nThen comes the override.\n");
# Directive lines cannot begin with TAB
run_make_test(q!
#TAB#override FOO = bar
all:;@echo hi
!,
'', "#MAKEFILE#:2: warning: directive lines cannot start with TAB\nhi");
run_make_test(q!
#TAB#override#TAB#export FOO = bar
all:;@echo hi
!,
'', "#MAKEFILE#:2: warning: directive lines cannot start with TAB\nhi");
run_make_test(q!
override#TAB#export FOO = bar
all:;@echo hi
!,
'', "hi");
1;

View File

@ -113,4 +113,12 @@ vpa/foo.x: ; @echo vpath $@
rmdir("vpa");
# Validate that vpath indented with TAB gives a warning
run_make_test(q!
#TAB#vpath %.h b3
all:;@echo hi
!,
'', "#MAKEFILE#:2: warning: vpath directive lines cannot start with TAB\nhi");
1;

View File

@ -4,7 +4,7 @@ $description = "Test define/endef variable assignments.";
$details = "";
# TEST 0: old-style basic define/endef
# old-style basic define/endef
run_make_test('
define multi
@ -16,7 +16,7 @@ all: ; $(multi)
',
'', "hi\necho there\nthere\n");
# TEST 1: Various new-style define/endef
# Various new-style define/endef
run_make_test('
FOO = foo
@ -59,7 +59,7 @@ all: ; $(multi)
',
'', "echo hi\nhi\nthere\nfoo\nfoo\na\nb\nfirst\n");
# TEST 1a: Various new-style define/endef, with no spaces
# Various new-style define/endef, with no spaces
run_make_test(q!
FOO = foo
@ -107,7 +107,7 @@ all: ; $(multi)
!,
'', "echo hi\nhi\nthere\nfoo\nfoo\nfoo\$bar\na\nb\nfirst\n");
# TEST 2: define in true section of conditional (containing conditional)
# define in true section of conditional (containing conditional)
run_make_test('
FOO = foo
@ -126,11 +126,11 @@ all: ; @echo $(FOO)
',
'BOGUS=1', "bar\n");
# TEST 3: define in false section of conditional (containing conditional)
# define in false section of conditional (containing conditional)
run_make_test(undef, '', "foo\n");
# TEST 4: nested define (supported?)
# nested define (supported?)
run_make_test('
define outer
@ -145,7 +145,7 @@ outer: ; @echo $(inner)
',
'', "A = B\n");
# TEST 5: NEGATIVE: Missing variable name
# NEGATIVE: Missing variable name
run_make_test('
NAME =
@ -156,7 +156,7 @@ all: ; @echo ouch
',
'', "#MAKEFILE#:3: *** empty variable name. Stop.\n", 512);
# TEST 6: NEGATIVE: extra text after define
# NEGATIVE: extra text after define
run_make_test('
NAME =
@ -167,7 +167,7 @@ all: ; @echo ok
',
'', "#MAKEFILE#:3: extraneous text after 'define' directive\nok\n");
# TEST 7: NEGATIVE: extra text after endef
# NEGATIVE: extra text after endef
run_make_test('
NAME =
@ -178,7 +178,7 @@ all: ; @echo ok
',
'', "#MAKEFILE#:5: extraneous text after 'endef' directive\nok\n");
# TEST 8: NEGATIVE: missing endef
# NEGATIVE: missing endef
run_make_test('
NAME =
@ -215,9 +215,6 @@ endef$(NAME)
# can't know anymore whether the prefix character came before the variable
# reference or was included in the first line of the variable reference.
# TEST #5
# -------
run_make_test('
define FOO
$(V1)echo hello
@ -227,15 +224,9 @@ all: ; @$(FOO)
', '', 'hello
world');
# TEST #6
# -------
run_make_test(undef, 'V1=@ V2=@', 'hello
world');
# TEST #7
# -------
run_make_test('
define FOO
$(V1)echo hello
@ -246,21 +237,13 @@ all: ; $(FOO)
echo world
world');
# TEST #8
# -------
run_make_test(undef, 'V2=@', 'echo hello
hello
world');
# TEST #9
# -------
run_make_test(undef, 'V1=@ V2=@', 'hello
world');
# TEST #10
# -------
# Test the basics; a "@" internally to the variable applies to only one line.
# A "@" before the variable applies to the entire variable.
@ -302,4 +285,59 @@ foo:;
!,
'', "define\n");
# Verify that define indented by TAB is warned about.
# This will be an error in future versions.
run_make_test(q!
#TAB#define foo
@echo foo
endef
all:;$(foo)
!,
'', "#MAKEFILE#:2: warning: directive lines cannot start with TAB\nfoo\n");
# The failure doesn't happen at define time for nested defines, it happens
# at eval time
run_make_test(q!
foo = echo foo
define bar
#TAB#define foo
#TAB# echo bar
#TAB#endef
endef
all:;@$(foo)
!,
'', "foo\n");
run_make_test(q!
foo = echo foo
define bar
#TAB#define foo
#TAB# echo bar
#TAB#endef
endef
$(eval $(bar))
all:;@echo foo
!,
'', "#MAKEFILE#:10: warning: directive lines cannot start with TAB\n#MAKEFILE#:10: *** missing 'endef', unterminated 'define'. Stop.\n",
512);
# endef indented by TAB is an error; this has always been true!
run_make_test(q!
define foo
@echo foo
#TAB#endef
all:;$(foo)
!,
'', "#MAKEFILE#:2: *** missing 'endef', unterminated 'define'. Stop.\n", 512);
1;

View File

@ -174,4 +174,24 @@ b: ; @#HELPER# env FOO
!,
'', 'FOO=<unset>');
# Directive lines cannot begin with TAB
run_make_test(q!
#TAB#private FOO = bar
all:;@echo hi
!,
'', "#MAKEFILE#:2: warning: directive lines cannot start with TAB\nhi");
run_make_test(q!
#TAB#private#TAB#export FOO = bar
all:;@echo hi
!,
'', "#MAKEFILE#:2: warning: directive lines cannot start with TAB\nhi");
run_make_test(q!
private#TAB#export FOO = bar
all:;@echo hi
!,
'', "hi");
1;

View File

@ -88,4 +88,12 @@ foo:;
!,
'', "undefine\n");
# Directive lines cannot begin with TAB
run_make_test(q!
#TAB#undefine FOO
all:;@echo hi
!,
'', "#MAKEFILE#:2: warning: directive lines cannot start with TAB\nhi");
1;