Ensure that output generated while reading makefiles is synced.
authorPaul Smith <psmith@gnu.org>
Sat, 21 Sep 2013 21:24:59 +0000 (17:24 -0400)
committerPaul Smith <psmith@gnu.org>
Sat, 21 Sep 2013 21:24:59 +0000 (17:24 -0400)
ChangeLog
main.c
output.h
tests/ChangeLog
tests/scripts/features/output-sync

index f4a897e8e078e7e1a9658262f4582831674c9cef..cc9ed4eeef7006711bf223a3567dc49a97a86f2a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,15 @@
 2013-09-21  Paul Smith  <psmith@gnu.org>
 
+       Output generated while reading makefiles should be synced.
+
+       * main.c (make_sync): Define a context for syncing while reading
+       makefiles and other top-level operations.
+       (main): If we request syncing, enable it while we are parsing
+       options, reading makefiles, etc. to capture that output.  Just
+       before we start to run rules, dump the output if any.
+       (die): Dump any output we've been syncing before we die
+       * output.h (OUTPUT_SET): Disable output_context if not syncout.
+
        Stderr generated from shell functions in recipes should be synced.
 
        * job.h (FD_STDIN, FD_STDOUT, FD_STDERR): Create new macros to
diff --git a/main.c b/main.c
index bd8b478a63fbcaa2e07f4cf6a6e1ca4ab863f4d5..f0a7174dbb9951265bcdaedfa435abb8525d85f2 100644 (file)
--- a/main.c
+++ b/main.c
@@ -550,6 +550,11 @@ int clock_skew_detected;
 #endif
 unsigned short stopchar_map[UCHAR_MAX + 1] = {0};
 
+/* If output-sync is enabled we'll collect all the output generated due to
+   options, while reading makefiles, etc.  */
+
+struct output make_sync;
+
 \f
 /* Mask of signals that are being caught with fatal_error_signal.  */
 
@@ -1041,6 +1046,7 @@ main (int argc, char **argv, char **envp)
   struct dep *read_files;
   PATH_VAR (current_directory);
   unsigned int restarts = 0;
+  unsigned int syncing = 0;
 #ifdef WINDOWS32
   char *unix_path = NULL;
   char *windows32_path = NULL;
@@ -1052,6 +1058,8 @@ main (int argc, char **argv, char **envp)
   no_default_sh_exe = 1;
 #endif
 
+  output_init (&make_sync);
+
   initialize_stopchar_map();
 
 #ifdef SET_STACK_SIZE
@@ -1390,6 +1398,13 @@ main (int argc, char **argv, char **envp)
   decode_env_switches (STRING_SIZE_TUPLE ("GNUMAKEFLAGS"));
   decode_env_switches (STRING_SIZE_TUPLE ("MAKEFLAGS"));
 
