summaryrefslogtreecommitdiff
path: root/src/main.c
diff options
context:
space:
mode:
authorPaul Smith <psmith@gnu.org>2023-02-26 18:04:14 -0500
committerPaul Smith <psmith@gnu.org>2023-04-01 11:13:12 -0400
commit2611e1991fabe2a3ae929c6ebd4afbd4f550f306 (patch)
tree0733d2ff7f545c8ba0b4c032a309cde459dfdfce /src/main.c
parent9db74434cd34b2b875b3f9bfbab4f1e0b682e27c (diff)
downloadmake-git-2611e1991fabe2a3ae929c6ebd4afbd4f550f306.tar.gz
Introduce a --warn command line option
Replace the singleton --warn-undefined-variables with infrastructure to manage multiple warnings: the --warn option can take an action "ignore", "warn", or "error" (which will apply to all warnings), or a specific warning type and an action for that type. Multiple options can be provided and are consolidated. * NEWS: Announce the new option. * doc/make.1: Document in the man page. * doc/make.texi (Warnings): Document in the user's manual. * Makefile.am: Add new header warning.h. * src/warning.h: Define enum for actions and warning types, and macros to test whether they are set. Keep the default settings separate so that we can correctly reconstruct MAKEFLAGS. * src/makeint.h: Remove deprecated warn_undefined_variables_flag. * src/main.c: Create global variables to hold warning settings. (switches): Add a new switch for --warn. (initialize_warnings): Set the default warning actions. (main): Call initialize_warnings(). (encode_warning_state, decode_warning_state): Convert warning states between strings and enums. (encode_warning_name, decode_warning_name): Convert warning names between strings and enums. (decode_warn_flags): Convert a --warn option into enum values. If deprecated warn_undefined_variables_flag is set convert it to --warn. (decode_switches): Don't remove duplicates of --warn since order matters. Call decode_warn_flags() to handle --warn. (define_makeflags): Special-case handling of --warn options written to MAKEFLAGS: write out the current settings. * src/read.c (tilde_expand): Use new warning control macros. * src/variable.c (warn_undefined): Ditto. * src/job.c (construct_command_argv): Ditto. * tests/scripts/options/warn: Rename from warn-undefined-variables and add tests for --warn. * tests/scripts/variables/MAKEFLAGS: Expect the new behavior.
Diffstat (limited to 'src/main.c')
-rw-r--r--src/main.c195
1 files changed, 176 insertions, 19 deletions
diff --git a/src/main.c b/src/main.c
index bf74ab94..221870ab 100644
--- a/src/main.c
+++ b/src/main.c
@@ -25,6 +25,7 @@ this program. If not, see <https://www.gnu.org/licenses/>. */
#include "debug.h"
#include "getopt.h"
#include "shuffle.h"
+#include "warning.h"
#include <assert.h>
#if MK_OS_W32
@@ -272,10 +273,26 @@ static struct stringlist *eval_strings = 0;
static int print_usage_flag = 0;
+/* The default state of warnings. */
+
+enum warning_state default_warnings[wt_max];
+
+/* Current state of warnings. */
+
+enum warning_state warnings[wt_max];
+
+/* Global warning settings. */
+
+enum warning_state warn_global;
+
+/* Command line warning flags. */
+
+static struct stringlist *warn_flags = 0;
+
/* If nonzero, we should print a warning message
for each reference to an undefined variable. */
-int warn_undefined_variables_flag;
+static int warn_undefined_variables_flag;
/* If nonzero, always build all targets, regardless of whether
they appear out of date or not. */
@@ -393,7 +410,7 @@ static const char *const usage[] =
-W FILE, --what-if=FILE, --new-file=FILE, --assume-new=FILE\n\
Consider FILE to be infinitely new.\n"),
N_("\
- --warn-undefined-variables Warn when an undefined variable is referenced.\n"),
+ --warn[=CONTROL] Control warnings for makefile issues.\n"),
NULL
};
@@ -439,7 +456,8 @@ struct command_switch
Order matters here: this is the order MAKEFLAGS will be constructed.
So be sure all simple flags (single char, no argument) come first. */
-#define TEMP_STDIN_OPT (CHAR_MAX+10)
+#define TEMP_STDIN_OPT (CHAR_MAX+10)
+#define WARN_OPT (CHAR_MAX+13)
static struct command_switch switches[] =
{
@@ -498,7 +516,8 @@ static struct command_switch switches[] =
{ TEMP_STDIN_OPT, filename, &makefiles, 0, 0, 0, 0, 0, 0, "temp-stdin", 0 },
{ CHAR_MAX+11, string, &shuffle_mode, 1, 1, 0, 0, "random", 0, "shuffle", 0 },
{ CHAR_MAX+12, string, &jobserver_style, 1, 0, 0, 0, 0, 0, "jobserver-style", 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+ { WARN_OPT, strlist, &warn_flags, 1, 1, 0, 0, "warn", NULL, "warn", NULL },
+ { 0, 0, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL }
};
/* Secondary long names for options. */
@@ -644,6 +663,13 @@ initialize_global_hash_tables (void)
hash_init_function_table ();
}
+static void
+initialize_warnings ()
+{
+ /* All warnings must have a default. */
+ default_warnings[wt_undefined_var] = w_ignore;
+}
+
/* This character map locate stop chars when parsing GNU makefiles.
Each element is true if we should stop parsing on that character. */
@@ -858,6 +884,99 @@ decode_debug_flags (void)
debug_flag = 0;
}
+static const char *w_state_map[w_error+1] = {NULL, "ignore", "warn", "error"};
+static const char *w_name_map[wt_max] = {"undefined-var"};
+
+#define encode_warn_state(_b,_s) variable_buffer_output (_b, w_state_map[_s], strlen (w_state_map[_s]))
+#define encode_warn_name(_b,_t) variable_buffer_output (_b, w_name_map[_t], strlen (w_name_map[_t]))
+
+static enum warning_state
+decode_warn_state (const char *state, size_t length)
+{
+ for (enum warning_state st = w_ignore; st <= w_error; ++st)
+ {
+ size_t len = strlen (w_state_map[st]);
+ if (length == len && strncasecmp (state, w_state_map[st], length) == 0)
+ return st;
+ }
+
+ return w_unset;
+}
+
+static enum warning_type
+decode_warn_name (const char *name, size_t length)
+{
+ for (enum warning_type wt = wt_undefined_var; wt < wt_max; ++wt)
+ {
+ size_t len = strlen (w_name_map[wt]);
+ if (length == len && strncasecmp (name, w_name_map[wt], length) == 0)
+ return wt;
+ }
+
+ return wt_max;
+}
+
+static void
+decode_warn_flags ()
+{
+ const char **pp;
+
+ /* */
+ if (warn_undefined_variables_flag)
+ {
+ warn_set (wt_undefined_var, w_warn);
+ warn_undefined_variables_flag = 0;
+ }
+
+ if (warn_flags)
+ for (pp=warn_flags->list; *pp; ++pp)
+ {
+ const char *p = *pp;
+
+ while (*p != '\0')
+ {
+ enum warning_state state;
+ /* See if the value is comma-separated. */
+ const char *ep = strchr (p, ',');
+ if (!ep)
+ ep = p + strlen (p);
+
+ /* If the value is just a state set it globally. */
+ state = decode_warn_state (p, ep - p);
+ if (state != w_unset)
+ warn_global = state;
+ else
+ {
+ enum warning_type type;
+ const char *cp = memchr (p, ':', ep - p);
+ if (!cp)
+ cp = ep;
+ type = decode_warn_name (p, cp - p);
+ if (type == wt_max)
+ ONS (fatal, NILF,
+ _("unknown warning '%.*s'"), (int)(cp - p), p);
+
+ /* If there's a warning state, decode it. */
+ if (cp == ep)
+ state = w_warn;
+ else
+ {
+ ++cp;
+ state = decode_warn_state (cp, ep - cp);
+ if (state == w_unset)
+ ONS (fatal, NILF,
+ _("unknown warning state '%.*s'"), (int)(ep - cp), cp);
+ }
+ warn_set (type, state);
+ }
+
+ p = ep;
+ while (*p == ',')
+ ++p;
+ }
+ }
+}
+
static void
decode_output_sync_flags (void)
{
@@ -1198,7 +1317,9 @@ main (int argc, char **argv, char **envp)
output_init (&make_sync);
- initialize_stopchar_map();
+ initialize_stopchar_map ();
+
+ initialize_warnings ();
#ifdef SET_STACK_SIZE
/* Get rid of any avoidable limit on stack size. */
@@ -3205,8 +3326,9 @@ decode_switches (int argc, const char **argv, enum variable_origin origin)
}
/* Filter out duplicate options.
- * Allow duplicate makefiles for backward compatibility. */
- if (cs->c != 'f')
+ Order matters for warnings.
+ Allow duplicate makefiles for backward compatibility. */
+ if (cs->c != 'f' && cs->c != WARN_OPT)
{
unsigned int k;
for (k = 0; k < sl->idx; ++k)
@@ -3317,6 +3439,7 @@ decode_switches (int argc, const char **argv, enum variable_origin origin)
/* If there are any options that need to be decoded do it now. */
decode_debug_flags ();
+ decode_warn_flags ();
decode_output_sync_flags ();
/* Perform any special switch handling. */
@@ -3527,20 +3650,54 @@ define_makeflags (int makefile)
case filename:
case strlist:
- {
- struct stringlist *sl = *(struct stringlist **) cs->value_ptr;
- if (sl != 0)
- {
- unsigned int i;
- for (i = 0; i < sl->idx; ++i)
+ if (cs->c == WARN_OPT)
+ {
+ enum warning_type wt;
+ char sp = '=';
+
+ /* See if any warning options are set. */
+ for (wt = 0; wt < wt_max; ++wt)
+ if (warnings[wt] != w_unset)
+ break;
+ if (wt == wt_max && warn_global == w_unset)
+ break;
+
+ /* Something is set so construct a --warn option. */
+ fp = variable_buffer_output(fp, STRING_SIZE_TUPLE (" --warn"));
+ if (wt == wt_max && warn_global == w_warn)
+ break;
+
+ if (warn_global > w_unset)
+ {
+ fp = variable_buffer_output (fp, &sp, 1);
+ sp = ',';
+ fp = encode_warn_state (fp, warn_global);
+ }
+ for (wt = 0; wt < wt_max; ++wt)
+ if (warnings[wt] > w_unset)
{
- ADD_OPT (cs);
- if (!short_option (cs->c))
- fp = variable_buffer_output (fp, "=", 1);
- fp = variable_buffer_output (fp, sl->list[i], strlen (sl->list[i]));
+ fp = variable_buffer_output (fp, &sp, 1);
+ sp = ',';
+ fp = encode_warn_name (fp, wt);
+ if (warnings[wt] != w_warn)
+ fp = encode_warn_state (variable_buffer_output(fp, ":", 1), warnings[wt]);
}
- }
- }
+ }
+ else
+ {
+ struct stringlist *sl = *(struct stringlist **) cs->value_ptr;
+ if (sl != 0)
+ {
+ unsigned int i;
+ for (i = 0; i < sl->idx; ++i)
+ {
+ ADD_OPT (cs);
+ if (!short_option (cs->c))
+ fp = variable_buffer_output (fp, "=", 1);
+ fp = variable_buffer_output (fp, sl->list[i], strlen (sl->list[i]));
+ }
+ }
+ }
break;
default: