Ensure command lines are written synchronously with -O.

If output-sync is enabled, have make write the command line to the temp file
instead of printing it directly to the screen to ensure that the output is
ordered properly.  Also, remove extraneous enter/leave operations by having
them printed directly when dumping temp file output.
This commit is contained in:
Paul Smith 2013-05-05 17:03:51 -04:00
parent 3484c9675a
commit 1d992d8fe7
5 changed files with 96 additions and 100 deletions

View File

@ -1,3 +1,15 @@
2013-05-05 Paul Smith <psmith@gnu.org>
* job.c (child_out): Write newlines explicitly, and don't do
anything if the message is empty.
(sync_output): Put working dir messages around stdout AND stderr.
(start_job_command): Move the tmp file assignment earlier. After
we do it, write the command line to the temp file to get the order
correct.
* misc.c (message): Remove special handling for output_sync.
(error): Ditto.
2013-05-04 Paul Smith <psmith@gnu.org> 2013-05-04 Paul Smith <psmith@gnu.org>
* loadapi.c (gmk_alloc): New function. * loadapi.c (gmk_alloc): New function.

126
job.c
View File

@ -478,14 +478,17 @@ child_out (const struct child *child, const char *msg, int out)
{ {
int fd = out ? child->outfd : child->errfd; int fd = out ? child->outfd : child->errfd;
if (!msg || msg[0] == '\0')
return;
if (fd >= 0) if (fd >= 0)
{ {
int len = strlen (msg); int len = strlen (msg);
int b;
lseek (fd, 0, SEEK_END); lseek (fd, 0, SEEK_END);
while (1) while (1)
{ {
int b;
EINTRLOOP (b, write (fd, msg, len)); EINTRLOOP (b, write (fd, msg, len));
if (b == len) if (b == len)
break; break;
@ -494,12 +497,14 @@ child_out (const struct child *child, const char *msg, int out)
len -= b; len -= b;
msg += b; msg += b;
} }
EINTRLOOP (b, write (fd, "\n", 1));
} }
else else
{ {
FILE *f = out ? stdout : stderr; FILE *f = out ? stdout : stderr;
fputs (msg, f); fputs (msg, f);
fflush (f); fflush (f);
putc ('\n', f);
} }
} }
@ -548,7 +553,7 @@ child_error (const struct child *child,
l = strlen (pre) + strlen (f->name) + strlen (post); l = strlen (pre) + strlen (f->name) + strlen (post);
#ifdef VMS #ifdef VMS
if (exit_code & 1 != 0) if ((exit_code & 1) != 0)
return; return;
msg = error_s (l + INTEGER_LENGTH, NILF, msg = error_s (l + INTEGER_LENGTH, NILF,
@ -651,28 +656,28 @@ sync_init ()
static void static void
assign_child_tempfiles (struct child *c) assign_child_tempfiles (struct child *c)
{ {
/* If we have a temp file, we're done. */ /* If we don't have a temp file, get one. */
if (c->outfd >= 0 || c->errfd >= 0) if (c->outfd < 0 && c->errfd < 0)
return;
if (STREAM_OK (stdout))
{ {
c->outfd = open_tmpfd (); if (STREAM_OK (stdout))
if (c->outfd < 0)
goto error;
CLOSE_ON_EXEC (c->outfd);
}
if (STREAM_OK (stderr))
{
if (c->outfd >= 0 && combined_output)
c->errfd = c->outfd;
else
{ {
c->errfd = open_tmpfd (); c->outfd = open_tmpfd ();
if (c->errfd < 0) if (c->outfd < 0)
goto error; goto error;
CLOSE_ON_EXEC (c->errfd); CLOSE_ON_EXEC (c->outfd);
}
if (STREAM_OK (stderr))
{
if (c->outfd >= 0 && combined_output)
c->errfd = c->outfd;
else
{
c->errfd = open_tmpfd ();
if (c->errfd < 0)
goto error;
CLOSE_ON_EXEC (c->errfd);
}
} }
} }
@ -765,14 +770,12 @@ sync_output (struct child *c)
/* We've entered the "critical section" during which a lock is held. /* We've entered the "critical section" during which a lock is held.
We want to keep it as short as possible. */ We want to keep it as short as possible. */
log_working_directory (1, 1);
if (outfd_not_empty) if (outfd_not_empty)
{
log_working_directory (1, 1);
pump_from_tmp (c->outfd, stdout); pump_from_tmp (c->outfd, stdout);
log_working_directory (0, 1);
}
if (errfd_not_empty && c->errfd != c->outfd) if (errfd_not_empty && c->errfd != c->outfd)
pump_from_tmp (c->errfd, stderr); pump_from_tmp (c->errfd, stderr);
log_working_directory (0, 1);
/* Exit the critical section. */ /* Exit the critical section. */
if (sem) if (sem)
@ -1375,7 +1378,8 @@ start_job_command (struct child *child)
#if !defined(_AMIGA) && !defined(WINDOWS32) #if !defined(_AMIGA) && !defined(WINDOWS32)
static int bad_stdin = -1; static int bad_stdin = -1;
#endif #endif
int sync_cmd = 0; int print_cmd;
int sync_cmd;
char *p; char *p;
/* Must be volatile to silence bogus GCC warning about longjmp/vfork. */ /* Must be volatile to silence bogus GCC warning about longjmp/vfork. */
volatile int flags; volatile int flags;
@ -1503,13 +1507,40 @@ start_job_command (struct child *child)
return; return;
} }
/* Print out the command. If silent, we call 'message' with null so it print_cmd = (just_print_flag || trace_flag
can log the working directory before the command's own error messages || (!(flags & COMMANDS_SILENT) && !silent_flag));
appear. */
message (0, (just_print_flag || trace_flag #ifdef OUTPUT_SYNC
|| (!(flags & COMMANDS_SILENT) && !silent_flag)) if (output_sync && sync_handle == -1)
? "%s" : (char *) 0, p); sync_init();
#endif
/* Are we going to synchronize this command's output? Do so if either we're
in SYNC_MAKE mode or this command is not recursive. We'll also check
output_sync separately below in case it changes due to error. */
sync_cmd = output_sync && (output_sync == OUTPUT_SYNC_MAKE
|| !(flags & COMMANDS_RECURSE));
#ifdef OUTPUT_SYNC
if (sync_cmd)
{
/* If syncing, make sure we have temp files.
Write the command to the temp file so it's output in order. */
assign_child_tempfiles (child);
if (print_cmd)
child_out (child, p, 1);
}
else
/* We don't want to sync this command: to avoid misordered
output ensure any already-synced content is written. */
sync_output (child);
#endif /* OUTPUT_SYNC */
/* If we're not syncing, print out the command. If silent, we call
'message' with null so it can log the working directory before the
command's own error messages appear. */
if (! sync_cmd)
message (0, print_cmd ? "%s" : NULL, p);
/* Tell update_goal_chain that a command has been started on behalf of /* Tell update_goal_chain that a command has been started on behalf of
this target. It is important that this happens here and not in this target. It is important that this happens here and not in
@ -1563,11 +1594,6 @@ start_job_command (struct child *child)
fflush (stdout); fflush (stdout);
fflush (stderr); fflush (stderr);
/* Are we going to synchronize this command's output? Do so if either we're
in SYNC_MAKE mode or this command is not recursive. We'll also check
output_sync separately below in case it changes due to error. */
sync_cmd = output_sync == OUTPUT_SYNC_MAKE || !(flags & COMMANDS_RECURSE);
#ifndef VMS #ifndef VMS
#if !defined(WINDOWS32) && !defined(_AMIGA) && !defined(__MSDOS__) #if !defined(WINDOWS32) && !defined(_AMIGA) && !defined(__MSDOS__)
@ -1692,19 +1718,6 @@ start_job_command (struct child *child)
#else /* !__EMX__ */ #else /* !__EMX__ */
#ifdef OUTPUT_SYNC
if (output_sync && sync_handle == -1)
sync_init();
if (output_sync && sync_cmd)
/* If we still want to sync, make sure we have temp files. */
assign_child_tempfiles (child);
else
/* We don't want to sync this command: to avoid misordered
output ensure any already-synched content is written. */
sync_output (child);
#endif /* OUTPUT_SYNC */
child->pid = vfork (); child->pid = vfork ();
environ = parent_environ; /* Restore value child may have clobbered. */ environ = parent_environ; /* Restore value child may have clobbered. */
if (child->pid == 0) if (child->pid == 0)
@ -1831,19 +1844,6 @@ start_job_command (struct child *child)
HANDLE hPID; HANDLE hPID;
char* arg0; char* arg0;
#ifdef OUTPUT_SYNC
if (output_sync && sync_handle == -1)
sync_init();
if (output_sync && sync_cmd)
/* If we still want to sync, make sure we have temp files. */
assign_child_tempfiles (child);
else
/* We don't want to sync this command: to avoid misordered output
ensure any already-synched content is written. */
sync_output (child);
#endif /* OUTPUT_SYNC */
/* make UNC paths safe for CreateProcess -- backslash format */ /* make UNC paths safe for CreateProcess -- backslash format */
arg0 = argv[0]; arg0 = argv[0];
if (arg0 && arg0[0] == '/' && arg0[1] == '/') if (arg0 && arg0[0] == '/' && arg0[1] == '/')

24
misc.c
View File

@ -179,11 +179,11 @@ concat (unsigned int num, ...)
return result; 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. /* Return a formatted string buffer.
LENGTH must be the maximum length of all format arguments, stringified. */ LENGTH must be the maximum length of all format arguments, stringified.
If we had a standard-compliant vsnprintf() this would be a lot simpler.
Maybe in the future we'll include gnulib's version. */
const char * const char *
message_s (unsigned int length, int prefix, const char *fmt, ...) message_s (unsigned int length, int prefix, const char *fmt, ...)
@ -215,8 +215,6 @@ message_s (unsigned int length, int prefix, const char *fmt, ...)
vsprintf (bp, fmt, args); vsprintf (bp, fmt, args);
va_end (args); va_end (args);
strcat (bp, "\n");
return buffer; return buffer;
} }
@ -253,8 +251,6 @@ error_s (unsigned int length, const gmk_floc *flocp, const char *fmt, ...)
vsprintf (bp, fmt, args); vsprintf (bp, fmt, args);
va_end (args); va_end (args);
strcat (bp, "\n");
return buffer; return buffer;
} }
@ -270,9 +266,6 @@ message (int prefix, const char *fmt, ...)
if (fmt != 0) if (fmt != 0)
{ {
if (output_sync)
log_working_directory (1, 1);
if (prefix) if (prefix)
{ {
if (makelevel == 0) if (makelevel == 0)
@ -284,9 +277,6 @@ message (int prefix, const char *fmt, ...)
vfprintf (stdout, fmt, args); vfprintf (stdout, fmt, args);
va_end (args); va_end (args);
putchar ('\n'); putchar ('\n');
if (output_sync)
log_working_directory (0, 1);
} }
fflush (stdout); fflush (stdout);
@ -299,10 +289,7 @@ error (const gmk_floc *flocp, const char *fmt, ...)
{ {
va_list args; va_list args;
if (output_sync) log_working_directory (1, 0);
log_working_directory (1, 1);
else
log_working_directory (1, 0);
if (flocp && flocp->filenm) if (flocp && flocp->filenm)
fprintf (stderr, "%s:%lu: ", flocp->filenm, flocp->lineno); fprintf (stderr, "%s:%lu: ", flocp->filenm, flocp->lineno);
@ -317,9 +304,6 @@ error (const gmk_floc *flocp, const char *fmt, ...)
putc ('\n', stderr); putc ('\n', stderr);
fflush (stderr); fflush (stderr);
if (output_sync)
log_working_directory (0, 1);
} }
/* Print an error message and exit. */ /* Print an error message and exit. */

View File

@ -1,3 +1,9 @@
2013-05-05 Paul Smith <psmith@gnu.org>
* scripts/features/output-sync (output_sync_set): Remove
extraneous enter/leave lines, which are no longer printed.
Add tests for syncing command line printing.
2013-05-04 Paul Smith <psmith@gnu.org> 2013-05-04 Paul Smith <psmith@gnu.org>
* scripts/features/loadapi: Use the new alloc functions. * scripts/features/loadapi: Use the new alloc functions.

View File

@ -127,14 +127,11 @@ make-foo: ; \$(MAKE) -C foo
make-bar: ; \$(MAKE) -C bar!, make-bar: ; \$(MAKE) -C bar!,
'-j -Omake', '-j -Omake',
"#MAKEPATH# -C foo "#MAKEPATH# -C foo
#MAKEPATH# -C bar
#MAKE#[1]: Entering directory '#PWD#/foo'
#MAKE#[1]: Entering directory '#PWD#/foo' #MAKE#[1]: Entering directory '#PWD#/foo'
foo: start foo: start
foo: end foo: end
#MAKE#[1]: Leaving directory '#PWD#/foo' #MAKE#[1]: Leaving directory '#PWD#/foo'
#MAKE#[1]: Leaving directory '#PWD#/foo' #MAKEPATH# -C bar
#MAKE#[1]: Entering directory '#PWD#/bar'
#MAKE#[1]: Entering directory '#PWD#/bar' #MAKE#[1]: Entering directory '#PWD#/bar'
bar: start bar: start
bar: end bar: end
@ -142,7 +139,6 @@ bar: end
#MAKE#[1]: Entering directory '#PWD#/bar' #MAKE#[1]: Entering directory '#PWD#/bar'
baz: start baz: start
baz: end baz: end
#MAKE#[1]: Leaving directory '#PWD#/bar'
#MAKE#[1]: Leaving directory '#PWD#/bar'\n", 0, 6); #MAKE#[1]: Leaving directory '#PWD#/bar'\n", 0, 6);
# Test per-target synchronization. # Test per-target synchronization.
@ -160,8 +156,6 @@ make-bar: ; $sleep_command 1 ; \$(MAKE) -C bar!,
'-j --output-sync=target', '-j --output-sync=target',
"#MAKEPATH# -C foo "#MAKEPATH# -C foo
$sleep_command 1 ; #MAKEPATH# -C bar $sleep_command 1 ; #MAKEPATH# -C bar
#MAKE#[1]: Entering directory '#PWD#/foo'
#MAKE#[1]: Entering directory '#PWD#/bar'
#MAKE#[1]: Entering directory '#PWD#/bar' #MAKE#[1]: Entering directory '#PWD#/bar'
bar: start bar: start
bar: end bar: end
@ -170,11 +164,9 @@ bar: end
foo: start foo: start
foo: end foo: end
#MAKE#[1]: Leaving directory '#PWD#/foo' #MAKE#[1]: Leaving directory '#PWD#/foo'
#MAKE#[1]: Leaving directory '#PWD#/foo'
#MAKE#[1]: Entering directory '#PWD#/bar' #MAKE#[1]: Entering directory '#PWD#/bar'
baz: start baz: start
baz: end baz: end
#MAKE#[1]: Leaving directory '#PWD#/bar'
#MAKE#[1]: Leaving directory '#PWD#/bar'\n", 0, 6); #MAKE#[1]: Leaving directory '#PWD#/bar'\n", 0, 6);
# Test that messages from make itself are enclosed with # Test that messages from make itself are enclosed with
@ -189,20 +181,16 @@ make-bar-bar: ; $sleep_command 1 ; \$(MAKE) -C bar bar!,
'-j -O', '-j -O',
"#MAKEPATH# -C foo foo-fail "#MAKEPATH# -C foo foo-fail
$sleep_command 1 ; #MAKEPATH# -C bar bar $sleep_command 1 ; #MAKEPATH# -C bar bar
#MAKE#[1]: Entering directory '#PWD#/foo'
#MAKE#[1]: Entering directory '#PWD#/bar'
#MAKE#[1]: Entering directory '#PWD#/bar' #MAKE#[1]: Entering directory '#PWD#/bar'
bar: start bar: start
bar: end bar: end
#MAKE#[1]: Leaving directory '#PWD#/bar' #MAKE#[1]: Leaving directory '#PWD#/bar'
#MAKE#[1]: Leaving directory '#PWD#/bar'
#MAKE#[1]: Entering directory '#PWD#/foo' #MAKE#[1]: Entering directory '#PWD#/foo'
foo-fail: start foo-fail: start
foo-fail: end foo-fail: end
Makefile:20: recipe for target 'foo-fail' failed Makefile:20: recipe for target 'foo-fail' failed
#MAKE#[1]: *** [foo-fail] Error 1 #MAKE#[1]: *** [foo-fail] Error 1
#MAKE#[1]: Leaving directory '#PWD#/foo' #MAKE#[1]: Leaving directory '#PWD#/foo'
#MAKE#[1]: Leaving directory '#PWD#/foo'
#MAKEFILE#:4: recipe for target 'make-foo-fail' failed #MAKEFILE#:4: recipe for target 'make-foo-fail' failed
#MAKE#: *** [make-foo-fail] Error 2\n", #MAKE#: *** [make-foo-fail] Error 2\n",
512); 512);
@ -224,20 +212,16 @@ make-bar: ; $sleep_command 1 ; \$(MAKE) -C bar bar-job!,
"#MAKEPATH# -C foo foo-job "#MAKEPATH# -C foo foo-job
$sleep_command 1 ; #MAKEPATH# -C bar bar-job $sleep_command 1 ; #MAKEPATH# -C bar bar-job
#MAKE#[1]: Entering directory '#PWD#/foo' #MAKE#[1]: Entering directory '#PWD#/foo'
#MAKE#[1]: Entering directory '#PWD#/foo'
foo: start foo: start
#MAKE#[1]: Leaving directory '#PWD#/foo' #MAKE#[1]: Leaving directory '#PWD#/foo'
#MAKE#[1]: Entering directory '#PWD#/bar' #MAKE#[1]: Entering directory '#PWD#/bar'
#MAKE#[1]: Entering directory '#PWD#/bar'
bar: start bar: start
#MAKE#[1]: Leaving directory '#PWD#/bar' #MAKE#[1]: Leaving directory '#PWD#/bar'
#MAKE#[1]: Entering directory '#PWD#/bar' #MAKE#[1]: Entering directory '#PWD#/bar'
bar: end bar: end
#MAKE#[1]: Leaving directory '#PWD#/bar' #MAKE#[1]: Leaving directory '#PWD#/bar'
#MAKE#[1]: Leaving directory '#PWD#/bar'
#MAKE#[1]: Entering directory '#PWD#/foo' #MAKE#[1]: Entering directory '#PWD#/foo'
foo: end foo: end
#MAKE#[1]: Leaving directory '#PWD#/foo'
#MAKE#[1]: Leaving directory '#PWD#/foo'\n", 0, 6); #MAKE#[1]: Leaving directory '#PWD#/foo'\n", 0, 6);
@ -254,5 +238,15 @@ all:
run_make_test(undef, '-j -Otarget', "foo\nbar\n"); run_make_test(undef, '-j -Otarget', "foo\nbar\n");
# Ensure when make writes out command it's not misordered
run_make_test(qq!
all:
\t\@echo foobar
\ttrue
!,
'-j -Ojob', "foobar\ntrue\n");
run_make_test(undef, '-j -Otarget', "foobar\ntrue\n");
# This tells the test driver that the perl test script executed properly. # This tells the test driver that the perl test script executed properly.
1; 1;