summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Smith <psmith@gnu.org>2023-02-26 18:04:14 -0500
committerPaul Smith <psmith@gnu.org>2023-04-01 11:13:12 -0400
commit2611e1991fabe2a3ae929c6ebd4afbd4f550f306 (patch)
tree0733d2ff7f545c8ba0b4c032a309cde459dfdfce
parent9db74434cd34b2b875b3f9bfbab4f1e0b682e27c (diff)
downloadmake-git-2611e1991fabe2a3ae929c6ebd4afbd4f550f306.tar.gz
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.
-rw-r--r--Makefile.am2
-rw-r--r--NEWS9
-rw-r--r--doc/make.130
-rw-r--r--doc/make.texi81
-rw-r--r--src/job.c9
-rw-r--r--src/main.c195
-rw-r--r--src/makeint.h4
-rw-r--r--src/read.c10
-rw-r--r--src/variable.c11
-rw-r--r--src/warning.h60
-rw-r--r--tests/scripts/options/warn86
-rw-r--r--tests/scripts/options/warn-undefined-variables49
-rw-r--r--tests/scripts/variables/MAKEFLAGS14
13 files changed, 462 insertions, 98 deletions
diff --git a/Makefile.am b/Makefile.am
index 49bc06bb..8741b562 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -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 \
diff --git a/NEWS b/NEWS
index 683ab115..ad56d660 100644
--- a/NEWS
+++ b/NEWS
@@ -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)
diff --git a/doc/make.1 b/doc/make.1
index f02afbee..933a8273 100644
--- a/doc/make.1
+++ b/doc/make.1
@@ -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
diff --git a/doc/make.texi b/doc/make.texi
index aa488eb7..31db623b 100644
--- a/doc/make.texi
+++ b/doc/make.texi
@@ -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
diff --git a/src/job.c b/src/job.c
index d7b584f5..b26cb2ca 100644
--- a/src/job.c
+++ b/src/job.c
@@ -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,
diff --git a/src/main.c b/src/main.c
index bf74ab94..221870ab 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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:
diff --git a/src/makeint.h b/src/makeint.h
index 00f72190..e130e761 100644
--- a/src/makeint.h
+++ b/src/makeint.h
@@ -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;
diff --git a/src/read.c b/src/read.c
index 2d25be6a..6913928f 100644
--- a/src/read.c
+++ b/src/read.c
@@ -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';
diff --git a/src/variable.c b/src/variable.c
index e2a529de..f1911759 100644
--- a/src/variable.c
+++ b/src/variable.c
@@ -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);
}
}
diff --git a/src/warning.h b/src/warning.h
new file mode 100644
index 00000000..778ee407
--- /dev/null
+++ b/src/warning.h
@@ -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)
diff --git a/tests/scripts/options/warn b/tests/scripts/options/warn
new file mode 100644
index 00000000..98155d46
--- /dev/null
+++ b/tests/scripts/options/warn
@@ -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;
diff --git a/tests/scripts/options/warn-undefined-variables b/tests/scripts/options/warn-undefined-variables
deleted file mode 100644
index d9653d2c..00000000
--- a/tests/scripts/options/warn-undefined-variables
+++ /dev/null
@@ -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;
diff --git a/tests/scripts/variables/MAKEFLAGS b/tests/scripts/variables/MAKEFLAGS
index 32c2ede8..fc18d650 100644
--- a/tests/scripts/variables/MAKEFLAGS
+++ b/tests/scripts/variables/MAKEFLAGS
@@ -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)')