Ensure error messages are printed with sync'd output.
authorPaul Smith <psmith@gnu.org>
Sun, 28 Apr 2013 23:09:20 +0000 (19:09 -0400)
committerPaul Smith <psmith@gnu.org>
Sun, 28 Apr 2013 23:09:20 +0000 (19:09 -0400)
Enhance the child_error() function so that it will write error output to the
child's sync output buffer, if it exists.  If it doesn't the output goes to
stdout/stderr.

ChangeLog
job.c
makeint.h
misc.c
tests/ChangeLog
tests/scripts/features/output-sync

index 254f9261813aa7c060f23add4186d886c552c350..1144dc2e4fa731cb6df48ec886c1da852bf21fe5 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,12 @@
 2013-04-28  Paul Smith  <psmith@gnu.org>
 
+       * 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 6ee6b8f9bc6b8e31ce41e6d1e32d2567ec3f7bb8..91da29b17369c943e6e5ca3538eb00a39f5add16 100644 (file)
--- a/job.c
+++ b/job.c
@@ -467,19 +467,46 @@ is_bourne_compatible_shell (const char *path)
 }
 
 \f
+/* 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);
 }
 \f
 
@@ -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 */
 
index 3b0336eb4ef1d10c9c5f8d149109274f31a9278d..812ead18cc097c696a84277faadc2cd883ee02ef 100644 (file)
--- a/makeint.h
+++ b/makeint.h
@@ -383,6 +383,10 @@ extern struct rlimit stack_limit;
 
 \f
 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 366e856f639c5cce82a0ca926a78edd0ac89fc04..12b9d3d8fd68fabc0f5973320ee2d5ec6a87f2db 100644 (file)
--- a/misc.c
+++ b/misc.c
@@ -179,6 +179,79 @@ concat (unsigned int num, ...)
   return result;
 }
 \f
+/* 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;
+}
+\f
 /* Print a message on stdout.  */
 
 void
index 642ba8516ab2bdedf5edb4fd396f093b360ca4e8..98c597053224b642b839c9c4ee400f981576b91e 100644 (file)
@@ -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  <psmith@gnu.org>
 
index d1b743d3a364037247a45a7d1908a82dde2c9112..c8ff2911365d5af135e438875733bba67612dd1d 100644 (file)
@@ -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