From a9e3eb1eecb595320147884af08fe95be546af33 Mon Sep 17 00:00:00 2001 From: Dmitry Goncharov Date: Sun, 19 May 2024 18:56:12 -0400 Subject: [PATCH] [SV 65739] Add warning circular-dep. Add a warning to control circular dependency detection. Use "warn" as the default action to be backward-compatible. * src/warning.h (enum warning_type): Add warning type wt_circular_dep. * src/warning.c (warn_init): Set default wt_circular_dep to w_warn. * src/remake.c (update_file_1): Consult the circular-dep warning to handle circular dependencies. * tests/scripts/options/warn: Test --warn circular-dep flag. * tests/scripts/variables/WARNINGS: Test .WARNINGS circular-dep flag. * doc/make.texi: Document circular-dep warning. * doc/make.1: Ditto. --- NEWS | 3 +++ doc/make.1 | 7 +++++-- doc/make.texi | 18 +++++++++++++----- src/remake.c | 11 +++++++++-- src/warning.c | 4 +++- src/warning.h | 1 + tests/scripts/options/warn | 13 +++++++++++++ tests/scripts/variables/WARNINGS | 21 +++++++++++++++++++++ 8 files changed, 68 insertions(+), 10 deletions(-) diff --git a/NEWS b/NEWS index c9d8ff5e..216e17cc 100644 --- a/NEWS +++ b/NEWS @@ -83,6 +83,9 @@ https://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=111&se defined in the makefiles, one per line, then exit with success. No recipes are invoked and no makefiles are re-built. +* Warnings for detecting circular dependencies are controllable via warning + reporting, with the name "circular-dep". + * 'make --print-data-base' (or 'make -p') now outputs time of day using the same form as for file timestamps, e.g., "2023-05-10 10:43:57.570558743". Previously it used the form "Wed May 10 diff --git a/doc/make.1 b/doc/make.1 index bb394bde..059bf752 100644 --- a/doc/make.1 +++ b/doc/make.1 @@ -379,10 +379,13 @@ can be an action; one of or .I error to set the default action for all warnings, or it can be a specific warning: +.I circular-dep +(finding a circular dependency), +.I invalid-ref +(referencing an invalid variable name), .I invalid-var (assigning to an invalid variable name), -.I invalid-ref -(referencing an invalid variable name), or +or .I undefined-var (referencing an undefined variable). The behavior of each warning can be set by adding diff --git a/doc/make.texi b/doc/make.texi index 8b0f4506..a7e7bd40 100644 --- a/doc/make.texi +++ b/doc/make.texi @@ -9447,11 +9447,13 @@ Show an error for the usage and immediately stop processing the makefile. The types of warnings GNU Make can detect are: @table @samp -@item invalid-var -@findex invalid-var -@cindex warning invalid variable -Assigning to an invalid variable name (e.g., a name containing whitespace). -The default action is @samp{warn}. +@item circular-dep +@findex circular-dep +@cindex warning circular dependency +Finding a loop in the dependency graph (the prerequisites of a target contain +or depend on the target itself). If the action is not @samp{error}, the +circular reference is dropped from the graph before continuing. The default +action is @samp{warn}. @item invalid-ref @findex invalid-ref @@ -9459,6 +9461,12 @@ The default action is @samp{warn}. Using an invalid variable name in a variable reference. The default action is @samp{warn}. +@item invalid-var +@findex invalid-var +@cindex warning invalid variable +Assigning to an invalid variable name (e.g., a name containing whitespace). +The default action is @samp{warn}. + @item undefined-var @findex undefined-var @cindex warning undefined variable diff --git a/src/remake.c b/src/remake.c index ee8971e7..fcc5cc12 100644 --- a/src/remake.c +++ b/src/remake.c @@ -20,6 +20,7 @@ this program. If not, see . */ #include "commands.h" #include "dep.h" #include "variable.h" +#include "warning.h" #include "debug.h" #include @@ -635,8 +636,14 @@ update_file_1 (struct file *file, unsigned int depth) if (is_updating (d->file)) { - OSS (error, NILF, _("circular %s <- %s dependency dropped"), - file->name, d->file->name); + /* Avoid macro warning, bacause its output differs from that of + older makes. */ + if (warn_error (wt_circular_dep)) + OSS (fatal, NILF, _("circular %s <- %s dependency detected"), + file->name, d->file->name); + if (warn_check (wt_circular_dep)) + OSS (error, NILF, _("circular %s <- %s dependency dropped"), + file->name, d->file->name); if (lastd == 0) file->deps = du->next; diff --git a/src/warning.c b/src/warning.c index 35950f77..26584e92 100644 --- a/src/warning.c +++ b/src/warning.c @@ -34,7 +34,8 @@ 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" + "undefined-var", + "circular-dep" }; #define encode_warn_action(_b,_s) \ @@ -66,6 +67,7 @@ warn_init () warn_default.actions[wt_invalid_var] = w_warn; warn_default.actions[wt_invalid_ref] = w_warn; warn_default.actions[wt_undefined_var] = w_ignore; + warn_default.actions[wt_circular_dep] = w_warn; set_warnings (); } diff --git a/src/warning.h b/src/warning.h index b8fcae97..fabbe01a 100644 --- a/src/warning.h +++ b/src/warning.h @@ -20,6 +20,7 @@ enum warning_type wt_invalid_var = 0, /* Assign to an invalid variable name. */ wt_invalid_ref, /* Reference an invalid variable name. */ wt_undefined_var, /* Reference an undefined variable name. */ + wt_circular_dep, /* A target depends on itself. */ wt_max }; diff --git a/tests/scripts/options/warn b/tests/scripts/options/warn index 2b862a58..5285d873 100644 --- a/tests/scripts/options/warn +++ b/tests/scripts/options/warn @@ -166,4 +166,17 @@ run_make_test(undef, '--warn=no-such-warn', run_make_test(undef, '--warn=invalid-var:no-such-action', "#MAKE#: *** unknown warning action 'no-such-action'. Stop.", 512); +# sv 65739. Circular dependency. +run_make_test(q! +hello: hello; @: +!, + '', "#MAKE#: circular hello <- hello dependency dropped\n"); + +run_make_test(undef, '--warn=error', "#MAKE#: *** circular hello <- hello dependency detected. Stop.\n", 512); +run_make_test(undef, '--warn=circular-dep:error', "#MAKE#: *** circular hello <- hello dependency detected. Stop.\n", 512); +run_make_test(undef, '--warn=warn', "#MAKE#: circular hello <- hello dependency dropped\n"); +run_make_test(undef, '--warn=circular-dep:warn', "#MAKE#: circular hello <- hello dependency dropped\n"); +run_make_test(undef, '--warn=ignore', ''); +run_make_test(undef, '--warn=circular-dep:ignore', ''); + 1; diff --git a/tests/scripts/variables/WARNINGS b/tests/scripts/variables/WARNINGS index 870a41d0..b6ce2613 100644 --- a/tests/scripts/variables/WARNINGS +++ b/tests/scripts/variables/WARNINGS @@ -154,6 +154,27 @@ all:; !, '',"#MAKEFILE#:2: unknown warning action 'no-such-action': ignored\n#MAKE#: 'all' is up to date."); +# sv 65739. Circular dependency. +run_make_test(q! +hello: hello; @: +!, + '', "#MAKE#: circular hello <- hello dependency dropped\n"); +run_make_test(q! +.WARNINGS = circular-dep:error +hello: hello; @: +!, + '', "#MAKE#: *** circular hello <- hello dependency detected. Stop.\n", 512); +run_make_test(q! +.WARNINGS = circular-dep:warn +hello: hello; @: +!, + '', "#MAKE#: circular hello <- hello dependency dropped\n"); +run_make_test(q! +.WARNINGS = circular-dep:ignore +hello: hello; @: +!, + '', ''); + # Validate .WARNINGS set as target-specific variables # This is not supported (yet...?)