mirror of
https://github.com/mirror/make.git
synced 2024-12-27 13:20:34 +08:00
Add support for .WARNINGS special variable
Create a new special variable, .WARNINGS, to allow per-makefile control over warnings. The command line settings will override this. Move the handling of warning flags to a new file: src/warning.c. Allow the decode to work with generic strings, and call it from decode_switches(). * Makefile.am: Add new file src/warning.c. * build_w32.bat: Ditto. * builddos.bat: Ditto. * po/POTFILES.in: Ditto. * src/makeint.h: #define for the .WARNINGS variable name. * src/warning.h: Add declarations for methods moved from main.c. Rename the enum warning_state to warning_action. * src/warning.c: New file. Move all warning encode/decode here from main.c. * src/main.c: Move methods into warning.c and call those methods instead. (main): Set .WARNINGS as a special variable. * src/job.c (construct_command_argv): Rename to warning_action. * src/read.c (tilde_expand): Ditto. * src/variable.c (set_special_var): Update warnings when the .WARNINGS special variable is set. * tests/scripts/options/warn: Check invalid warning options. * tests/scripts/variables/WARNINGS: Add tests for the .WARNINGS special variable.
This commit is contained in:
parent
03ecd94488
commit
a0d1e76d60
@ -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/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/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/signame.c src/strcache.c src/variable.c src/variable.h \
|
||||||
src/version.c src/vpath.c src/warning.h
|
src/version.c src/vpath.c src/warning.c src/warning.h
|
||||||
|
|
||||||
w32_SRCS = src/w32/pathstuff.c src/w32/w32os.c src/w32/compat/dirent.c \
|
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 \
|
src/w32/compat/posixfcn.c src/w32/include/dirent.h \
|
||||||
|
@ -271,6 +271,7 @@ call :Compile src/strcache
|
|||||||
call :Compile src/variable
|
call :Compile src/variable
|
||||||
call :Compile src/version
|
call :Compile src/version
|
||||||
call :Compile src/vpath
|
call :Compile src/vpath
|
||||||
|
call :Compile src/warning
|
||||||
call :Compile src/w32/pathstuff
|
call :Compile src/w32/pathstuff
|
||||||
call :Compile src/w32/w32os
|
call :Compile src/w32/w32os
|
||||||
call :Compile src/w32/compat/posixfcn
|
call :Compile src/w32/compat/posixfcn
|
||||||
|
@ -56,6 +56,7 @@ gcc -c -I./src -I%XSRC%/src -I./lib -I%XSRC%/lib -DHAVE_CONFIG_H -O2 -g %XSRC%/s
|
|||||||
gcc -c -I./src -I%XSRC%/src -I./lib -I%XSRC%/lib -DHAVE_CONFIG_H -O2 -g %XSRC%/src/implicit.c -o implicit.o
|
gcc -c -I./src -I%XSRC%/src -I./lib -I%XSRC%/lib -DHAVE_CONFIG_H -O2 -g %XSRC%/src/implicit.c -o implicit.o
|
||||||
gcc -c -I./src -I%XSRC%/src -I./lib -I%XSRC%/lib -DHAVE_CONFIG_H -O2 -g %XSRC%/src/default.c -o default.o
|
gcc -c -I./src -I%XSRC%/src -I./lib -I%XSRC%/lib -DHAVE_CONFIG_H -O2 -g %XSRC%/src/default.c -o default.o
|
||||||
gcc -c -I./src -I%XSRC%/src -I./lib -I%XSRC%/lib -DHAVE_CONFIG_H -O2 -g %XSRC%/src/variable.c -o variable.o
|
gcc -c -I./src -I%XSRC%/src -I./lib -I%XSRC%/lib -DHAVE_CONFIG_H -O2 -g %XSRC%/src/variable.c -o variable.o
|
||||||
|
gcc -c -I./src -I%XSRC%/src -I./lib -I%XSRC%/lib -DHAVE_CONFIG_H -O2 -g %XSRC%/src/warning.c -o warning.o
|
||||||
gcc -c -I./src -I%XSRC%/src -I./lib -I%XSRC%/lib -DHAVE_CONFIG_H -O2 -g %XSRC%/src/expand.c -o expand.o
|
gcc -c -I./src -I%XSRC%/src -I./lib -I%XSRC%/lib -DHAVE_CONFIG_H -O2 -g %XSRC%/src/expand.c -o expand.o
|
||||||
gcc -c -I./src -I%XSRC%/src -I./lib -I%XSRC%/lib -DHAVE_CONFIG_H -O2 -g %XSRC%/src/function.c -o function.o
|
gcc -c -I./src -I%XSRC%/src -I./lib -I%XSRC%/lib -DHAVE_CONFIG_H -O2 -g %XSRC%/src/function.c -o function.o
|
||||||
gcc -c -I./src -I%XSRC%/src -I./lib -I%XSRC%/lib -DHAVE_CONFIG_H -O2 -g %XSRC%/src/vpath.c -o vpath.o
|
gcc -c -I./src -I%XSRC%/src -I./lib -I%XSRC%/lib -DHAVE_CONFIG_H -O2 -g %XSRC%/src/vpath.c -o vpath.o
|
||||||
@ -74,7 +75,7 @@ gcc -c -I./src -I%XSRC%/src -I./lib -I%XSRC%/lib -DHAVE_CONFIG_H -O2 -g %XSRC%/l
|
|||||||
gcc -c -I./src -I%XSRC%/src -I./lib -I%XSRC%/lib -DHAVE_CONFIG_H -O2 -g %XSRC%/lib/fnmatch.c -o lib/fnmatch.o
|
gcc -c -I./src -I%XSRC%/src -I./lib -I%XSRC%/lib -DHAVE_CONFIG_H -O2 -g %XSRC%/lib/fnmatch.c -o lib/fnmatch.o
|
||||||
@echo off
|
@echo off
|
||||||
echo commands.o > respf.$$$
|
echo commands.o > respf.$$$
|
||||||
for %%f in (job output dir file misc main read remake rule implicit default variable load) do echo %%f.o >> respf.$$$
|
for %%f in (job output dir file misc main read remake rule implicit default variable warning load) do echo %%f.o >> respf.$$$
|
||||||
for %%f in (expand function vpath hash strcache version ar arscan signame remote-stub getopt getopt1 shuffle) do echo %%f.o >> respf.$$$
|
for %%f in (expand function vpath hash strcache version ar arscan signame remote-stub getopt getopt1 shuffle) do echo %%f.o >> respf.$$$
|
||||||
for %%f in (lib\glob lib\fnmatch) do echo %%f.o >> respf.$$$
|
for %%f in (lib\glob lib\fnmatch) do echo %%f.o >> respf.$$$
|
||||||
gcc -c -I./src -I%XSRC%/src -I./lib -I%XSRC%/lib -DHAVE_CONFIG_H -O2 -g %XSRC%/src/guile.c -o guile.o
|
gcc -c -I./src -I%XSRC%/src -I./lib -I%XSRC%/lib -DHAVE_CONFIG_H -O2 -g %XSRC%/src/guile.c -o guile.o
|
||||||
|
131
doc/make.texi
131
doc/make.texi
@ -7043,6 +7043,10 @@ a target-specific value). Note @code{make} is smart enough not to add
|
|||||||
a prerequisite listed in @code{.EXTRA_PREREQS} as a prerequisite to
|
a prerequisite listed in @code{.EXTRA_PREREQS} as a prerequisite to
|
||||||
itself.
|
itself.
|
||||||
|
|
||||||
|
@item .WARNINGS
|
||||||
|
Changes the actions taken when @code{make} detects warning conditions in the
|
||||||
|
makefile. @xref{Warnings, ,Makefile Warnings}.
|
||||||
|
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
@node Conditionals, Functions, Using Variables, Top
|
@node Conditionals, Functions, Using Variables, Top
|
||||||
@ -9309,69 +9313,108 @@ correct them all before the next attempt to compile. This is why Emacs'
|
|||||||
@section Makefile Warnings
|
@section Makefile Warnings
|
||||||
@cindex warnings
|
@cindex warnings
|
||||||
|
|
||||||
GNU Make can detect some types of incorrect usage in makefiles and show
|
GNU Make can detect some types of incorrect usage in makefiles. When one of
|
||||||
warnings about them. Currently these issues can be detected:
|
these incorrect usages is detected, GNU Make can perform one of these actions:
|
||||||
|
|
||||||
@table @samp
|
|
||||||
@item invalid-var
|
|
||||||
Assigning to an invalid variable name (e.g., a name containing whitespace).
|
|
||||||
|
|
||||||
@item invalid-ref
|
|
||||||
Using an invalid variable name in a variable reference.
|
|
||||||
|
|
||||||
@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
|
@table @samp
|
||||||
@item ignore
|
@item ignore
|
||||||
|
@cindex warning action ignore
|
||||||
|
@cindex ignore, warning action
|
||||||
Ignore the usage.
|
Ignore the usage.
|
||||||
|
|
||||||
@item warn
|
@item warn
|
||||||
|
@cindex warning action warn
|
||||||
|
@cindex warn, warning action
|
||||||
Show a warning about the usage and continue processing the makefile.
|
Show a warning about the usage and continue processing the makefile.
|
||||||
|
|
||||||
@item error
|
@item error
|
||||||
|
@cindex warning action error
|
||||||
|
@cindex error, warning action
|
||||||
Show an error for the usage and immediately stop processing the makefile.
|
Show an error for the usage and immediately stop processing the makefile.
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
The default action of GNU Make when no warning control options are provided
|
@noindent
|
||||||
is @samp{ignore} for @samp{undefined-var}, and @samp{warn} for
|
The types of warnings GNU Make can detect are:
|
||||||
@samp{invalid-var} and @samp{invalid-ref}.
|
|
||||||
|
|
||||||
To modify this default behavior, you can use the @code{--warn} option. This
|
@table @samp
|
||||||
option can be specified on the command line, or by adding it to the
|
@item invalid-var
|
||||||
@code{MAKEFLAGS} variable (@pxref{Recursion, ,Recursive Use of @code{make}}).
|
@findex invalid-var
|
||||||
Settings added to @code{MAKEFLAGS} are only affect after the assignment
|
@cindex warning invalid variable
|
||||||
statement.
|
Assigning to an invalid variable name (e.g., a name containing whitespace).
|
||||||
|
The default action is @samp{warn}.
|
||||||
|
|
||||||
|
@item invalid-ref
|
||||||
|
@findex invalid-ref
|
||||||
|
@cindex warning invalid reference
|
||||||
|
Using an invalid variable name in a variable reference. The default action is
|
||||||
|
@samp{warn}.
|
||||||
|
|
||||||
|
@item undefined-var
|
||||||
|
@findex undefined-var
|
||||||
|
@cindex warning undefined variable
|
||||||
|
Referencing a variable that has not been defined. The default action is
|
||||||
|
@samp{ignore}. Note the deprecated @code{--warn-undefined-variables} option
|
||||||
|
sets the action for this warning to @samp{warn}.
|
||||||
|
@end table
|
||||||
|
|
||||||
|
The actions for these warnings can be changed by specifying warning control
|
||||||
|
options. Each warning control option consists of either a warning type, or a
|
||||||
|
warning action, or a warning type and warning action separated by a colon
|
||||||
|
(@code{:}). Multiple control options are separated by either whitespace or
|
||||||
|
commas.
|
||||||
|
|
||||||
|
If the control option is just a warning type, then the action associated with
|
||||||
|
that type is set to @code{warn}. If the option is just an action, then that
|
||||||
|
action is applied to all warning types (a ``global action'').
|
||||||
|
|
||||||
|
``Global actions'' take precedence over default actions. Actions associated
|
||||||
|
with a specific warning type take precedence over ``global actions'' and
|
||||||
|
default actions.
|
||||||
|
|
||||||
|
If multiple control options provide actions for the same warning type, the
|
||||||
|
last action specified will be used.
|
||||||
|
|
||||||
|
There are two ways to specify control options: using the @code{--warn} command
|
||||||
|
line option, or using the @code{.WARNINGS} variable.
|
||||||
|
|
||||||
|
@subsubheading The @code{.WARNINGS} variable
|
||||||
|
@findex .WARNINGS
|
||||||
|
Warning control options provided in the @code{.WARNINGS} variable take effect
|
||||||
|
as soon as the variable assignment is parsed and will last until this instance
|
||||||
|
of @code{make} finishes parsing all makefiles. These settings will not be
|
||||||
|
passed to recursive invocations of @code{make}.
|
||||||
|
|
||||||
|
Note that the value of this variable is expanded immediately, even if the
|
||||||
|
recursive expansion assignment operator (@code{=}) is used.
|
||||||
|
|
||||||
|
Each assignment of @code{.WARNINGS} completely replaces any previous settings.
|
||||||
|
If you want to preserve the previous settings, use the @code{+=} assignment
|
||||||
|
operator.
|
||||||
|
|
||||||
|
Currently, assigning @code{.WARNINGS} as a target-specific or pattern-specific
|
||||||
|
variable has no effect. This may change in the future.
|
||||||
|
|
||||||
|
@subsubheading The @code{--warn} option
|
||||||
|
@cindex @code{--warn}
|
||||||
|
The @code{--warn} 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} take affect after the
|
||||||
|
assignment is parsed. This option is passed to sub-makes through the
|
||||||
|
@code{MAKEFLAGS} variable.
|
||||||
|
|
||||||
The @code{--warn} option can be provided multiple times: the effects are
|
The @code{--warn} option can be provided multiple times: the effects are
|
||||||
cumulative with later options overriding over earlier options. When GNU Make
|
cumulative with later options overriding over earlier options. When GNU Make
|
||||||
provides warning settings to sub-makes, they are all combined into a single
|
provides warning settings to sub-makes, they are all combined into a single
|
||||||
@code{--warn} option in @code{MAKEFLAGS}.
|
@code{--warn} option in @code{MAKEFLAGS} with a standard order.
|
||||||
|
|
||||||
If @code{--warn} is provided with no arguments then all issues are detected
|
Specifying @code{--warn} with no arguments is equivalent to using
|
||||||
and reported at the @samp{warn} level unless otherwise specified.
|
@code{--warn=warn}, which sets the action for all warning types to
|
||||||
|
@samp{warn}.
|
||||||
|
|
||||||
If one of the actions (@samp{ignore}, @samp{warn}, @samp{error}) is provided
|
Any action specified with an @code{--warn} option will take precedence over
|
||||||
as an argument to @code{--warn}, then this action becomes the default for all
|
actions provided in the makefile with @code{.WARNINGS}. This means if you use
|
||||||
warning types. For example all warnings can be disabled by using
|
@code{--warn=error}, for example, all warnings will be treated as errors
|
||||||
@code{--warn=ignore}, or all warnings can be considered fatal errors by using
|
regardless of any @code{.WARNINGS} assignments.
|
||||||
@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
|
@node Temporary Files, Options Summary, Warnings, Running
|
||||||
@section Temporary Files
|
@section Temporary Files
|
||||||
|
@ -45,4 +45,5 @@ src/variable.h
|
|||||||
src/vmsfunctions.c
|
src/vmsfunctions.c
|
||||||
src/vmsjobs.c
|
src/vmsjobs.c
|
||||||
src/vpath.c
|
src/vpath.c
|
||||||
|
src/warning.c
|
||||||
src/w32/w32os.c
|
src/w32/w32os.c
|
||||||
|
@ -24,6 +24,7 @@ this program. If not, see <https://www.gnu.org/licenses/>. */
|
|||||||
#include "job.h"
|
#include "job.h"
|
||||||
#include "variable.h"
|
#include "variable.h"
|
||||||
#include "rule.h"
|
#include "rule.h"
|
||||||
|
#include "warning.h"
|
||||||
|
|
||||||
/* Initially, any errors reported when expanding strings will be reported
|
/* Initially, any errors reported when expanding strings will be reported
|
||||||
against the file where the error appears. */
|
against the file where the error appears. */
|
||||||
|
@ -3635,7 +3635,7 @@ construct_command_argv (char *line, char **restp, struct file *file,
|
|||||||
{
|
{
|
||||||
struct variable *var;
|
struct variable *var;
|
||||||
/* Turn off undefined variables warning while we expand HOME. */
|
/* Turn off undefined variables warning while we expand HOME. */
|
||||||
enum warning_state save = warn_get (wt_undefined_var);
|
enum warning_action save = warn_get (wt_undefined_var);
|
||||||
warn_set (wt_undefined_var, w_ignore);
|
warn_set (wt_undefined_var, w_ignore);
|
||||||
|
|
||||||
shell = allocated_expand_variable_for_file (STRING_SIZE_TUPLE ("SHELL"), file);
|
shell = allocated_expand_variable_for_file (STRING_SIZE_TUPLE ("SHELL"), file);
|
||||||
|
166
src/main.c
166
src/main.c
@ -273,18 +273,6 @@ static struct stringlist *eval_strings = 0;
|
|||||||
|
|
||||||
static int print_usage_flag = 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. */
|
/* Command line warning flags. */
|
||||||
|
|
||||||
static struct stringlist *warn_flags = 0;
|
static struct stringlist *warn_flags = 0;
|
||||||
@ -663,15 +651,6 @@ initialize_global_hash_tables (void)
|
|||||||
hash_init_function_table ();
|
hash_init_function_table ();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
initialize_warnings ()
|
|
||||||
{
|
|
||||||
/* All warnings must have a default. */
|
|
||||||
default_warnings[wt_invalid_var] = w_warn;
|
|
||||||
default_warnings[wt_invalid_ref] = w_warn;
|
|
||||||
default_warnings[wt_undefined_var] = w_ignore;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This character map locate stop chars when parsing GNU makefiles.
|
/* This character map locate stop chars when parsing GNU makefiles.
|
||||||
Each element is true if we should stop parsing on that character. */
|
Each element is true if we should stop parsing on that character. */
|
||||||
|
|
||||||
@ -886,101 +865,6 @@ decode_debug_flags (void)
|
|||||||
debug_flag = 0;
|
debug_flag = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *w_state_map[w_error+1] = {NULL, "ignore", "warn", "error"};
|
|
||||||
static const char *w_name_map[wt_max] = {"invalid-var",
|
|
||||||
"invalid-ref",
|
|
||||||
"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_invalid_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
|
static void
|
||||||
decode_output_sync_flags (void)
|
decode_output_sync_flags (void)
|
||||||
{
|
{
|
||||||
@ -1323,7 +1207,7 @@ main (int argc, char **argv, char **envp)
|
|||||||
|
|
||||||
initialize_stopchar_map ();
|
initialize_stopchar_map ();
|
||||||
|
|
||||||
initialize_warnings ();
|
warn_init ();
|
||||||
|
|
||||||
#ifdef SET_STACK_SIZE
|
#ifdef SET_STACK_SIZE
|
||||||
/* Get rid of any avoidable limit on stack size. */
|
/* Get rid of any avoidable limit on stack size. */
|
||||||
@ -1554,6 +1438,7 @@ main (int argc, char **argv, char **envp)
|
|||||||
define_variable_cname (".VARIABLES", "", o_default, 0)->special = 1;
|
define_variable_cname (".VARIABLES", "", o_default, 0)->special = 1;
|
||||||
/* define_variable_cname (".TARGETS", "", o_default, 0)->special = 1; */
|
/* define_variable_cname (".TARGETS", "", o_default, 0)->special = 1; */
|
||||||
define_variable_cname (".RECIPEPREFIX", "", o_default, 0)->special = 1;
|
define_variable_cname (".RECIPEPREFIX", "", o_default, 0)->special = 1;
|
||||||
|
define_variable_cname (WARNINGS_NAME, "", o_default, 0)->special = 1;
|
||||||
define_variable_cname (".SHELLFLAGS", "-c", o_default, 0);
|
define_variable_cname (".SHELLFLAGS", "-c", o_default, 0);
|
||||||
define_variable_cname (".LOADED", "", o_default, 0);
|
define_variable_cname (".LOADED", "", o_default, 0);
|
||||||
|
|
||||||
@ -3013,7 +2898,7 @@ main (int argc, char **argv, char **envp)
|
|||||||
/* If we detected some clock skew, generate one last warning */
|
/* If we detected some clock skew, generate one last warning */
|
||||||
if (clock_skew_detected)
|
if (clock_skew_detected)
|
||||||
O (error, NILF,
|
O (error, NILF,
|
||||||
_("warning: Clock skew detected. Your build may be incomplete."));
|
_("warning: Clock skew detected. Your build may be incomplete."));
|
||||||
|
|
||||||
/* Exit. */
|
/* Exit. */
|
||||||
die (makefile_status);
|
die (makefile_status);
|
||||||
@ -3443,9 +3328,19 @@ decode_switches (int argc, const char **argv, enum variable_origin origin)
|
|||||||
|
|
||||||
/* If there are any options that need to be decoded do it now. */
|
/* If there are any options that need to be decoded do it now. */
|
||||||
decode_debug_flags ();
|
decode_debug_flags ();
|
||||||
decode_warn_flags ();
|
|
||||||
decode_output_sync_flags ();
|
decode_output_sync_flags ();
|
||||||
|
|
||||||
|
/* Support old-style option. */
|
||||||
|
if (warn_undefined_variables_flag)
|
||||||
|
{
|
||||||
|
decode_warn_actions ("undefined-var", NULL);
|
||||||
|
warn_undefined_variables_flag = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (warn_flags)
|
||||||
|
for (const char **pp = warn_flags->list; *pp; ++pp)
|
||||||
|
decode_warn_actions (*pp, NULL);
|
||||||
|
|
||||||
/* Perform any special switch handling. */
|
/* Perform any special switch handling. */
|
||||||
run_silent = silent_flag;
|
run_silent = silent_flag;
|
||||||
}
|
}
|
||||||
@ -3655,38 +3550,7 @@ define_makeflags (int makefile)
|
|||||||
case filename:
|
case filename:
|
||||||
case strlist:
|
case strlist:
|
||||||
if (cs->c == WARN_OPT)
|
if (cs->c == WARN_OPT)
|
||||||
{
|
fp = encode_warn_flag (fp);
|
||||||
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)
|
|
||||||
{
|
|
||||||
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
|
else
|
||||||
{
|
{
|
||||||
struct stringlist *sl = *(struct stringlist **) cs->value_ptr;
|
struct stringlist *sl = *(struct stringlist **) cs->value_ptr;
|
||||||
|
@ -553,6 +553,8 @@ void error (const floc *flocp, size_t length, const char *fmt, ...)
|
|||||||
ATTRIBUTE ((__format__ (__printf__, 3, 4)));
|
ATTRIBUTE ((__format__ (__printf__, 3, 4)));
|
||||||
void fatal (const floc *flocp, size_t length, const char *fmt, ...)
|
void fatal (const floc *flocp, size_t length, const char *fmt, ...)
|
||||||
ATTRIBUTE ((noreturn, __format__ (__printf__, 3, 4)));
|
ATTRIBUTE ((noreturn, __format__ (__printf__, 3, 4)));
|
||||||
|
char *format (const char *prefix, size_t length, const char *fmt, ...)
|
||||||
|
ATTRIBUTE ((__format__ (__printf__, 3, 4)));
|
||||||
void out_of_memory (void) NORETURN;
|
void out_of_memory (void) NORETURN;
|
||||||
|
|
||||||
/* When adding macros to this list be sure to update the value of
|
/* When adding macros to this list be sure to update the value of
|
||||||
@ -760,6 +762,9 @@ extern int batch_mode_shell;
|
|||||||
#define RECIPEPREFIX_DEFAULT '\t'
|
#define RECIPEPREFIX_DEFAULT '\t'
|
||||||
extern char cmd_prefix;
|
extern char cmd_prefix;
|
||||||
|
|
||||||
|
/* Setting warning actions. */
|
||||||
|
#define WARNINGS_NAME ".WARNINGS"
|
||||||
|
|
||||||
extern unsigned int no_intermediates;
|
extern unsigned int no_intermediates;
|
||||||
|
|
||||||
#if HAVE_MKFIFO
|
#if HAVE_MKFIFO
|
||||||
|
@ -437,6 +437,7 @@ find_next_token (const char **ptr, size_t *lengthptr)
|
|||||||
return (char *)p;
|
return (char *)p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Write a BUFFER of size LEN to file descriptor FD.
|
/* Write a BUFFER of size LEN to file descriptor FD.
|
||||||
Retry short writes from EINTR. Return LEN, or -1 on error. */
|
Retry short writes from EINTR. Return LEN, or -1 on error. */
|
||||||
ssize_t
|
ssize_t
|
||||||
@ -611,7 +612,7 @@ get_tmpdir ()
|
|||||||
unsigned int found = 0;
|
unsigned int found = 0;
|
||||||
|
|
||||||
for (tp = tlist; *tp; ++tp)
|
for (tp = tlist; *tp; ++tp)
|
||||||
if ((tmpdir = getenv (*tp)) && *tmpdir != '\0')
|
if ((tmpdir = getenv (*tp)) != NULL && *tmpdir != '\0')
|
||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
int r;
|
int r;
|
||||||
|
25
src/output.c
25
src/output.c
@ -475,8 +475,8 @@ error (const floc *flocp, size_t len, const char *fmt, ...)
|
|||||||
void
|
void
|
||||||
fatal (const floc *flocp, size_t len, const char *fmt, ...)
|
fatal (const floc *flocp, size_t len, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list args;
|
|
||||||
const char *stop = _(". Stop.\n");
|
const char *stop = _(". Stop.\n");
|
||||||
|
va_list args;
|
||||||
char *start;
|
char *start;
|
||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
@ -505,6 +505,29 @@ fatal (const floc *flocp, size_t len, const char *fmt, ...)
|
|||||||
die (MAKE_FAILURE);
|
die (MAKE_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Format a message and return a pointer to an internal buffer. */
|
||||||
|
|
||||||
|
char *
|
||||||
|
format (const char *prefix, size_t len, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
size_t plen = prefix ? strlen (prefix) : 0;
|
||||||
|
char *start;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
len += strlen (fmt) + plen + 1;
|
||||||
|
start = p = get_buffer (len);
|
||||||
|
|
||||||
|
if (plen)
|
||||||
|
p = mempcpy (p, prefix, plen);
|
||||||
|
|
||||||
|
va_start (args, fmt);
|
||||||
|
vsprintf (p, fmt, args);
|
||||||
|
va_end (args);
|
||||||
|
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
/* Print an error message from errno. */
|
/* Print an error message from errno. */
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -3068,7 +3068,7 @@ tilde_expand (const char *name)
|
|||||||
|
|
||||||
{
|
{
|
||||||
/* Turn off undefined variables warning while we expand HOME. */
|
/* Turn off undefined variables warning while we expand HOME. */
|
||||||
enum warning_state save = warn_get (wt_undefined_var);
|
enum warning_action save = warn_get (wt_undefined_var);
|
||||||
warn_set (wt_undefined_var, w_ignore);
|
warn_set (wt_undefined_var, w_ignore);
|
||||||
|
|
||||||
home_dir = allocated_expand_variable (STRING_SIZE_TUPLE ("HOME"));
|
home_dir = allocated_expand_variable (STRING_SIZE_TUPLE ("HOME"));
|
||||||
|
@ -198,10 +198,8 @@ check_valid_name (const floc* flocp, const char *name, size_t length)
|
|||||||
if (cp == end)
|
if (cp == end)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (warn_error (wt_invalid_var))
|
warning (wt_invalid_var, flocp,
|
||||||
ONS (fatal, flocp, _("invalid variable name '%.*s'"), (int)length, name);
|
ONS (format, 0, _("invalid variable name '%.*s'"), (int)length, name));
|
||||||
|
|
||||||
ONS (error, flocp, _("invalid variable name '%.*s'"), (int)length, name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -491,12 +489,8 @@ check_variable_reference (const char *name, size_t length)
|
|||||||
if (cp == end)
|
if (cp == end)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (warn_error (wt_invalid_ref))
|
warning (wt_invalid_ref, *expanding_var,
|
||||||
ONS (fatal, *expanding_var,
|
ONS (format, 0, _("invalid variable reference '%.*s'"), (int)length, name));
|
||||||
_("invalid variable reference '%.*s'"), (int)length, name);
|
|
||||||
|
|
||||||
ONS (error, *expanding_var,
|
|
||||||
_("invalid variable reference '%.*s'"), (int)length, name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Lookup a variable whose name is a string starting at NAME
|
/* Lookup a variable whose name is a string starting at NAME
|
||||||
@ -1335,11 +1329,18 @@ set_special_var (struct variable *var, enum variable_origin origin)
|
|||||||
reset_makeflags (origin);
|
reset_makeflags (origin);
|
||||||
|
|
||||||
else if (streq (var->name, RECIPEPREFIX_NAME))
|
else if (streq (var->name, RECIPEPREFIX_NAME))
|
||||||
|
/* The user is resetting the command introduction prefix. This has to
|
||||||
|
happen immediately, so that subsequent rules are interpreted
|
||||||
|
properly. */
|
||||||
|
cmd_prefix = var->value[0]=='\0' ? RECIPEPREFIX_DEFAULT : var->value[0];
|
||||||
|
|
||||||
|
else if (streq (var->name, WARNINGS_NAME))
|
||||||
{
|
{
|
||||||
/* The user is resetting the command introduction prefix. This has to
|
/* It's weird but for .WARNINGS to make sense we need to expand them
|
||||||
happen immediately, so that subsequent rules are interpreted
|
when they are set, even if it's a recursive variable. */
|
||||||
properly. */
|
char *actions = allocated_expand_variable (STRING_SIZE_TUPLE (WARNINGS_NAME));
|
||||||
cmd_prefix = var->value[0]=='\0' ? RECIPEPREFIX_DEFAULT : var->value[0];
|
decode_warn_actions (actions, &var->fileinfo);
|
||||||
|
free (actions);
|
||||||
}
|
}
|
||||||
|
|
||||||
return var;
|
return var;
|
||||||
@ -1499,7 +1500,7 @@ do_variable_definition (const floc *flocp, const char *varname,
|
|||||||
{
|
{
|
||||||
char *s;
|
char *s;
|
||||||
if (streq (varname, MAKEFLAGS_NAME)
|
if (streq (varname, MAKEFLAGS_NAME)
|
||||||
&& (s = strstr (v->value, " -- ")))
|
&& (s = strstr (v->value, " -- ")) != NULL)
|
||||||
/* We found a separator in MAKEFLAGS. Ignore variable
|
/* We found a separator in MAKEFLAGS. Ignore variable
|
||||||
assignments: set_special_var() will reconstruct things. */
|
assignments: set_special_var() will reconstruct things. */
|
||||||
cp = mempcpy (cp, v->value, s - v->value);
|
cp = mempcpy (cp, v->value, s - v->value);
|
||||||
@ -1914,6 +1915,7 @@ static const struct defined_vars defined_vars[] = {
|
|||||||
{ STRING_SIZE_TUPLE ("-*-eval-flags-*-") },
|
{ STRING_SIZE_TUPLE ("-*-eval-flags-*-") },
|
||||||
{ STRING_SIZE_TUPLE ("VPATH") },
|
{ STRING_SIZE_TUPLE ("VPATH") },
|
||||||
{ STRING_SIZE_TUPLE ("GPATH") },
|
{ STRING_SIZE_TUPLE ("GPATH") },
|
||||||
|
{ STRING_SIZE_TUPLE (WARNINGS_NAME) },
|
||||||
{ NULL, 0 }
|
{ NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1927,12 +1929,9 @@ warn_undefined (const char *name, size_t len)
|
|||||||
if (dp->len == len && memcmp (dp->name, name, len) == 0)
|
if (dp->len == len && memcmp (dp->name, name, len) == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (warn_error (wt_undefined_var))
|
warning (wt_undefined_var, reading_file,
|
||||||
fatal (reading_file, len, _("reference to undefined variable '%.*s'"),
|
ONS (format, 0, _("reference to undefined variable '%.*s'"),
|
||||||
(int)len, name);
|
(int)len, name));
|
||||||
else
|
|
||||||
error (reading_file, len, _("reference to undefined variable '%.*s'"),
|
|
||||||
(int)len, name);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
235
src/warning.c
Normal file
235
src/warning.c
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
/* 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/>. */
|
||||||
|
|
||||||
|
#include "makeint.h"
|
||||||
|
#include "warning.h"
|
||||||
|
#include "variable.h"
|
||||||
|
|
||||||
|
/* Current action for each warning. */
|
||||||
|
enum warning_action warnings[wt_max];
|
||||||
|
|
||||||
|
/* The default behavior of warnings. */
|
||||||
|
static struct warning_data warn_default;
|
||||||
|
|
||||||
|
/* Warning settings from the .WARNING variable. */
|
||||||
|
static struct warning_data warn_variable;
|
||||||
|
|
||||||
|
/* Warning settings from the command line. */
|
||||||
|
static struct warning_data warn_flag;
|
||||||
|
|
||||||
|
static const char *w_action_map[w_error+1] = {NULL, "ignore", "warn", "error"};
|
||||||
|
static const char *w_name_map[wt_max] = {
|
||||||
|
"invalid-var",
|
||||||
|
"invalid-ref",
|
||||||
|
"undefined-var"
|
||||||
|
};
|
||||||
|
|
||||||
|
#define encode_warn_action(_b,_s) \
|
||||||
|
variable_buffer_output (_b, w_action_map[_s], strlen (w_action_map[_s]))
|
||||||
|
#define encode_warn_name(_b,_t) \
|
||||||
|
variable_buffer_output (_b, w_name_map[_t], strlen (w_name_map[_t]))
|
||||||
|
|
||||||
|
static void set_warnings ()
|
||||||
|
{
|
||||||
|
/* Called whenever any warnings could change; resets the current actions. */
|
||||||
|
for (enum warning_type wt = 0; wt < wt_max; ++wt)
|
||||||
|
warnings[wt] =
|
||||||
|
warn_flag.actions[wt] != w_unset ? warn_flag.actions[wt]
|
||||||
|
: warn_flag.global != w_unset ? warn_flag.global
|
||||||
|
: warn_variable.actions[wt] != w_unset ? warn_variable.actions[wt]
|
||||||
|
: warn_variable.global != w_unset ? warn_variable.global
|
||||||
|
: warn_default.actions[wt];
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
warn_init ()
|
||||||
|
{
|
||||||
|
memset (&warn_default, '\0', sizeof (warn_default));
|
||||||
|
memset (&warn_variable, '\0', sizeof (warn_variable));
|
||||||
|
memset (&warn_flag, '\0', sizeof (warn_flag));
|
||||||
|
|
||||||
|
/* All warnings must have a default. */
|
||||||
|
warn_default.global = w_warn;
|
||||||
|
warn_default.actions[wt_invalid_var] = w_warn;
|
||||||
|
warn_default.actions[wt_invalid_ref] = w_warn;
|
||||||
|
warn_default.actions[wt_undefined_var] = w_ignore;
|
||||||
|
|
||||||
|
set_warnings ();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
init_data (struct warning_data *data)
|
||||||
|
{
|
||||||
|
data->global = w_unset;
|
||||||
|
for (enum warning_type wt = wt_invalid_var; wt < wt_max; ++wt)
|
||||||
|
data->actions[wt] = w_unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum warning_action
|
||||||
|
decode_warn_action (const char *action, size_t length)
|
||||||
|
{
|
||||||
|
for (enum warning_action st = w_ignore; st <= w_error; ++st)
|
||||||
|
{
|
||||||
|
size_t len = strlen (w_action_map[st]);
|
||||||
|
if (length == len && strncasecmp (action, w_action_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_invalid_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
decode_warn_actions (const char *value, const floc *flocp)
|
||||||
|
{
|
||||||
|
struct warning_data *data = &warn_flag;
|
||||||
|
|
||||||
|
NEXT_TOKEN (value);
|
||||||
|
|
||||||
|
if (flocp)
|
||||||
|
{
|
||||||
|
data = &warn_variable;
|
||||||
|
/* When a variable is set to empty, reset everything. */
|
||||||
|
if (*value == '\0')
|
||||||
|
init_data (data);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (*value != '\0')
|
||||||
|
{
|
||||||
|
enum warning_action action;
|
||||||
|
|
||||||
|
/* Find the end of the next warning definition. */
|
||||||
|
const char *ep = value;
|
||||||
|
while (! STOP_SET (*ep, MAP_BLANK|MAP_COMMA|MAP_NUL))
|
||||||
|
++ep;
|
||||||
|
|
||||||
|
/* If the value is just an action set it globally. */
|
||||||
|
action = decode_warn_action (value, ep - value);
|
||||||
|
if (action != w_unset)
|
||||||
|
data->global = action;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
enum warning_type type;
|
||||||
|
const char *cp = memchr (value, ':', ep - value);
|
||||||
|
if (!cp)
|
||||||
|
cp = ep;
|
||||||
|
type = decode_warn_name (value, cp - value);
|
||||||
|
if (type == wt_max)
|
||||||
|
{
|
||||||
|
int l = (int)(cp - value);
|
||||||
|
if (!flocp)
|
||||||
|
ONS (fatal, NILF, _("unknown warning '%.*s'"), l, value);
|
||||||
|
ONS (error, flocp,
|
||||||
|
_("unknown warning '%.*s': ignored"), l, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If there's a warning action, decode it. */
|
||||||
|
if (cp == ep)
|
||||||
|
action = w_warn;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++cp;
|
||||||
|
action = decode_warn_action (cp, ep - cp);
|
||||||
|
if (action == w_unset)
|
||||||
|
{
|
||||||
|
int l = (int)(ep - cp);
|
||||||
|
if (!flocp)
|
||||||
|
ONS (fatal, NILF, _("unknown warning action '%.*s'"), l, cp);
|
||||||
|
ONS (error, flocp,
|
||||||
|
_("unknown warning action '%.*s': ignored"), l, cp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data->actions[type] = action;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = ep;
|
||||||
|
while (STOP_SET (*value, MAP_BLANK|MAP_COMMA))
|
||||||
|
++value;
|
||||||
|
}
|
||||||
|
|
||||||
|
set_warnings ();
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
encode_warn_flag (char *fp)
|
||||||
|
{
|
||||||
|
enum warning_type wt;
|
||||||
|
char sp = '=';
|
||||||
|
|
||||||
|
/* See if any warning options are set. */
|
||||||
|
for (wt = 0; wt < wt_max; ++wt)
|
||||||
|
if (warn_flag.actions[wt] != w_unset)
|
||||||
|
break;
|
||||||
|
if (wt == wt_max && warn_flag.global == w_unset)
|
||||||
|
return fp;
|
||||||
|
|
||||||
|
/* Something is set so construct a --warn option. */
|
||||||
|
fp = variable_buffer_output (fp, STRING_SIZE_TUPLE (" --warn"));
|
||||||
|
|
||||||
|
/* If only a global action set to warn, we're done. */
|
||||||
|
if (wt == wt_max && warn_flag.global == w_warn)
|
||||||
|
return fp;
|
||||||
|
|
||||||
|
/* If a global action is set, add it. */
|
||||||
|
if (warn_flag.global > w_unset)
|
||||||
|
{
|
||||||
|
fp = variable_buffer_output (fp, &sp, 1);
|
||||||
|
sp = ',';
|
||||||
|
fp = encode_warn_action (fp, warn_flag.global);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add any specific actions. */
|
||||||
|
if (wt != wt_max)
|
||||||
|
for (wt = 0; wt < wt_max; ++wt)
|
||||||
|
{
|
||||||
|
enum warning_action act = warn_flag.actions[wt];
|
||||||
|
if (act > w_unset)
|
||||||
|
{
|
||||||
|
fp = variable_buffer_output (fp, &sp, 1);
|
||||||
|
sp = ',';
|
||||||
|
fp = encode_warn_name (fp, wt);
|
||||||
|
if (act != w_warn)
|
||||||
|
fp = encode_warn_action (variable_buffer_output (fp, ":", 1), act);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
warn_get_vardata (struct warning_data *data)
|
||||||
|
{
|
||||||
|
memcpy (data, &warn_variable, sizeof (warn_variable));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
warn_set_vardata (const struct warning_data *data)
|
||||||
|
{
|
||||||
|
memcpy (&warn_variable, data, sizeof (warn_variable));
|
||||||
|
set_warnings ();
|
||||||
|
}
|
@ -23,8 +23,8 @@ enum warning_type
|
|||||||
wt_max
|
wt_max
|
||||||
};
|
};
|
||||||
|
|
||||||
/* State of a given warning. */
|
/* Action taken for a given warning. */
|
||||||
enum warning_state
|
enum warning_action
|
||||||
{
|
{
|
||||||
w_unset = 0,
|
w_unset = 0,
|
||||||
w_ignore,
|
w_ignore,
|
||||||
@ -32,25 +32,24 @@ enum warning_state
|
|||||||
w_error
|
w_error
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The default state of warnings. */
|
struct warning_data
|
||||||
extern enum warning_state default_warnings[wt_max];
|
{
|
||||||
|
enum warning_action global; /* Global setting. */
|
||||||
|
enum warning_action actions[wt_max]; /* Action for each warning type. */
|
||||||
|
};
|
||||||
|
|
||||||
/* Current state of warnings. */
|
/* Actions taken for each warning. */
|
||||||
extern enum warning_state warnings[wt_max];
|
extern enum warning_action warnings[wt_max];
|
||||||
|
|
||||||
/* Global warning settings. */
|
/* Get the current action for a given warning. */
|
||||||
extern enum warning_state warn_global;
|
#define warn_get(_w) (warnings[_w])
|
||||||
|
|
||||||
/* Get the current state of a given warning. */
|
/* Set the current actin for a given warning. Can't use w_unset here.
|
||||||
#define warn_get(_w) (warnings[_w] != w_unset ? warnings[_w] \
|
This should only be used for temporary resetting of warnings. */
|
||||||
: warn_global != w_unset ? warn_global \
|
#define warn_set(_w,_f) do{ warnings[_w] = (_f); }while(0)
|
||||||
: 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. */
|
/* True if we should check for the warning in the first place. */
|
||||||
#define warn_check(_w) (warn_get (_w) > w_ignore)
|
#define warn_check(_w) (warn_get (_w) > w_ignore)
|
||||||
|
|
||||||
/* Check if the warning is ignored. */
|
/* Check if the warning is ignored. */
|
||||||
#define warn_ignored(_w) (warn_get (_w) == w_ignore)
|
#define warn_ignored(_w) (warn_get (_w) == w_ignore)
|
||||||
@ -60,3 +59,22 @@ extern enum warning_state warn_global;
|
|||||||
|
|
||||||
/* Check if the warning is in "error" mode. */
|
/* Check if the warning is in "error" mode. */
|
||||||
#define warn_error(_w) (warn_get (_w) == w_error)
|
#define warn_error(_w) (warn_get (_w) == w_error)
|
||||||
|
|
||||||
|
void warn_init (void);
|
||||||
|
void decode_warn_actions (const char *value, const floc *flocp);
|
||||||
|
char *encode_warn_flag (char *fp);
|
||||||
|
|
||||||
|
void warn_get_vardata (struct warning_data *data);
|
||||||
|
void warn_set_vardata (const struct warning_data *data);
|
||||||
|
|
||||||
|
#define warning(_t,_f,_m) \
|
||||||
|
do{ \
|
||||||
|
if (warn_check (_t)) \
|
||||||
|
{ \
|
||||||
|
char *_a = xstrdup (_m); \
|
||||||
|
if (warn_error (_t)) \
|
||||||
|
fatal (_f, strlen (_a), "%s", _a); \
|
||||||
|
error (_f, strlen (_a), _("warning: %s"), _a); \
|
||||||
|
free (_a); \
|
||||||
|
} \
|
||||||
|
}while(0)
|
||||||
|
@ -53,7 +53,7 @@ all:;
|
|||||||
X := $(averyveryveryloooooooooooooooooooooooooooongvariablename)
|
X := $(averyveryveryloooooooooooooooooooooooooooongvariablename)
|
||||||
!,
|
!,
|
||||||
'--warn=undefined-var',
|
'--warn=undefined-var',
|
||||||
"#MAKEFILE#:3: reference to undefined variable 'averyveryveryloooooooooooooooooooooooooooongvariablename'
|
"#MAKEFILE#:3: warning: reference to undefined variable 'averyveryveryloooooooooooooooooooooooooooongvariablename'
|
||||||
#MAKE#: 'all' is up to date.\n"
|
#MAKE#: 'all' is up to date.\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -75,8 +75,8 @@ run_make_test(undef, '--warn=undefined-var:ignore', 'ref');
|
|||||||
|
|
||||||
# Check warnings
|
# Check warnings
|
||||||
run_make_test(undef, '--warn=undefined-var',
|
run_make_test(undef, '--warn=undefined-var',
|
||||||
"#MAKEFILE#:7: reference to undefined variable 'UNDEFINED'
|
"#MAKEFILE#:7: warning: reference to undefined variable 'UNDEFINED'
|
||||||
#MAKEFILE#:9: reference to undefined variable 'UNDEFINED'
|
#MAKEFILE#:9: warning: reference to undefined variable 'UNDEFINED'
|
||||||
ref");
|
ref");
|
||||||
|
|
||||||
# Check and errors
|
# Check and errors
|
||||||
@ -96,9 +96,9 @@ define nl
|
|||||||
endef
|
endef
|
||||||
|
|
||||||
all: ; @echo ref $(also$(nl)bad) $(IREF) $(SIREF)',
|
all: ; @echo ref $(also$(nl)bad) $(IREF) $(SIREF)',
|
||||||
'', "#MAKEFILE#:2: invalid variable reference 'bad variable'
|
'', "#MAKEFILE#:2: warning: invalid variable reference 'bad variable'
|
||||||
#MAKEFILE#:10: invalid variable reference 'also\nbad'
|
#MAKEFILE#:10: warning: invalid variable reference 'also\nbad'
|
||||||
#MAKEFILE#:2: invalid variable reference 'bad variable'
|
#MAKEFILE#:2: warning: invalid variable reference 'bad variable'
|
||||||
ref");
|
ref");
|
||||||
|
|
||||||
run_make_test(undef, '--warn=ignore', 'ref');
|
run_make_test(undef, '--warn=ignore', 'ref');
|
||||||
@ -133,18 +133,26 @@ foo
|
|||||||
endef
|
endef
|
||||||
|
|
||||||
all: ; @echo ref',
|
all: ; @echo ref',
|
||||||
'', "#MAKEFILE#:4: invalid variable name 'BAD VAR'
|
'', "#MAKEFILE#:4: warning: invalid variable name 'BAD VAR'
|
||||||
#MAKEFILE#:11: invalid variable name 'NL\nVAR'
|
#MAKEFILE#:11: warning: invalid variable name 'NL\nVAR'
|
||||||
#MAKEFILE#:13: invalid variable name 'BAD DEF'
|
#MAKEFILE#:13: warning: invalid variable name 'BAD DEF'
|
||||||
#MAKEFILE#:17: invalid variable name 'NL\nDEF'
|
#MAKEFILE#:17: warning: invalid variable name 'NL\nDEF'
|
||||||
ref");
|
ref");
|
||||||
|
|
||||||
run_make_test(undef, '--warn=ignore', 'ref');
|
run_make_test(undef, '--warn=ignore', 'ref');
|
||||||
|
|
||||||
run_make_test(undef, '--warn=invalid-var:ignore', 'ref');
|
run_make_test(undef, '--warn=invalid-var:ignore', 'ref');
|
||||||
|
|
||||||
# Check and errors
|
# Check errors
|
||||||
run_make_test(undef, '--warn=invalid-var:error',
|
run_make_test(undef, '--warn=invalid-var:error',
|
||||||
"#MAKEFILE#:4: *** invalid variable name 'BAD VAR'. Stop.", 512);
|
"#MAKEFILE#:4: *** invalid variable name 'BAD VAR'. Stop.", 512);
|
||||||
|
|
||||||
|
# Make sure unknown warnings and actions fail when given on the command line.
|
||||||
|
|
||||||
|
run_make_test(undef, '--warn=no-such-warn',
|
||||||
|
"#MAKE#: *** unknown warning 'no-such-warn'. Stop.", 512);
|
||||||
|
|
||||||
|
run_make_test(undef, '--warn=invalid-var:no-such-action',
|
||||||
|
"#MAKE#: *** unknown warning action 'no-such-action'. Stop.", 512);
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
180
tests/scripts/variables/WARNINGS
Normal file
180
tests/scripts/variables/WARNINGS
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
# -*-perl-*-
|
||||||
|
|
||||||
|
$description = "Test the .WARNINGS variable.";
|
||||||
|
|
||||||
|
my %warn_test = (
|
||||||
|
'warn' => 'warn', 'error warn' => 'warn',
|
||||||
|
'error' => 'error',
|
||||||
|
'ignore error ignore invalid-var,invalid-ref,undefined-var' => 'ignore,invalid-var,invalid-ref,undefined-var',
|
||||||
|
'invalid-ref:ignore error invalid-var:warn,,,,,undefined-var:error,,,,,' => '=error,invalid-var,invalid-ref:ignore,undefined-var:error'
|
||||||
|
);
|
||||||
|
|
||||||
|
# Verify that values set in .WARNINGS don't get passed to sub-makes
|
||||||
|
|
||||||
|
while (my ($f, $r) = each %warn_test) {
|
||||||
|
run_make_test(qq!
|
||||||
|
.WARNINGS = error
|
||||||
|
\$(info MF=\$(MAKEFLAGS))
|
||||||
|
all:; \@#HELPER# env MAKEFLAGS
|
||||||
|
!,
|
||||||
|
'', "MF=\nMAKEFLAGS=");
|
||||||
|
}
|
||||||
|
|
||||||
|
# Verify that make's special variables don't warn even if they're not set
|
||||||
|
run_make_test(q!
|
||||||
|
.WARNINGS = undefined-var
|
||||||
|
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:;
|
||||||
|
!,
|
||||||
|
'', "#MAKE#: 'all' is up to date.");
|
||||||
|
|
||||||
|
# sv 63609.
|
||||||
|
# Test for buffer overrun in warn_undefined.
|
||||||
|
run_make_test(q!
|
||||||
|
.WARNINGS = undefined-var
|
||||||
|
all:;
|
||||||
|
X := $(averyveryveryloooooooooooooooooooooooooooongvariablename)
|
||||||
|
!,
|
||||||
|
'', "#MAKEFILE#:4: warning: 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('
|
||||||
|
.WARNINGS := $(warnval)
|
||||||
|
EMPTY =
|
||||||
|
EREF = $(EMPTY)
|
||||||
|
UREF = $(UNDEFINED)
|
||||||
|
|
||||||
|
SEREF := $(EREF)
|
||||||
|
SUREF := $(UREF)
|
||||||
|
|
||||||
|
all: ; @echo ref $(EREF) $(UREF)',
|
||||||
|
'', 'ref');
|
||||||
|
|
||||||
|
run_make_test(undef, 'warnval=undefined-var:ignore', 'ref');
|
||||||
|
|
||||||
|
# Check warnings
|
||||||
|
run_make_test(undef, 'warnval=undefined-var',
|
||||||
|
"#MAKEFILE#:8: warning: reference to undefined variable 'UNDEFINED'
|
||||||
|
#MAKEFILE#:10: warning: reference to undefined variable 'UNDEFINED'
|
||||||
|
ref");
|
||||||
|
|
||||||
|
# Check and errors
|
||||||
|
run_make_test(undef, 'warnval=undefined-var:error',
|
||||||
|
"#MAKEFILE#:8: *** reference to undefined variable 'UNDEFINED'. Stop.", 512);
|
||||||
|
|
||||||
|
# Check invalid variable reference warnings
|
||||||
|
|
||||||
|
# With no options we still check for invalid references
|
||||||
|
run_make_test('
|
||||||
|
.WARNINGS = $(warnval)
|
||||||
|
IREF = $(bad variable)
|
||||||
|
SIREF := $(IREF)
|
||||||
|
|
||||||
|
define nl
|
||||||
|
|
||||||
|
|
||||||
|
endef
|
||||||
|
|
||||||
|
all: ; @echo ref $(also$(nl)bad) $(IREF) $(SIREF)',
|
||||||
|
'', "#MAKEFILE#:3: warning: invalid variable reference 'bad variable'
|
||||||
|
#MAKEFILE#:11: warning: invalid variable reference 'also\nbad'
|
||||||
|
#MAKEFILE#:3: warning: invalid variable reference 'bad variable'
|
||||||
|
ref");
|
||||||
|
|
||||||
|
run_make_test(undef, 'warnval=ignore', 'ref');
|
||||||
|
|
||||||
|
run_make_test(undef, 'warnval=invalid-ref:ignore', 'ref');
|
||||||
|
|
||||||
|
# Check and errors
|
||||||
|
run_make_test(undef, 'warnval=invalid-ref:error',
|
||||||
|
"#MAKEFILE#:3: *** invalid variable reference 'bad variable'. Stop.", 512);
|
||||||
|
|
||||||
|
# Check invalid variable name warnings
|
||||||
|
|
||||||
|
# With no options we still check for invalid references
|
||||||
|
run_make_test('
|
||||||
|
.WARNINGS = $(warnval)
|
||||||
|
EMPTY =
|
||||||
|
SPACE = $(EMPTY) $(EMPTY)
|
||||||
|
BAD$(SPACE)VAR = foo
|
||||||
|
|
||||||
|
define nl
|
||||||
|
|
||||||
|
|
||||||
|
endef
|
||||||
|
|
||||||
|
NL$(nl)VAR = bar
|
||||||
|
|
||||||
|
define BAD$(SPACE)DEF :=
|
||||||
|
foo
|
||||||
|
endef
|
||||||
|
|
||||||
|
define NL$(nl)DEF :=
|
||||||
|
foo
|
||||||
|
endef
|
||||||
|
|
||||||
|
all: ; @echo ref',
|
||||||
|
'', "#MAKEFILE#:5: warning: invalid variable name 'BAD VAR'
|
||||||
|
#MAKEFILE#:12: warning: invalid variable name 'NL\nVAR'
|
||||||
|
#MAKEFILE#:14: warning: invalid variable name 'BAD DEF'
|
||||||
|
#MAKEFILE#:18: warning: invalid variable name 'NL\nDEF'
|
||||||
|
ref");
|
||||||
|
|
||||||
|
run_make_test(undef, 'warnval=ignore', 'ref');
|
||||||
|
|
||||||
|
run_make_test(undef, 'warnval=invalid-var:ignore', 'ref');
|
||||||
|
|
||||||
|
# Check errors
|
||||||
|
run_make_test(undef, 'warnval=invalid-var:error',
|
||||||
|
"#MAKEFILE#:5: *** invalid variable name 'BAD VAR'. Stop.", 512);
|
||||||
|
|
||||||
|
# Make sure unknown warnings and actions are only noted but not failed on:
|
||||||
|
# this allows makefiles to be portable to older versions where those warnings
|
||||||
|
# didn't exist
|
||||||
|
|
||||||
|
run_make_test(q!
|
||||||
|
.WARNINGS = no-such-warn
|
||||||
|
all:;
|
||||||
|
!,
|
||||||
|
'',"#MAKEFILE#:2: unknown warning 'no-such-warn': ignored\n#MAKE#: 'all' is up to date.");
|
||||||
|
|
||||||
|
run_make_test(q!
|
||||||
|
.WARNINGS = invalid-var:no-such-action
|
||||||
|
all:;
|
||||||
|
!,
|
||||||
|
'',"#MAKEFILE#:2: unknown warning action 'no-such-action': ignored\n#MAKE#: 'all' is up to date.");
|
||||||
|
|
||||||
|
|
||||||
|
# Validate .WARNINGS set as target-specific variables
|
||||||
|
# This is not supported (yet...?)
|
||||||
|
|
||||||
|
# run_make_test(q!
|
||||||
|
# ok := $(undef)
|
||||||
|
# ref = $(undef)
|
||||||
|
|
||||||
|
# all: enabled disabled enabled2 ;
|
||||||
|
|
||||||
|
# .WARNINGS = undefined-var
|
||||||
|
|
||||||
|
# enabled enabled2 disabled ref: ; $(info $@:$(ref))
|
||||||
|
|
||||||
|
# disabled: .WARNINGS =
|
||||||
|
# disabled: ref
|
||||||
|
# !,
|
||||||
|
# '', "#MAKEFILE#:9: reference to undefined variable 'undef'\nenabled:
|
||||||
|
# ref:
|
||||||
|
# disabled:
|
||||||
|
# #MAKEFILE#:9: reference to undefined variable 'undef'\nenabled2:
|
||||||
|
# #MAKE#: 'all' is up to date.");
|
||||||
|
|
||||||
|
1;
|
Loading…
Reference in New Issue
Block a user