summaryrefslogtreecommitdiff
path: root/src/main.c
diff options
context:
space:
mode:
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: