Introduce a --warn command line option

Replace the singleton --warn-undefined-variables with infrastructure
to manage multiple warnings: the --warn option can take an action
"ignore", "warn", or "error" (which will apply to all warnings), or
a specific warning type and an action for that type.  Multiple
options can be provided and are consolidated.

* NEWS: Announce the new option.
* doc/make.1: Document in the man page.
* doc/make.texi (Warnings): Document in the user's manual.
* Makefile.am: Add new header warning.h.
* src/warning.h: Define enum for actions and warning types, and
macros to test whether they are set.  Keep the default settings
separate so that we can correctly reconstruct MAKEFLAGS.
* src/makeint.h: Remove deprecated warn_undefined_variables_flag.
* src/main.c: Create global variables to hold warning settings.
(switches): Add a new switch for --warn.
(initialize_warnings): Set the default warning actions.
(main): Call initialize_warnings().
(encode_warning_state, decode_warning_state): Convert warning states
between strings and enums.
(encode_warning_name, decode_warning_name): Convert warning names
between strings and enums.
(decode_warn_flags): Convert a --warn option into enum values.  If
deprecated warn_undefined_variables_flag is set convert it to --warn.
(decode_switches): Don't remove duplicates of --warn since order
matters.  Call decode_warn_flags() to handle --warn.
(define_makeflags): Special-case handling of --warn options written
to MAKEFLAGS: write out the current settings.
* src/read.c (tilde_expand): Use new warning control macros.
* src/variable.c (warn_undefined): Ditto.
* src/job.c (construct_command_argv): Ditto.
* tests/scripts/options/warn: Rename from warn-undefined-variables
and add tests for --warn.
* tests/scripts/variables/MAKEFLAGS: Expect the new behavior.
This commit is contained in:
Paul Smith 2023-02-26 18:04:14 -05:00
parent 9db74434cd
commit 2611e1991f
13 changed files with 462 additions and 98 deletions

View File

@ -37,7 +37,7 @@ make_SRCS = src/ar.c src/arscan.c src/commands.c src/commands.h \
src/mkcustom.h src/os.h src/output.c src/output.h src/read.c \
src/remake.c src/rule.c src/rule.h src/shuffle.h src/shuffle.c \
src/signame.c src/strcache.c src/variable.c src/variable.h \
src/version.c src/vpath.c
src/version.c src/vpath.c src/warning.h
w32_SRCS = src/w32/pathstuff.c src/w32/w32os.c src/w32/compat/dirent.c \
src/w32/compat/posixfcn.c src/w32/include/dirent.h \

9
NEWS
View File

@ -18,7 +18,14 @@ https://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=111&se
* WARNING: Removed AmigaOS support!
This version of GNU Make no longer supports AmigaOS. If you need support
for AmigaOS please use one of the older versions.
for AmigaOS please use one of the older versions of GNU Make.
* New feature: Makefile warning reporting control
A new option "--warn" controls reporting of warnings for makefiles. Actions
can be set to "ignore", "warn", or "error". The existing warning for
undefined variables is implemented and defaults to "ignore".
"--warn-undefined-variables" is deprecated, and is translated to
"--warn=undefined-vars" internally.
Version 4.4.1 (26 Feb 2023)

View File

@ -364,8 +364,36 @@ command on the given file before running
except that the modification time is changed only in the imagination of
.BR make .
.TP 0.5i
\fB\-\-warn\fR[=\fIARG[\fR,\fIARG\fR]]
Control warning reporting for makefiles. This option can appear multiple times.
In case of conflicts, later settings override earlier settings.
.I ARG
can be an action; one of
.IR ignore ,
.IR warn ,
or
.I error
to set the default action for all warnings, or it can be a specific warning:
.I undefined-var
(referencing an undefined variable). The behavior of each warning can be set
by adding
.BI : action
after the warning name. If an action is not specified the default is
.IR warn .
If no
.I ARG
is provided the action for all warnings is
.IR warn .
If no
.B \-\-warn
option is provided the default action for
.I undefined-var
is
.IR ignore .
.TP 0.5i
.B \-\-warn\-undefined\-variables
Warn when an undefined variable is referenced.
A deprecated alternative for
.BR \-\-warn=undefined-var .
.SH "EXIT STATUS"
GNU Make exits with a status of zero if all makefiles were successfully parsed
and no targets that were built failed. A status of one will be returned

View File

@ -310,6 +310,7 @@ How to Run @code{make}
an alternate compiler and other things.
* Testing:: How to proceed past some errors, to
test compilation.
* Warnings:: How to control reporting of makefile issues.
* Temporary Files:: Where @code{make} keeps its temporary files.
* Options Summary:: Summary of Options
@ -5170,7 +5171,7 @@ compatibility. It has the same value as @code{MAKEFLAGS} except that it
does not contain the command line variable definitions, and it always
begins with a hyphen unless it is empty (@code{MAKEFLAGS} begins with a
hyphen only when it begins with an option that has no single-letter
version, such as @samp{--warn-undefined-variables}). @code{MFLAGS} was
version, such as @samp{--no-print-directory}). @code{MFLAGS} was
traditionally used explicitly in the recursive @code{make} command, like
this:
@ -8873,6 +8874,7 @@ determines that some target is not already up to date.
an alternate compiler and other things.
* Testing:: How to proceed past some errors, to
test compilation.
* Warnings:: How to control reporting of makefile issues.
* Temporary Files:: Where @code{make} keeps its temporary files.
* Options Summary:: Summary of Options
@end menu
@ -9265,7 +9267,7 @@ overridden. This is to use the @code{override} directive, which is a line
that looks like this: @samp{override @var{variable} = @var{value}}
(@pxref{Override Directive, ,The @code{override} Directive}).
@node Testing, Temporary Files, Overriding, Running
@node Testing, Warnings, Overriding, Running
@section Testing the Compilation of a Program
@cindex testing compilation
@cindex compilation, testing
@ -9303,7 +9305,68 @@ program, perhaps to find several independent problems so that you can
correct them all before the next attempt to compile. This is why Emacs'
@kbd{M-x compile} command passes the @samp{-k} flag by default.
@node Temporary Files, Options Summary, Testing, Running
@node Warnings, Temporary Files, Testing, Running
@section Makefile Warnings
@cindex warnings
GNU Make can detect some types of incorrect usage in makefiles and show
warnings about them. Currently these issues can be detected:
@table @samp
@item undefined-var
Referencing a variable that has not been defined.
@end table
When one of these incorrect usages is detected, GNU Make can perform one of
these actions:
@table @samp
@item ignore
Ignore the usage.
@item warn
Show a warning about the usage and continue processing the makefile.
@item error
Show an error for the usage and immediately stop processing the makefile.
@end table
The default action when no warning control options are provided for
@samp{undefined-var} is @samp{warn}.
To modify this default behavior, you can use the @code{--warn} option. This
option can be specified on the command line, or by adding it to the
@code{MAKEFLAGS} variable (@pxref{Recursion, ,Recursive Use of @code{make}}).
Settings added to @code{MAKEFLAGS} are only affect after the assignment
statement.
The @code{--warn} option can be provided multiple times: the effects are
cumulative with later options overriding over earlier options. When GNU Make
provides warning settings to sub-makes, they are all combined into a single
@code{--warn} option in @code{MAKEFLAGS}.
If @code{--warn} is provided with no arguments then all issues are detected
and reported at the @samp{warn} level unless otherwise specified.
If one of the actions (@samp{ignore}, @samp{warn}, @samp{error}) is provided
as an argument to @code{--warn}, then this action becomes the default for all
warning types. For example all warnings can be disabled by using
@code{--warn=ignore}, or all warnings can be considered fatal errors by using
@code{--warn=error}.
Additionally, warning types can be specified. If the warning is listed alone,
then that warning is enabled with the @code{warn} action: e.g.,
@code{--warn=undefined-var} will enable @samp{undefined-var} warnings with the
@samp{warn} action. Alternatively an action can be provided after the warning
type, separated by a @code{:}. So @code{--warn=undefined-var:error} enables
@samp{undefined-var} warnings with an action of @samp{error}.
More specific settings take precedence over the global setting. For example,
an option @code{--warn=undefined-var:error,ignore} will set the action for
@samp{undefined-var} warnings to @samp{error}, and the action for all other
warnings to @samp{ignore}.
@node Temporary Files, Options Summary, Warnings, Running
@section Temporary Files
@cindex temporary files
@ -9756,13 +9819,19 @@ running a @code{touch} command on the given file before running
imagination of @code{make}.
@xref{Instead of Execution, ,Instead of Executing Recipes}.
@item --warn[=@var{arg}[,@var{arg}]]
@cindex @code{--warn}
@cindex warnings
Specify the handling of @ref{Warnings, ,Makefile Warnings} detected in
makefiles.
@item --warn-undefined-variables
@cindex @code{--warn-undefined-variables}
@cindex variables, warning for undefined
@cindex undefined variables, warning message
Issue a warning message whenever @code{make} sees a reference to an
undefined variable. This can be helpful when you are trying to debug
makefiles which use variables in complex ways.
A deprecated name for @code{--warn=undefined-var}. @xref{Warnings,
,Makefile Warnings}.
@end table
@node Implicit Rules, Archives, Running, Top

View File

@ -27,6 +27,7 @@ this program. If not, see <https://www.gnu.org/licenses/>. */
#include "os.h"
#include "dep.h"
#include "shuffle.h"
#include "warning.h"
/* Default shell to use. */
#if MK_OS_W32
@ -3633,9 +3634,9 @@ construct_command_argv (char *line, char **restp, struct file *file,
{
struct variable *var;
/* Turn off --warn-undefined-variables while we expand SHELL and IFS. */
int save = warn_undefined_variables_flag;
warn_undefined_variables_flag = 0;
/* Turn off undefined variables warning while we expand HOME. */
enum warning_state save = warn_get (wt_undefined_var);
warn_set (wt_undefined_var, w_ignore);
shell = allocated_expand_variable_for_file (STRING_SIZE_TUPLE ("SHELL"), file);
#if MK_OS_W32
@ -3704,7 +3705,7 @@ construct_command_argv (char *line, char **restp, struct file *file,
ifs = allocated_expand_variable_for_file (STRING_SIZE_TUPLE ("IFS"), file);
warn_undefined_variables_flag = save;
warn_set (wt_undefined_var, save);
}
argv = construct_command_argv_internal (line, restp, shell, shellflags, ifs,

View File

@ -25,6 +25,7 @@ this program. If not, see <https://www.gnu.org/licenses/>. */
#include "debug.h"
#include "getopt.h"
#include "shuffle.h"
#include "warning.h"
#include <assert.h>
#if MK_OS_W32
@ -272,10 +273,26 @@ static struct stringlist *eval_strings = 0;
static int print_usage_flag = 0;
/* The default state of warnings. */
enum warning_state default_warnings[wt_max];
/* Current state of warnings. */
enum warning_state warnings[wt_max];
/* Global warning settings. */
enum warning_state warn_global;
/* Command line warning flags. */
static struct stringlist *warn_flags = 0;
/* If nonzero, we should print a warning message
for each reference to an undefined variable. */
int warn_undefined_variables_flag;
static int warn_undefined_variables_flag;
/* If nonzero, always build all targets, regardless of whether
they appear out of date or not. */
@ -393,7 +410,7 @@ static const char *const usage[] =
-W FILE, --what-if=FILE, --new-file=FILE, --assume-new=FILE\n\
Consider FILE to be infinitely new.\n"),
N_("\
--warn-undefined-variables Warn when an undefined variable is referenced.\n"),
--warn[=CONTROL] Control warnings for makefile issues.\n"),
NULL
};
@ -439,7 +456,8 @@ struct command_switch
Order matters here: this is the order MAKEFLAGS will be constructed.
So be sure all simple flags (single char, no argument) come first. */
#define TEMP_STDIN_OPT (CHAR_MAX+10)
#define TEMP_STDIN_OPT (CHAR_MAX+10)
#define WARN_OPT (CHAR_MAX+13)
static struct command_switch switches[] =
{
@ -498,7 +516,8 @@ static struct command_switch switches[] =
{ TEMP_STDIN_OPT, filename, &makefiles, 0, 0, 0, 0, 0, 0, "temp-stdin", 0 },
{ CHAR_MAX+11, string, &shuffle_mode, 1, 1, 0, 0, "random", 0, "shuffle", 0 },
{ CHAR_MAX+12, string, &jobserver_style, 1, 0, 0, 0, 0, 0, "jobserver-style", 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
{ WARN_OPT, strlist, &warn_flags, 1, 1, 0, 0, "warn", NULL, "warn", NULL },
{ 0, 0, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL }
};
/* Secondary long names for options. */
@ -644,6 +663,13 @@ initialize_global_hash_tables (void)
hash_init_function_table ();
}
static void
initialize_warnings ()
{
/* All warnings must have a default. */
default_warnings[wt_undefined_var] = w_ignore;
}
/* This character map locate stop chars when parsing GNU makefiles.
Each element is true if we should stop parsing on that character. */
@ -858,6 +884,99 @@ decode_debug_flags (void)
debug_flag = 0;
}
static const char *w_state_map[w_error+1] = {NULL, "ignore", "warn", "error"};
static const char *w_name_map[wt_max] = {"undefined-var"};
#define encode_warn_state(_b,_s) variable_buffer_output (_b, w_state_map[_s], strlen (w_state_map[_s]))
#define encode_warn_name(_b,_t) variable_buffer_output (_b, w_name_map[_t], strlen (w_name_map[_t]))
static enum warning_state
decode_warn_state (const char *state, size_t length)
{
for (enum warning_state st = w_ignore; st <= w_error; ++st)
{
size_t len = strlen (w_state_map[st]);
if (length == len && strncasecmp (state, w_state_map[st], length) == 0)
return st;
}
return w_unset;
}
static enum warning_type
decode_warn_name (const char *name, size_t length)
{
for (enum warning_type wt = wt_undefined_var; wt < wt_max; ++wt)
{
size_t len = strlen (w_name_map[wt]);
if (length == len && strncasecmp (name, w_name_map[wt], length) == 0)
return wt;
}
return wt_max;
}
static void
decode_warn_flags ()
{
const char **pp;
/* */
if (warn_undefined_variables_flag)
{
warn_set (wt_undefined_var, w_warn);
warn_undefined_variables_flag = 0;
}
if (warn_flags)
for (pp=warn_flags->list; *pp; ++pp)
{
const char *p = *pp;
while (*p != '\0')
{
enum warning_state state;
/* See if the value is comma-separated. */
const char *ep = strchr (p, ',');
if (!ep)
ep = p + strlen (p);
/* If the value is just a state set it globally. */
state = decode_warn_state (p, ep - p);
if (state != w_unset)
warn_global = state;
else
{
enum warning_type type;
const char *cp = memchr (p, ':', ep - p);
if (!cp)
cp = ep;
type = decode_warn_name (p, cp - p);
if (type == wt_max)
ONS (fatal, NILF,
_("unknown warning '%.*s'"), (int)(cp - p), p);
/* If there's a warning state, decode it. */
if (cp == ep)
state = w_warn;
else
{
++cp;
state = decode_warn_state (cp, ep - cp);
if (state == w_unset)
ONS (fatal, NILF,
_("unknown warning state '%.*s'"), (int)(ep - cp), cp);
}
warn_set (type, state);
}
p = ep;
while (*p == ',')
++p;
}
}
}
static void
decode_output_sync_flags (void)
{
@ -1198,7 +1317,9 @@ main (int argc, char **argv, char **envp)
output_init (&make_sync);
initialize_stopchar_map();
initialize_stopchar_map ();
initialize_warnings ();
#ifdef SET_STACK_SIZE
/* Get rid of any avoidable limit on stack size. */
@ -3205,8 +3326,9 @@ decode_switches (int argc, const char **argv, enum variable_origin origin)
}
/* Filter out duplicate options.
* Allow duplicate makefiles for backward compatibility. */
if (cs->c != 'f')
Order matters for warnings.
Allow duplicate makefiles for backward compatibility. */
if (cs->c != 'f' && cs->c != WARN_OPT)
{
unsigned int k;
for (k = 0; k < sl->idx; ++k)
@ -3317,6 +3439,7 @@ decode_switches (int argc, const char **argv, enum variable_origin origin)
/* If there are any options that need to be decoded do it now. */
decode_debug_flags ();
decode_warn_flags ();
decode_output_sync_flags ();
/* Perform any special switch handling. */
@ -3527,20 +3650,54 @@ define_makeflags (int makefile)
case filename:
case strlist:
{
struct stringlist *sl = *(struct stringlist **) cs->value_ptr;
if (sl != 0)
{
unsigned int i;
for (i = 0; i < sl->idx; ++i)
if (cs->c == WARN_OPT)
{
enum warning_type wt;
char sp = '=';
/* See if any warning options are set. */
for (wt = 0; wt < wt_max; ++wt)
if (warnings[wt] != w_unset)
break;
if (wt == wt_max && warn_global == w_unset)
break;
/* Something is set so construct a --warn option. */
fp = variable_buffer_output(fp, STRING_SIZE_TUPLE (" --warn"));
if (wt == wt_max && warn_global == w_warn)
break;
if (warn_global > w_unset)
{
fp = variable_buffer_output (fp, &sp, 1);
sp = ',';
fp = encode_warn_state (fp, warn_global);
}
for (wt = 0; wt < wt_max; ++wt)
if (warnings[wt] > w_unset)
{
ADD_OPT (cs);
if (!short_option (cs->c))
fp = variable_buffer_output (fp, "=", 1);
fp = variable_buffer_output (fp, sl->list[i], strlen (sl->list[i]));
fp = variable_buffer_output (fp, &sp, 1);
sp = ',';
fp = encode_warn_name (fp, wt);
if (warnings[wt] != w_warn)
fp = encode_warn_state (variable_buffer_output(fp, ":", 1), warnings[wt]);
}
}
}
}
else
{
struct stringlist *sl = *(struct stringlist **) cs->value_ptr;
if (sl != 0)
{
unsigned int i;
for (i = 0; i < sl->idx; ++i)
{
ADD_OPT (cs);
if (!short_option (cs->c))
fp = variable_buffer_output (fp, "=", 1);
fp = variable_buffer_output (fp, sl->list[i], strlen (sl->list[i]));
}
}
}
break;
default:

View File

@ -738,10 +738,10 @@ extern unsigned short stopchar_map[];
extern int just_print_flag, run_silent, ignore_errors_flag, keep_going_flag;
extern int print_data_base_flag, question_flag, touch_flag, always_make_flag;
extern int env_overrides, no_builtin_rules_flag, no_builtin_variables_flag;
extern int print_version_flag, check_symlink_flag, export_all_variables;
extern int warn_undefined_variables_flag, posix_pedantic;
extern int print_version_flag, check_symlink_flag, posix_pedantic;
extern int not_parallel, second_expansion, clock_skew_detected;
extern int rebuilding_makefiles, one_shell, output_sync, verify_flag;
extern int export_all_variables;
extern unsigned long command_count;
extern const char *default_shell;

View File

@ -27,7 +27,7 @@ this program. If not, see <https://www.gnu.org/licenses/>. */
#include "rule.h"
#include "debug.h"
#include "hash.h"
#include "warning.h"
#if MK_OS_W32
# include <windows.h>
@ -3067,13 +3067,13 @@ tilde_expand (const char *name)
int is_variable;
{
/* Turn off --warn-undefined-variables while we expand HOME. */
int save = warn_undefined_variables_flag;
warn_undefined_variables_flag = 0;
/* Turn off undefined variables warning while we expand HOME. */
enum warning_state save = warn_get (wt_undefined_var);
warn_set (wt_undefined_var, w_ignore);
home_dir = allocated_expand_variable (STRING_SIZE_TUPLE ("HOME"));
warn_undefined_variables_flag = save;
warn_set (wt_undefined_var, save);
}
is_variable = home_dir[0] != '\0';

View File

@ -30,6 +30,7 @@ this program. If not, see <https://www.gnu.org/licenses/>. */
#include "pathstuff.h"
#endif
#include "hash.h"
#include "warning.h"
/* Incremented every time we enter target_environment(). */
unsigned long long env_recursion = 0;
@ -1868,15 +1869,19 @@ static const struct defined_vars defined_vars[] = {
void
warn_undefined (const char *name, size_t len)
{
if (warn_undefined_variables_flag)
if (warn_check (wt_undefined_var))
{
const struct defined_vars *dp;
for (dp = defined_vars; dp->name != NULL; ++dp)
if (dp->len == len && memcmp (dp->name, name, len) == 0)
return;
error (reading_file, len, _("warning: undefined variable '%.*s'"),
(int)len, name);
if (warn_error (wt_undefined_var))
fatal (reading_file, len, _("reference to undefined variable '%.*s'"),
(int)len, name);
else
error (reading_file, len, _("reference to undefined variable '%.*s'"),
(int)len, name);
}
}

60
src/warning.h Normal file
View File

@ -0,0 +1,60 @@
/* Control warning output in GNU Make.
Copyright (C) 2023 Free Software Foundation, Inc.
This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3 of the License, or (at your option) any later
version.
GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see <https://www.gnu.org/licenses/>. */
/* Types of warnings we can show. */
enum warning_type
{
wt_undefined_var = 0, /* Reference an undefined variable name. */
wt_max
};
/* State of a given warning. */
enum warning_state
{
w_unset = 0,
w_ignore,
w_warn,
w_error
};
/* The default state of warnings. */
extern enum warning_state default_warnings[wt_max];
/* Current state of warnings. */
extern enum warning_state warnings[wt_max];
/* Global warning settings. */
extern enum warning_state warn_global;
/* Get the current state of a given warning. */
#define warn_get(_w) (warnings[_w] != w_unset ? warnings[_w] \
: warn_global != w_unset ? warn_global \
: default_warnings[_w])
/* Set the current state of a given warning. Can't use w_unset here. */
#define warn_set(_w,_f) do{ warnings[_w] = (_f); } while (0)
/* True if we should check for the warning in the first place. */
#define warn_check(_w) (warn_get (_w) > w_ignore)
/* Check if the warning is ignored. */
#define warn_ignored(_w) (warn_get (_w) == w_ignore)
/* Check if the warning is in "warn" mode. */
#define warn_warned(_w) (warn_get (_w) == w_warn)
/* Check if the warning is in "error" mode. */
#define warn_error(_w) (warn_get (_w) == w_error)

View File

@ -0,0 +1,86 @@
# -*-perl-*-
$description = "Test the --warn option.";
my %warn_test = (
'--warn' => '', '--warn=warn' => '', '--warn=error --warn=warn' => '',
'--warn --warn=error' => '=error',
'--warn=ignore --warn=error --warn=ignore --warn=undefined-var' => '=ignore,undefined-var',
'--warn=undefined-var:error --warn' => '=warn,undefined-var:error'
);
# Verify the deprecated --warn-undefined-variables option
run_make_test(q!
$(info MF=$(MAKEFLAGS))
all:; @#HELPER# env MAKEFLAGS
!,
'--warn-undefined-variables', "MF= --warn=undefined-var\nMAKEFLAGS= --warn=undefined-var");
# Verify parsing of --warn in various forms.
while (my ($f, $r) = each %warn_test) {
run_make_test(undef, $f, "MF= --warn$r\nMAKEFLAGS= --warn$r");
}
# Verify that values set in MAKEFLAGS take effect
while (my ($f, $r) = each %warn_test) {
run_make_test(qq!
MAKEFLAGS += $f
\$(info MF=\$(MAKEFLAGS))
all:; \@#HELPER# env MAKEFLAGS
!,
'', "MF= --warn$r\nMAKEFLAGS= --warn$r");
}
# Verify that make's special variables don't warn even if they're not set
run_make_test(q!
vars := $(.VARIABLES) $(MAKECMDGOALS) $(MAKE_RESTARTS) $(CURDIR)
vars += $(GNUMAKEFLAGS) $(MAKEFLAGS) $(MFLAGS) $(MAKE_COMMAND) $(MAKE)
vars += $(MAKEFILE_LIST) $(MAKEOVERRIDES) $(-*-command-variables-*-)
vars += $(.RECIPEPREFIX) $(.LOADED) $(.FEATURES)
vars += $(SHELL) $(.SHELLFLAGS) $(MAKE_TERMOUT) $(MAKE_TERMERR)
vars += $(.DEFAULT) $(.DEFAULT_GOAL) $(-*-eval-flags-*-) $(SUFFIXES)
vars += $(VPATH) $(GPATH)
all:;
!,
'--warn=undefined-var', "#MAKE#: 'all' is up to date.");
# sv 63609.
# Test for buffer overrun in warn_undefined.
run_make_test(q!
all:;
X := $(averyveryveryloooooooooooooooooooooooooooongvariablename)
!,
'--warn=undefined-var',
"#MAKEFILE#:3: reference to undefined variable 'averyveryveryloooooooooooooooooooooooooooongvariablename'
#MAKE#: 'all' is up to date.\n"
);
# Check undefined variable warnings
# With no options or with ignore, nothing should happen
run_make_test('
EMPTY =
EREF = $(EMPTY)
UREF = $(UNDEFINED)
SEREF := $(EREF)
SUREF := $(UREF)
all: ; @echo ref $(EREF) $(UREF)',
'', 'ref');
run_make_test(undef, '--warn=undefined-var:ignore', 'ref');
# Check warnings
run_make_test(undef, '--warn=undefined-var',
"#MAKEFILE#:7: reference to undefined variable 'UNDEFINED'
#MAKEFILE#:9: reference to undefined variable 'UNDEFINED'
ref");
# Check and errors
run_make_test(undef, '--warn=undefined-var:error',
"#MAKEFILE#:7: *** reference to undefined variable 'UNDEFINED'. Stop.", 512);
1;

View File

@ -1,49 +0,0 @@
# -*-perl-*-
$description = "Test the --warn-undefined-variables option.";
$details = "Verify that warnings are printed for referencing undefined variables.";
# Verify that make's special variables don't warn even if they're not set
run_make_test(q!
vars := $(.VARIABLES) $(MAKECMDGOALS) $(MAKE_RESTARTS) $(CURDIR)
vars += $(GNUMAKEFLAGS) $(MAKEFLAGS) $(MFLAGS) $(MAKE_COMMAND) $(MAKE)
vars += $(MAKEFILE_LIST) $(MAKEOVERRIDES) $(-*-command-variables-*-)
vars += $(.RECIPEPREFIX) $(.LOADED) $(.FEATURES)
vars += $(SHELL) $(.SHELLFLAGS) $(MAKE_TERMOUT) $(MAKE_TERMERR)
vars += $(.DEFAULT) $(.DEFAULT_GOAL) $(-*-eval-flags-*-) $(SUFFIXES)
vars += $(VPATH) $(GPATH)
all:;
!,
'--warn-undefined-variables', "#MAKE#: 'all' is up to date.");
# Without --warn-undefined-variables, nothing should happen
run_make_test('
EMPTY =
EREF = $(EMPTY)
UREF = $(UNDEFINED)
SEREF := $(EREF)
SUREF := $(UREF)
all: ; @echo ref $(EREF) $(UREF)',
'', 'ref');
# With --warn-undefined-variables, it should warn me
run_make_test(undef, '--warn-undefined-variables',
"#MAKEFILE#:7: warning: undefined variable 'UNDEFINED'
#MAKEFILE#:9: warning: undefined variable 'UNDEFINED'
ref");
# sv 63609.
# Test for buffer overrun in warn_undefined.
run_make_test(q!
all:;
X := $(averyveryverylongvariablename)
!,
'--warn-undefined-variables',
"#MAKEFILE#:3: warning: undefined variable 'averyveryverylongvariablename'
#MAKE#: 'all' is up to date.\n"
);
1;

View File

@ -99,7 +99,7 @@ all:; \$(info makeflags='\$(MAKEFLAGS)')
# Long options which take no arguments.
# sv 62514.
@opts = (' --no-print-directory', ' --warn-undefined-variables', ' --trace');
@opts = (' --no-print-directory', ' --warn=undefined-var', ' --trace');
for my $fl (@flavors) {
for my $opt (@opts) {
run_make_test("
@ -139,19 +139,19 @@ all:; \$(info makeflags='\$(MAKEFLAGS)')
# A mix of multiple flags from env, the makefile and command line.
# Skip -L since it's not available everywhere
for my $fl (@flavors) {
$ENV{'MAKEFLAGS'} = 'ikB --no-print-directory --warn-undefined-variables --trace';
$ENV{'MAKEFLAGS'} = 'ikB --no-print-directory --warn=undefined-var --trace';
run_make_test("
MAKEFLAGS${fl}iknqrswd -Ilocaltmp -Ilocaltmp -Onone -Onone -l2.5 -l2.5
all:; \$(info makeflags='\$(MAKEFLAGS)')
",
'-Onone -l2.5 -l2.5 -Onone -Ilocaltmp -iknqrswd -i -n -s -k -Ilocaltmp',
"/makeflags='Bdiknqrsw -Ilocaltmp -l2.5 -Onone --trace --warn-undefined-variables'/");
"/makeflags='Bdiknqrsw -Ilocaltmp -l2.5 -Onone --trace --warn=undefined-var'/");
}
# Verify MAKEFLAGS are all available to shell function at parse time.
for my $fl (@flavors) {
my $answer = 'Biknqrs -Ilocaltmp -l2.5 -Onone --no-print-directory --warn-undefined-variables';
$ENV{'MAKEFLAGS'} = 'ikB --no-print-directory --warn-undefined-variables';
my $answer = 'Biknqrs -Ilocaltmp -l2.5 -Onone --no-print-directory --warn=undefined-var';
$ENV{'MAKEFLAGS'} = 'ikB --no-print-directory --warn=undefined-var';
run_make_test("
MAKEFLAGS${fl}iknqrsw -Ilocaltmp -Ilocaltmp -Onone -Onone -l2.5 -l2.5 --no-print-directory
\$(info at parse time '\$(MAKEFLAGS)')
@ -165,8 +165,8 @@ at build time makeflags='$answer'");
# Verify MAKEFLAGS and command line definitions are all available to shell function at parse time.
for my $fl (@flavors) {
$ENV{'MAKEFLAGS'} = 'ikB --no-print-directory --warn-undefined-variables';
my $answer = 'Biknqrs -Ilocaltmp -l2.5 -Onone --no-print-directory --warn-undefined-variables -- hello=world';
$ENV{'MAKEFLAGS'} = 'ikB --no-print-directory --warn=undefined-var';
my $answer = 'Biknqrs -Ilocaltmp -l2.5 -Onone --no-print-directory --warn=undefined-var -- hello=world';
run_make_test("
MAKEFLAGS${fl}iknqrsw -Ilocaltmp -Ilocaltmp -Onone -Onone -l2.5 -l2.5 --no-print-directory
\$(info at parse time '\$(MAKEFLAGS)')