From 2611e1991fabe2a3ae929c6ebd4afbd4f550f306 Mon Sep 17 00:00:00 2001 From: Paul Smith Date: Sun, 26 Feb 2023 18:04:14 -0500 Subject: 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. --- Makefile.am | 2 +- NEWS | 9 +- doc/make.1 | 30 +++- doc/make.texi | 81 +++++++++- src/job.c | 9 +- src/main.c | 195 ++++++++++++++++++++++--- src/makeint.h | 4 +- src/read.c | 10 +- src/variable.c | 11 +- src/warning.h | 60 ++++++++ tests/scripts/options/warn | 86 +++++++++++ tests/scripts/options/warn-undefined-variables | 49 ------- tests/scripts/variables/MAKEFLAGS | 14 +- 13 files changed, 462 insertions(+), 98 deletions(-) create mode 100644 src/warning.h create mode 100644 tests/scripts/options/warn delete mode 100644 tests/scripts/options/warn-undefined-variables 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 . */ #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 . */ #include "debug.h" #include "getopt.h" #include "shuffle.h" +#include "warning.h" #include #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 . */ #include "rule.h" #include "debug.h" #include "hash.h" - +#include "warning.h" #if MK_OS_W32 # include @@ -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 . */ #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 . */ + +/* 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)') -- cgit v1.2.1