From 047bd5a16f5ba39e778d3438777147e583e3f3b2 Mon Sep 17 00:00:00 2001 From: Paul Smith Date: Sun, 10 Apr 2016 17:12:48 -0400 Subject: [PATCH] [SV 46433] Show recipe line offsets in line number messages. While displaying line numbers, show the relevant line number inside the recipe not just the first line of the entire recipe. Sample changes suggested by Brian Vandenberg * gnumake.h (gmk_floc): Add an 'offset' to track the recipe offset. * read.c (eval, eval_makefile, eval_buffer): Initialize 'offset'. (record_files, install_pattern_rule): Ditto. * job.c (new_job, job_next_command): Update 'offset' based on the line of the recipe we're expanding or invoking. (child_error): Add 'offset' when showing the line number. * function.c (func_shell_base): Ditto. * output.c (error, fatal): Ditto. * NEWS: Mention the new ability. * tests/scripts/features/errors: Check the line number on errors. * tests/scripts/functions/warning: Check the line number on warnings. * tests/scripts/features/output-sync, tests/scripts/features/parallelism, tests/scripts/functions/shell, tests/scripts/functions/error: Update line numbers. --- NEWS | 6 +++++- function.c | 3 ++- gnumake.h | 1 + job.c | 7 ++++++- output.c | 4 ++-- read.c | 4 ++++ rule.c | 1 + tests/scripts/features/errors | 14 ++++++++++++++ tests/scripts/features/output-sync | 2 +- tests/scripts/features/parallelism | 6 +++--- tests/scripts/functions/error | 10 ++++------ tests/scripts/functions/shell | 13 +++++++++++++ tests/scripts/functions/warning | 30 ++++++++++++++++++++++++------ variable.c | 2 +- 14 files changed, 81 insertions(+), 22 deletions(-) diff --git a/NEWS b/NEWS index 4a38e4fe..2c46e1e1 100644 --- a/NEWS +++ b/NEWS @@ -24,6 +24,10 @@ http://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=106&set The function is expanded to the contents of the file. The contents are expanded verbatim except that the final newline, if any, is stripped. +* The makefile line numbers shown by GNU make now point directly to the + specific line in the recipe where the failure or warning occurred. + Sample changes suggested by Brian Vandenberg + * The interface to GNU make's "jobserver" is stable as documented in the manual, for tools which may want to access it. @@ -32,7 +36,7 @@ http://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=106&set * The amount of parallelism can be determined by querying MAKEFLAGS, even when the job server is enabled (previously MAKEFLAGS would always contain only - "-j" when job server was enabled). + "-j", with no number, when job server was enabled). * VMS-specific changes: diff --git a/function.c b/function.c index 28015981..b8e69b22 100644 --- a/function.c +++ b/function.c @@ -1734,7 +1734,8 @@ func_shell_base (char *o, char **argv, int trim_newlines) if (reading_file && reading_file->filenm) { char *p = alloca (strlen (reading_file->filenm)+11+4); - sprintf (p, "%s:%lu: ", reading_file->filenm, reading_file->lineno); + sprintf (p, "%s:%lu: ", reading_file->filenm, + reading_file->lineno + reading_file->offset); error_prefix = p; } else diff --git a/gnumake.h b/gnumake.h index b508562f..5b441e58 100644 --- a/gnumake.h +++ b/gnumake.h @@ -24,6 +24,7 @@ typedef struct { const char *filenm; unsigned long lineno; + unsigned long offset; } gmk_floc; typedef char *(*gmk_func_ptr)(const char *nm, unsigned int argc, char **argv); diff --git a/job.c b/job.c index 59f51cd2..2d2c8037 100644 --- a/job.c +++ b/job.c @@ -500,7 +500,7 @@ child_error (struct child *child, else { char *a = alloca (strlen (flocp->filenm) + 1 + 11 + 1); - sprintf (a, "%s:%lu", flocp->filenm, flocp->lineno); + sprintf (a, "%s:%lu", flocp->filenm, flocp->lineno + flocp->offset); nm = a; } @@ -1745,10 +1745,12 @@ new_job (struct file *file) memmove (out, in, strlen (in) + 1); /* Finally, expand the line. */ + cmds->fileinfo.offset = i; lines[i] = allocated_variable_expand_for_file (cmds->command_lines[i], file); } + cmds->fileinfo.offset = 0; c->command_lines = lines; /* Fetch the first command line to be run. */ @@ -1873,12 +1875,15 @@ job_next_command (struct child *child) { /* There are no more lines to be expanded. */ child->command_ptr = 0; + child->file->cmds->fileinfo.offset = 0; return 0; } else /* Get the next line to run. */ child->command_ptr = child->command_lines[child->command_line++]; } + + child->file->cmds->fileinfo.offset = child->command_line - 1; return 1; } diff --git a/output.c b/output.c index 7e905cc3..475862f0 100644 --- a/output.c +++ b/output.c @@ -651,7 +651,7 @@ error (const gmk_floc *flocp, size_t len, const char *fmt, ...) p = get_buffer (len); if (flocp && flocp->filenm) - sprintf (p, "%s:%lu: ", flocp->filenm, flocp->lineno); + sprintf (p, "%s:%lu: ", flocp->filenm, flocp->lineno + flocp->offset); else if (makelevel == 0) sprintf (p, "%s: ", program); else @@ -683,7 +683,7 @@ fatal (const gmk_floc *flocp, size_t len, const char *fmt, ...) p = get_buffer (len); if (flocp && flocp->filenm) - sprintf (p, "%s:%lu: *** ", flocp->filenm, flocp->lineno); + sprintf (p, "%s:%lu: *** ", flocp->filenm, flocp->lineno + flocp->offset); else if (makelevel == 0) sprintf (p, "%s: *** ", program); else diff --git a/read.c b/read.c index 10b250e7..a71eaebe 100644 --- a/read.c +++ b/read.c @@ -324,6 +324,7 @@ eval_makefile (const char *filename, int flags) ebuf.floc.filenm = filename; /* Use the original file name. */ ebuf.floc.lineno = 1; + ebuf.floc.offset = 0; if (ISDB (DB_VERBOSE)) { @@ -470,6 +471,7 @@ eval_buffer (char *buffer, const gmk_floc *floc) { ebuf.floc.filenm = NULL; ebuf.floc.lineno = 1; + ebuf.floc.offset = 0; } curfile = reading_file; @@ -592,6 +594,7 @@ eval (struct ebuffer *ebuf, int set_default) if (filenames != 0) \ { \ fi.lineno = tgts_started; \ + fi.offset = 0; \ record_files (filenames, pattern, pattern_percent, depstr, \ cmds_started, commands, commands_idx, two_colon, \ prefix, &fi); \ @@ -1958,6 +1961,7 @@ record_files (struct nameseq *filenames, const char *pattern, cmds = xmalloc (sizeof (struct commands)); cmds->fileinfo.filenm = flocp->filenm; cmds->fileinfo.lineno = cmds_started; + cmds->fileinfo.offset = 0; cmds->commands = xstrndup (commands, commands_idx); cmds->command_lines = 0; cmds->recipe_prefix = prefix; diff --git a/rule.c b/rule.c index fce8372c..de8b3046 100644 --- a/rule.c +++ b/rule.c @@ -380,6 +380,7 @@ install_pattern_rule (struct pspec *p, int terminal) r->cmds = xmalloc (sizeof (struct commands)); r->cmds->fileinfo.filenm = 0; r->cmds->fileinfo.lineno = 0; + r->cmds->fileinfo.offset = 0; /* These will all be string literals, but we malloc space for them anyway because somebody might want to free them later. */ r->cmds->commands = xstrdup (p->commands); diff --git a/tests/scripts/features/errors b/tests/scripts/features/errors index 43b81d4d..ebd43831 100644 --- a/tests/scripts/features/errors +++ b/tests/scripts/features/errors @@ -90,4 +90,18 @@ if (!$vos) { &compare_output($answer,&get_logfile(1)); } +# Test that error line offset works + +run_make_test(q! +all: + @echo hi + @echo there + @exit 1 +!, + '', "hi\nthere\n#MAKE#: *** [#MAKEFILE#:5: all] Error 1", 512); + 1; + +### Local Variables: +### eval: (setq whitespace-action (delq 'auto-cleanup whitespace-action)) +### End: diff --git a/tests/scripts/features/output-sync b/tests/scripts/features/output-sync index 64d6fe08..7139e002 100644 --- a/tests/scripts/features/output-sync +++ b/tests/scripts/features/output-sync @@ -204,7 +204,7 @@ bar: end #MAKE#[1]: Entering directory '#PWD#/foo' foo-fail: start foo-fail: end -#MAKE#[1]: *** [Makefile:20: foo-fail] Error 1 +#MAKE#[1]: *** [Makefile:23: foo-fail] Error 1 #MAKE#[1]: Leaving directory '#PWD#/foo' #MAKE#: *** [#MAKEFILE#:4: make-foo-fail] Error 2\n", 512); diff --git a/tests/scripts/features/parallelism b/tests/scripts/features/parallelism index 6b9efe1b..fabe5485 100644 --- a/tests/scripts/features/parallelism +++ b/tests/scripts/features/parallelism @@ -99,12 +99,12 @@ ok: \@$sleep_command 4 \@echo Ok done", '-rR -j5', "Fail -#MAKE#: *** [#MAKEFILE#:6: fail.1] Error 1 +#MAKE#: *** [#MAKEFILE#:8: fail.1] Error 1 #MAKE#: *** Waiting for unfinished jobs.... Fail -#MAKE#: *** [#MAKEFILE#:6: fail.2] Error 1 +#MAKE#: *** [#MAKEFILE#:8: fail.2] Error 1 Fail -#MAKE#: *** [#MAKEFILE#:6: fail.3] Error 1 +#MAKE#: *** [#MAKEFILE#:8: fail.3] Error 1 Ok done", 512); diff --git a/tests/scripts/functions/error b/tests/scripts/functions/error index 0d61177f..998afe48 100644 --- a/tests/scripts/functions/error +++ b/tests/scripts/functions/error @@ -54,7 +54,7 @@ $answer = "Some stuff\n$makefile:12: *** error is maybe. Stop.\n"; # Test #4 &run_make_with_options($makefile, "ERROR4=definitely", &get_logfile, 512); -$answer = "Some stuff\n$makefile:16: *** error is definitely. Stop.\n"; +$answer = "Some stuff\n$makefile:17: *** error is definitely. Stop.\n"; &compare_output($answer,&get_logfile(1)); # Test #5 @@ -66,8 +66,6 @@ $answer = "$makefile:22: *** Error found!. Stop.\n"; # This tells the test driver that the perl test script executed properly. 1; - - - - - +### Local Variables: +### eval: (setq whitespace-action (delq 'auto-cleanup whitespace-action)) +### End: diff --git a/tests/scripts/functions/shell b/tests/scripts/functions/shell index 4702b096..809c77fa 100644 --- a/tests/scripts/functions/shell +++ b/tests/scripts/functions/shell @@ -44,4 +44,17 @@ export HI = $(shell echo hi) all: ; @echo $$HI ','','hi'); +# Test shell errors in recipes including offset +run_make_test(' +all: + @echo hi + $(shell ./basdfdfsed there) + @echo there +', + '', "#MAKE#: ./basdfdfsed: Command not found\nhi\nthere\n"); + 1; + +### Local Variables: +### eval: (setq whitespace-action (delq 'auto-cleanup whitespace-action)) +### End: diff --git a/tests/scripts/functions/warning b/tests/scripts/functions/warning index cd452d41..16eb83bb 100644 --- a/tests/scripts/functions/warning +++ b/tests/scripts/functions/warning @@ -52,14 +52,32 @@ $answer = "Some stuff\n$makefile:10: warning is maybe\nhi\n"; # Test #4 &run_make_with_options($makefile, "WARNING4=definitely", &get_logfile, 0); -$answer = "Some stuff\n$makefile:14: warning is definitely\nhi\nthere\n"; +$answer = "Some stuff\n$makefile:15: warning is definitely\nhi\nthere\n"; &compare_output($answer,&get_logfile(1)); +# Test linenumber offset + +run_make_test(q! +all: one two + $(warning in $@ line 3) + @true + $(warning in $@ line 5) + +one two: + $(warning in $@ line 8) + @true + $(warning in $@ line 10) +!, + '', "#MAKEFILE#:8: in one line 8 +#MAKEFILE#:10: in one line 10 +#MAKEFILE#:8: in two line 8 +#MAKEFILE#:10: in two line 10 +#MAKEFILE#:3: in all line 3 +#MAKEFILE#:5: in all line 5\n"); + # This tells the test driver that the perl test script executed properly. 1; - - - - - +### Local Variables: +### eval: (setq whitespace-action (delq 'auto-cleanup whitespace-action)) +### End: diff --git a/variable.c b/variable.c index edbe5945..b0d8d69c 100644 --- a/variable.c +++ b/variable.c @@ -1657,7 +1657,7 @@ print_variable (const void *item, void *arg) fputs (" private", stdout); if (v->fileinfo.filenm) printf (_(" (from '%s', line %lu)"), - v->fileinfo.filenm, v->fileinfo.lineno); + v->fileinfo.filenm, v->fileinfo.lineno + v->fileinfo.offset); putchar ('\n'); fputs (prefix, stdout);