diff --git a/ChangeLog b/ChangeLog index 254f9261..1144dc2e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ 2013-04-28 Paul Smith + * makeint.h (message_s, error_s): Functions that print to strings + rather than directly to files. + * misc.c (message_s, error_s): Create them. + * job.c (child_error): Print error messages to the output sync + logs, if one exists, rather then directly to the terminal. + (reap_children): Move the per-line sync after child_error(). + * configure.ac: Remove support for pre-ANSI variadic function calls. * makeint.h: Ditto. * misc.c: Ditto. diff --git a/job.c b/job.c index 6ee6b8f9..91da29b1 100644 --- a/job.c +++ b/job.c @@ -467,19 +467,46 @@ is_bourne_compatible_shell (const char *path) } +/* Write a message relating to a child. Write it to the child's output + sync file if present, otherwise to the terminal. */ + +static void +child_out (const struct child *child, const char *msg, int out) +{ + int outfd = out ? child->outfd : child->errfd; + + if (outfd >= 0) + { + lseek (outfd, 0, SEEK_END); + write (outfd, msg, strlen (msg)); + write (outfd, "\n", 1); + } + else + { + FILE *outf = out ? stdout : stderr; + + fputs (msg, outf); + putc ('\n', outf); + fflush (outf); + } +} + /* Write an error message describing the exit status given in EXIT_CODE, EXIT_SIG, and COREDUMP, for the target TARGET_NAME. Append "(ignored)" if IGNORED is nonzero. */ static void -child_error (const struct file *file, +child_error (const struct child *child, int exit_code, int exit_sig, int coredump, int ignored) { - const char *nm; const char *pre = "*** "; const char *post = ""; const char *dump = ""; - gmk_floc *flocp = &file->cmds->fileinfo; + const struct file *f = child->file; + gmk_floc *flocp = &f->cmds->fileinfo; + const char *msg; + const char *nm; + unsigned int l; if (ignored && silent_flag) return; @@ -501,18 +528,32 @@ child_error (const struct file *file, sprintf (a, "%s:%lu", flocp->filenm, flocp->lineno); nm = a; } - message (0, _("%s: recipe for target '%s' failed"), nm, file->name); + + msg = message_s (strlen (nm) + strlen (f->name), + 0, _("%s: recipe for target '%s' failed"), nm, f->name); + child_out (child, msg, 1); + + l = strlen (pre) + strlen (f->name) + strlen (post); #ifdef VMS - if (!(exit_code & 1)) - error (NILF, _("%s[%s] Error 0x%x%s"), pre, file->name, exit_code, post); + if (exit_code & 1 != 0) + return; + + msg = error_s (l + INTEGER_LENGTH, NILF, _("%s[%s] Error 0x%x%s"), + pre, f->name, exit_code, post); #else if (exit_sig == 0) - error (NILF, _("%s[%s] Error %d%s"), pre, file->name, exit_code, post); + msg = error_s (l + INTEGER_LENGTH, NILF, _("%s[%s] Error %d%s"), + pre, f->name, exit_code, post); else - error (NILF, _("%s[%s] %s%s%s"), - pre, file->name, strsignal (exit_sig), dump, post); + { + const char *s = strsignal (exit_sig); + msg = error_s (l + strlen (s) + strlen (dump), + NILF, _("%s[%s] %s%s%s"), pre, f->name, s, dump, post); + } #endif /* VMS */ + + child_out (child, msg, 0); } @@ -1006,11 +1047,6 @@ reap_children (int block, int err) c->sh_batch_file = NULL; } -#ifdef OUTPUT_SYNC - if (output_sync == OUTPUT_SYNC_JOB) - sync_output (c); -#endif - /* If this child had the good stdin, say it is now free. */ if (c->good_stdin) good_stdin_used = 0; @@ -1024,7 +1060,7 @@ reap_children (int block, int err) static int delete_on_error = -1; if (!dontcare) - child_error (c->file, exit_code, exit_sig, coredump, 0); + child_error (c, exit_code, exit_sig, coredump, 0); c->file->update_status = 2; if (delete_on_error == -1) @@ -1040,7 +1076,7 @@ reap_children (int block, int err) if (child_failed) { /* The commands failed, but we don't care. */ - child_error (c->file, exit_code, exit_sig, coredump, 1); + child_error (c, exit_code, exit_sig, coredump, 1); child_failed = 0; } @@ -1057,6 +1093,11 @@ reap_children (int block, int err) } else { +#ifdef OUTPUT_SYNC + /* If we're sync'ing per job, write it now. */ + if (output_sync == OUTPUT_SYNC_JOB) + sync_output (c); +#endif /* Check again whether to start remotely. Whether or not we want to changes over time. Also, start_remote_job may need state set up @@ -1089,7 +1130,7 @@ reap_children (int block, int err) #ifdef OUTPUT_SYNC /* Synchronize parallel output if requested */ - if (output_sync > OUTPUT_SYNC_JOB) + if (output_sync) sync_output (c); #endif /* OUTPUT_SYNC */ diff --git a/makeint.h b/makeint.h index 3b0336eb..812ead18 100644 --- a/makeint.h +++ b/makeint.h @@ -383,6 +383,10 @@ extern struct rlimit stack_limit; const char *concat (unsigned int, ...); +const char *message_s (unsigned int length, int prefix, const char *fmt, ...) + __attribute__ ((__format__ (__printf__, 3, 4))); +const char *error_s (unsigned int length, const gmk_floc *flocp, const char *fmt, ...) + __attribute__ ((__format__ (__printf__, 3, 4))); void message (int prefix, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 2, 3))); void error (const gmk_floc *flocp, const char *fmt, ...) diff --git a/misc.c b/misc.c index 366e856f..12b9d3d8 100644 --- a/misc.c +++ b/misc.c @@ -179,6 +179,79 @@ concat (unsigned int num, ...) return result; } +/* If we had a standard-compliant vsnprintf() this would be a lot simpler. + Maybe in the future we'll include gnulib's version. */ + +/* Return a formatted string buffer. */ + +const char * +message_s (unsigned int length, int prefix, const char *fmt, ...) +{ + static char *buffer = NULL; + static unsigned int bsize = 0; + char *bp; + va_list args; + + /* Compute the maximum buffer size we'll need, and make sure we have it. */ + length += strlen (fmt) + strlen (program) + 4 + INTEGER_LENGTH + 1; + if (length > bsize) + { + bsize = length * 2; + buffer = xrealloc (buffer, bsize); + } + + bp = buffer; + if (prefix) + { + if (makelevel == 0) + sprintf (bp, "%s: ", program); + else + sprintf (bp, "%s[%u]: ", program, makelevel); + bp += strlen (buffer); + } + + va_start (args, fmt); + vsprintf (bp, fmt, args); + va_end (args); + + return buffer; +} + +/* Return a formatted error message in a buffer. */ + +const char * +error_s (unsigned int length, const gmk_floc *flocp, const char *fmt, ...) +{ + static char *buffer = NULL; + static unsigned int bsize = 0; + char *bp; + va_list args; + + /* Compute the maximum buffer size we'll need, and make sure we have it. */ + length += (strlen (fmt) + strlen (program) + 4 + INTEGER_LENGTH + 1 + + (flocp && flocp->filenm ? strlen (flocp->filenm) : 0)); + if (length > bsize) + { + bsize = length * 2; + buffer = xrealloc (buffer, bsize); + } + + bp = buffer; + if (flocp && flocp->filenm) + sprintf (bp, "%s:%lu: ", flocp->filenm, flocp->lineno); + else if (makelevel == 0) + sprintf (bp, "%s: ", program); + else + sprintf (bp, "%s[%u]: ", program, makelevel); + bp += strlen (bp); + + va_start (args, fmt); + vsprintf (bp, fmt, args); + va_end (args); + + return buffer; +} + /* Print a message on stdout. */ void diff --git a/tests/ChangeLog b/tests/ChangeLog index 642ba851..98c59705 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -2,6 +2,7 @@ * scripts/features/output-sync (output_sync_set): Add tests for the per-job syntax mode. + (output_sync_set): Test improved error message location. 2013-04-15 Paul Smith diff --git a/tests/scripts/features/output-sync b/tests/scripts/features/output-sync index d1b743d3..c8ff2911 100644 --- a/tests/scripts/features/output-sync +++ b/tests/scripts/features/output-sync @@ -197,14 +197,10 @@ bar: end #MAKE#[1]: Leaving directory '#PWD#/bar' #MAKE#[1]: Leaving directory '#PWD#/bar' #MAKE#[1]: Entering directory '#PWD#/foo' -Makefile:20: recipe for target 'foo-fail' failed -#MAKE#[1]: Leaving directory '/home/psmith/src/make/make/tests/foo' -#MAKE#[1]: Entering directory '/home/psmith/src/make/make/tests/foo' -#MAKE#[1]: *** [foo-fail] Error 1 -#MAKE#[1]: Leaving directory '/home/psmith/src/make/make/tests/foo' -#MAKE#[1]: Entering directory '/home/psmith/src/make/make/tests/foo' foo-fail: start foo-fail: end +Makefile:20: recipe for target 'foo-fail' failed +#MAKE#[1]: *** [foo-fail] Error 1 #MAKE#[1]: Leaving directory '#PWD#/foo' #MAKE#[1]: Leaving directory '#PWD#/foo' #MAKEFILE#:4: recipe for target 'make-foo-fail' failed