+  /* In output sync mode we need to sync any output generated by reading the
+     makefiles, such as in $(info ...) or stderr from $(shell ...) etc.  */
+
+  syncing = make_sync.syncout = (output_sync == OUTPUT_SYNC_LINE
+                                 || output_sync == OUTPUT_SYNC_TARGET);
+  OUTPUT_SET (&make_sync);
+
 #if 0
   /* People write things like:
         MFLAGS="CC=gcc -pipe" "CFLAGS=-g"
@@ -1399,6 +1414,16 @@ main (int argc, char **argv, char **envp)
 
   decode_switches (argc, argv, 0);
 
+  /* Reset in case the switches changed our minds.  */
+  syncing = (output_sync == OUTPUT_SYNC_LINE
+             || output_sync == OUTPUT_SYNC_TARGET);
+
+  if (make_sync.syncout && ! syncing)
+    output_close (&make_sync);
+
+  make_sync.syncout = syncing;
+  OUTPUT_SET (&make_sync);
+
   /* Figure out the level of recursion.  */
   {
     struct variable *v = lookup_variable (STRING_SIZE_TUPLE (MAKELEVEL_NAME));
@@ -1907,6 +1932,16 @@ main (int argc, char **argv, char **envp)
     decode_env_switches (STRING_SIZE_TUPLE ("MFLAGS"));
 #endif
 
+    /* Reset in case the switches changed our minds.  */
+    syncing = (output_sync == OUTPUT_SYNC_LINE
+               || output_sync == OUTPUT_SYNC_TARGET);
+
+    if (make_sync.syncout && ! syncing)
+      output_close (&make_sync);
+
+    make_sync.syncout = syncing;
+    OUTPUT_SET (&make_sync);
+
     /* If we've disabled builtin rules, get rid of them.  */
     if (no_builtin_rules_flag && ! old_builtin_rules_flag)
       {
@@ -2077,6 +2112,11 @@ main (int argc, char **argv, char **envp)
   /* Initialize the remote job module.  */
   remote_setup ();
 
+  /* Dump any output we've collected.  */
+
+  OUTPUT_UNSET ();
+  output_close (&make_sync);
+
   if (read_files != 0)
     {
       /* Update any makefiles if necessary.  */
@@ -3358,6 +3398,13 @@ die (int status)
 
       clean_jobserver (status);
 
+      if (output_context)
+        {
+          assert (output_context == &make_sync);
+          OUTPUT_UNSET ();
+          output_close (&make_sync);
+        }
+
       output_close (NULL);
 
       /* Try to move back to the original directory.  This is essential on
index 1f0e2d7cf8725b1bed57cd2d6b98ea2156bfa6c9..5fef436cef625f901fcf6f889840f1bc8401a24f 100644 (file)
--- a/output.h
+++ b/output.h
@@ -24,7 +24,7 @@ struct output
 extern struct output *output_context;
 extern unsigned int stdio_traced;
 
-#define OUTPUT_SET(_new)    do{ if ((_new)->syncout) output_context = (_new); }while(0)
+#define OUTPUT_SET(_new)    do{ output_context = (_new)->syncout ? (_new) : NULL; }while(0)
 #define OUTPUT_UNSET()      do{ output_context = NULL; }while(0)
 
 #define OUTPUT_TRACED()     do{ stdio_traced = 1; }while(0)
index e0e9475ea1465e86ddced77b9d2bbc8520ff2352..cbcaa0366fca67d3b877801020d04143e63f7f5b 100644 (file)
@@ -1,7 +1,10 @@
 2013-09-21  Paul Smith  <psmith@gnu.org>
 
        * scripts/features/output-sync: Test shell functions writing to
-       stderr in recipes: ensure it's captured via output-sync.
+       stderr in recipes: ensure it's captured via output-sync.  Test
+       output generated while reading makefiles and make sure it's
+       captured via output-sync.  Make sure that fatal errors dump the
+       output so it's not lost.
 
        * scripts/options/dash-w: Add a test for -w flag.
 
index e09505fda65a8b87666ae8e6013da8e67b256bcb..3bb99976e9dbdabdf4c80f6e0d1fc344755c99c8 100644 (file)
@@ -267,5 +267,65 @@ all: ; @: $(shell echo foo 1>&2)
 !,
               '-w -Oline', "#MAKE#: Entering directory '#PWD#'\nfoo\n#MAKE#: Leaving directory '#PWD#'\n");
 
+# Ensure that output generated while parsing makefiles is synced
+# when appropriate.
+run_make_test(q!
+$(shell echo foo 1>&2)
+all: ; echo bar
+!,
+              '-s -w -Otarget', "#MAKE#: Entering directory '#PWD#'\nfoo\n#MAKE#: Leaving directory '#PWD#'\n#MAKE#: Entering directory '#PWD#'\nbar\n#MAKE#: Leaving directory '#PWD#'\n");
+
+# Test recursion
+$m1 = get_tmpfile();
+$m2 = get_tmpfile();
+
+open(M1, "> $m1");
+print M1 <<'EOF';
+$(shell echo d1 stderr 1>&2)
+$(info d1 stdout)
+all:; @:
+EOF
+close(M1);
+
+open(M2, "> $m2");
+print M2 <<'EOF';
+$(shell echo d2 stderr 1>&2)
+$(info d2 stdout)
+all:; @:
+# Force an ordering on the output
+$(shell sleep 1)
+EOF
+close(M2);
+
+run_make_test(qq!
+all: t1 t2
+t1: ; \@\$(MAKE) -f $m1
+t2: ; \@\$(MAKE) -f $m2
+!,
+              "-j -Oline", "#MAKE#[1]: Entering directory '#PWD#'\nd1 stderr\nd1 stdout\n#MAKE#[1]: Leaving directory '#PWD#'\n#MAKE#[1]: Entering directory '#PWD#'\nd2 stderr\nd2 stdout\n#MAKE#[1]: Leaving directory '#PWD#'\n");
+
+rmfiles($m1, $m2);
+
+# Ensure that output generated while parsing makefiles is synced
+# when appropriate.
+$m1 = get_tmpfile();
+
+open(M1, "> $m1");
+print M1 <<'EOF';
+$(shell echo d1 stderr 1>&2)
+$(info d1 stdout)
+$(error d1 failed)
+all:; @:
+EOF
+close(M1);
+
+run_make_test(qq!
+all: t1
+t1: ; -\@\$(MAKE) -f $m1
+!,
+              "-j -Oline", "#MAKE#[1]: Entering directory '#PWD#'\nd1 stderr\nd1 stdout\n$m1:3: *** d1 failed.  Stop.\n#MAKE#[1]: Leaving directory '#PWD#'\n#MAKEFILE#:3: recipe for target 't1' failed\n#MAKE#: [t1] Error 2 (ignored)\n");
+
+rmfiles($m1);
+
 # This tells the test driver that the perl test script executed properly.
 1;