there is no limit on the number of job slots. The default number of job
slots is one, which means serial execution (one thing at a time).
-One consequence of running several recipes simultaneously is that by
-default, output from each recipe appears as soon as it is generated,
-with the result that messages from different recipes may be interspersed.
-This may create problems in interpreting output. If the @samp{-P} option
-is used, however, recipes will save their output until completion and
-then take turns writing it, with a more coherent result.
+When running several recipes simultaneously the output from each
+recipe appears as soon as it is generated, with the result that
+messages from different recipes may be interspersed. To avoid this
+you can use the @samp{--output-sync} (@samp{-O}) option; if this
+option is provided then the output from each recipe will be saved
+until the recipe is complete, then written all at once. This ensures
+that output from different recipes is not mixed together.
Another problem is that two processes cannot both take input from the
same device; so to make sure that only one recipe tries to take input
recipe and variable definitions, so it can be a useful debugging tool
in complex environments.
-@item -P
-@cindex @code{-P}
-@itemx --parallel-sync
-@cindex @code{--parallel-sync}
-@cindex parallel recipe execution, output
-When jobs are running in parallel under @samp{--jobs}, the output of
-each job is held until the job is complete thus ensuring that the output
-of each recipe is grouped together.
+@item -O
+@cindex @code{-O}
+@itemx --output-sync
+@cindex @code{--output-sync}
+@cindex output of parallel execution
+@cindex parallel execution, output of
+Ensure that the complete output from each recipe is printed in one
+uninterrupted sequence. This option is only useful when using the
+@code{--jobs} option to run multiple recipes simultaneously
+(@pxref{Parallel, ,Parallel Execution}). Without this option output
+will be displayed as it is generated by the recipes.
With no argument or the argument @samp{1}, messages from each job in
recursive makes are grouped together. With the argument @samp{2}, the
complete output from any recursive make is grouped together. The latter
achieves better grouping of output from related jobs, but causes longer
delay, since messages do not appear until the recursive make has
-completed. Therefore @samp{-P} is more useful when watching the output
-while make runs, and @samp{-P2} is better suited when running a complex
+completed. Therefore @samp{-O} is more useful when watching the output
+while make runs, and @samp{-O2} is better suited when running a complex
parallel build in the background and checking its output afterwards.
@item -q
unsigned int jobserver_tokens = 0;
-#ifdef PARALLEL_SYNC
-/* Semaphore for use in -j mode with parallel_sync. */
+#ifdef OUTPUT_SYNC
+/* Semaphore for use in -j mode with output_sync. */
int sync_handle = -1;
-#define STREAM_OK(strm) ((fcntl (fileno ((strm)), F_GETFD) != -1) || (errno != EBADF))
+#define STREAM_OK(_s) ((fcntl (fileno (_s), F_GETFD) != -1) || (errno != EBADF))
-#define FD_NOT_EMPTY(FD) ((FD) >= 0 && lseek ((FD), 0, SEEK_CUR) > 0)
-#endif /* PARALLEL_SYNC */
+#define FD_NOT_EMPTY(_f) ((_f) >= 0 && lseek ((_f), 0, SEEK_CUR) > 0)
+#endif /* OUTPUT_SYNC */
\f
#ifdef WINDOWS32
/*
*/
}
-#ifdef PARALLEL_SYNC
-/* Adds file descriptors to the child structure to support parallel_sync;
+#ifdef OUTPUT_SYNC
+/* Adds file descriptors to the child structure to support output_sync;
one for stdout and one for stderr as long as they are (a) open and
(b) separate. If stdout and stderr share a device they can share a
temp file too. */
{
FILE *outstrm = NULL, *errstrm = NULL;
int o_ok, e_ok;
- const char *suppressed = "parallel-sync suppressed: ";
+ const char *suppressed = "output-sync suppressed: ";
char *failmode = NULL;
/* Check status of stdout and stderr before hooking up temp files. */
o_ok = STREAM_OK (stdout);
e_ok = STREAM_OK (stderr);
- /* The tmpfile() function returns a FILE pointer but those can be in
+ /* The tmpfile() function returns a FILE pointer but those can be in
limited supply, so we immediately dup its file descriptor and keep
only that, closing the FILE pointer. */
if (combined)
{
if (!(outstrm = tmpfile ()))
- failmode = "tmpfile()";
+ failmode = "tmpfile()";
else
- errstrm = outstrm;
+ errstrm = outstrm;
}
else if (o_ok && e_ok)
{
if (!(outstrm = tmpfile ()) || !(errstrm = tmpfile ()))
- failmode = "tmpfile()";
+ failmode = "tmpfile()";
}
else if (o_ok)
{
if (!(outstrm = tmpfile ()))
- failmode = "tmpfile()";
+ failmode = "tmpfile()";
}
else if (e_ok)
{
if (!(errstrm = tmpfile ()))
- failmode = "tmpfile()";
+ failmode = "tmpfile()";
}
else
failmode = "stdout";
if (!failmode && outstrm)
{
if ((c->outfd = dup (fileno (outstrm))) == -1)
- failmode = "dup2()";
+ failmode = "dup2()";
else
- CLOSE_ON_EXEC (c->outfd);
+ CLOSE_ON_EXEC (c->outfd);
}
if (!failmode && errstrm)
{
if (combined)
- c->errfd = c->outfd;
+ c->errfd = c->outfd;
else
- {
- if ((c->errfd = dup (fileno (errstrm))) == -1)
- failmode = "dup2()";
- else
- CLOSE_ON_EXEC (c->errfd);
- }
+ {
+ if ((c->errfd = dup (fileno (errstrm))) == -1)
+ failmode = "dup2()";
+ else
+ CLOSE_ON_EXEC (c->errfd);
+ }
}
if (failmode)
char *write_buf = buffer;
EINTRLOOP (nleft, read (from_fd, buffer, sizeof (buffer)));
if (nleft < 0)
- perror ("read()");
+ perror ("read()");
if (nleft <= 0)
- break;
+ break;
while (nleft > 0)
{
EINTRLOOP (nwrite, write (to_fd, write_buf, nleft));
if ((outfd_not_empty || errfd_not_empty) && (sem = acquire_semaphore ()))
{
- /*
- * We've entered the "critical section" during which a lock is held.
- * We want to keep it as short as possible.
- */
+ /* We've entered the "critical section" during which a lock is held.
+ We want to keep it as short as possible. */
if (outfd_not_empty)
{
log_working_directory (1, 1);
if (errfd_not_empty && c->errfd != c->outfd)
pump_from_tmp_fd (c->errfd, fileno (stderr));
- /* Exit the critical section */
+ /* Exit the critical section. */
release_semaphore (sem);
}
close (c->errfd);
c->outfd = c->errfd = -1;
}
-#endif /* PARALLEL_SYNC */
+#endif /* OUTPUT_SYNC */
extern int shell_function_pid, shell_function_completed;
c->sh_batch_file = NULL;
}
-#ifdef PARALLEL_SYNC
+#ifdef OUTPUT_SYNC
/* Synchronize parallel output if requested */
- if (parallel_sync)
- sync_output (c);
-#endif /* PARALLEL_SYNC */
+ if (output_sync)
+ sync_output (c);
+#endif /* OUTPUT_SYNC */
/* If this child had the good stdin, say it is now free. */
if (c->good_stdin)
#else /* !__EMX__ */
-#ifdef PARALLEL_SYNC
- if (parallel_sync)
- {
- static int combined_output;
- /* If parallel_sync is turned on, find a resource to
- synchronize on. This block is traversed only once. */
- if (sync_handle == -1)
- {
- struct stat stbuf_o, stbuf_e;
+#ifdef OUTPUT_SYNC
+ if (output_sync)
+ {
+ static int combined_output;
+ /* If output_sync is turned on, find a resource to
+ synchronize on. This block is traversed only once. */
+ if (sync_handle == -1)
+ {
+ struct stat stbuf_o, stbuf_e;
- if (STREAM_OK (stdout))
- {
- sync_handle = fileno (stdout);
- combined_output =
- fstat (fileno (stdout), &stbuf_o) == 0 &&
- fstat (fileno (stderr), &stbuf_e) == 0 &&
- stbuf_o.st_dev == stbuf_e.st_dev &&
- stbuf_o.st_ino == stbuf_e.st_ino;
- }
- else if (STREAM_OK (stderr))
- sync_handle = fileno (stderr);
- else
- {
- perror_with_name ("parallel-sync suppressed: ", "stderr");
- parallel_sync = 0;
- }
- }
+ if (STREAM_OK (stdout))
+ {
+ sync_handle = fileno (stdout);
+ combined_output =
+ fstat (fileno (stdout), &stbuf_o) == 0 &&
+ fstat (fileno (stderr), &stbuf_e) == 0 &&
+ stbuf_o.st_dev == stbuf_e.st_dev &&
+ stbuf_o.st_ino == stbuf_e.st_ino;
+ }
+ else if (STREAM_OK (stderr))
+ sync_handle = fileno (stderr);
+ else
+ {
+ perror_with_name ("output-sync suppressed: ", "stderr");
+ output_sync = 0;
+ }
+ }
- /* If it still looks like we can synchronize, create a temp
- file to hold stdout (and one for stderr if separate). */
- if (parallel_sync >= PARALLEL_SYNC_COARSE
- || (parallel_sync == PARALLEL_SYNC_FINE && !(flags & COMMANDS_RECURSE)))
- {
- if (!assign_child_tempfiles (child, combined_output))
- parallel_sync = 0;
- }
- }
-#endif /* PARALLEL_SYNC */
+ /* If it still looks like we can synchronize, create a temp
+ file to hold stdout (and one for stderr if separate). */
+ if (output_sync >= OUTPUT_SYNC_COARSE
+ || (output_sync == OUTPUT_SYNC_FINE && !(flags & COMMANDS_RECURSE)))
+ {
+ if (!assign_child_tempfiles (child, combined_output))
+ output_sync = 0;
+ }
+ }
+#endif /* OUTPUT_SYNC */
child->pid = vfork ();
environ = parent_environ; /* Restore value child may have clobbered. */
setrlimit (RLIMIT_STACK, &stack_limit);
#endif
-#ifdef PARALLEL_SYNC
- /* Divert child output into tempfile(s) if parallel_sync in use. */
- if (parallel_sync)
- {
- int outfd = fileno (stdout);
- int errfd = fileno (stderr);
+#ifdef OUTPUT_SYNC
+ /* Divert child output into tempfile(s) if output_sync in use. */
+ if (output_sync)
+ {
+ int outfd = fileno (stdout);
+ int errfd = fileno (stderr);
- if ((child->outfd >= 0 &&
- (close (outfd) == -1 || dup2 (child->outfd, outfd) == -1))
- || (child->errfd >= 0 &&
- (close (errfd) == -1 || dup2 (child->errfd, errfd) == -1)))
- {
- perror_with_name ("parallel-sync: ", "dup2()");
- }
- }
-#endif /* PARALLEL_SYNC */
+ if ((child->outfd >= 0 &&
+ (close (outfd) == -1 || dup2 (child->outfd, outfd) == -1))
+ || (child->errfd >= 0 &&
+ (close (errfd) == -1 || dup2 (child->errfd, errfd) == -1)))
+ {
+ perror_with_name ("output-sync: ", "dup2()");
+ }
+ }
+#endif /* OUTPUT_SYNC */
child_execute_job (child->good_stdin ? 0 : bad_stdin, 1,
argv, child->environment);
c->file = file;
c->command_lines = lines;
c->sh_batch_file = NULL;
-#ifdef PARALLEL_SYNC
+#ifdef OUTPUT_SYNC
c->outfd = c->errfd = -1;
#endif
# define CLOSE_ON_EXEC(_d) (void) fcntl ((_d), F_SETFD, FD_CLOEXEC)
#endif
-#ifdef POSIX /* PARALLEL_SYNC */
-#define PARALLEL_SYNC
-#endif /* POSIX */
+#ifdef POSIX
+# define OUTPUT_SYNC
+#endif
/* Structure describing a running or dead child process. */
unsigned int good_stdin:1; /* Nonzero if this child has a good stdin. */
unsigned int deleted:1; /* Nonzero if targets have been deleted. */
unsigned int dontcare:1; /* Saved dontcare flag. */
-#ifdef PARALLEL_SYNC
- int outfd; /* Optional file descriptor for saving stdout */
- int errfd; /* Optional file descriptor for saving stderr */
-#endif /* PARALLEL_SYNC */
+#ifdef OUTPUT_SYNC
+ int outfd; /* File descriptor for saving stdout */
+ int errfd; /* File descriptor for saving stderr */
+#endif
};
extern struct child *children;
static unsigned int inf_jobs = 0;
-#ifdef PARALLEL_SYNC
+#ifdef OUTPUT_SYNC
-/* Default value for parallel sync without an argument. */
+/* Default value for output-sync without an argument. */
-static unsigned int no_parallel_sync = 0;
-static unsigned int default_parallel_sync = PARALLEL_SYNC_FINE;
+static unsigned int no_output_sync = 0;
+static unsigned int default_output_sync = OUTPUT_SYNC_FINE;
#endif
N_("\
-o FILE, --old-file=FILE, --assume-old=FILE\n\
Consider FILE to be very old and don't remake it.\n"),
+#ifdef OUTPUT_SYNC
N_("\
- -p, --print-data-base Print make's internal database.\n"),
-#ifdef PARALLEL_SYNC
- N_("\
- -P [2], --parallel-sync[=2] Synchronize output of parallel jobs [coarse].\n"),
+ -O [2], --output-sync[=2] Synchronize output of parallel jobs [coarse].\n"),
#endif
N_("\
+ -p, --print-data-base Print make's internal database.\n"),
+ N_("\
-q, --question Run no recipe; exit status says if up to date.\n"),
N_("\
-r, --no-builtin-rules Disable the built-in implicit rules.\n"),
{ 'm', ignore, 0, 0, 0, 0, 0, 0, 0 },
{ 'n', flag, &just_print_flag, 1, 1, 1, 0, 0, "just-print" },
{ 'o', filename, &old_files, 0, 0, 0, 0, 0, "old-file" },
- { 'p', flag, &print_data_base_flag, 1, 1, 0, 0, 0, "print-data-base" },
-#ifdef PARALLEL_SYNC
- // { 'P', flag, ¶llel_sync, 1, 1, 0, 0, 0, "parallel-sync" }, // two-state
- { 'P', positive_int, ¶llel_sync, 1, 1, 0, &default_parallel_sync,
- &no_parallel_sync, "parallel-sync" },
+#ifdef OUTPUT_SYNC
+ // { 'O', flag, &output_sync, 1, 1, 0, 0, 0, "output-sync" }, // two-state
+ { 'O', positive_int, &output_sync, 1, 1, 0, &default_output_sync,
+ &no_output_sync, "output-sync" },
#endif
+ { 'p', flag, &print_data_base_flag, 1, 1, 0, 0, 0, "print-data-base" },
{ 'q', flag, &question_flag, 1, 1, 1, 0, 0, "question" },
{ 'r', flag, &no_builtin_rules_flag, 1, 1, 0, 0, 0, "no-builtin-rules" },
{ 'R', flag, &no_builtin_variables_flag, 1, 1, 0, 0, 0,
int one_shell;
-/* Either PARALLEL_SYNC_FINE or PARALLEL_SYNC_COARSE
- if the "--parallel-sync" option was given.
+/* Either OUTPUT_SYNC_FINE or OUTPUT_SYNC_COARSE
+ if the "--output-sync" option was given.
This attempts to synchronize the output of parallel
jobs such that the results of each job stay together.
It works best in combination with .ONESHELL. */
-int parallel_sync;
+int output_sync;
/* Nonzero if we have seen the '.NOTPARALLEL' target.
This turns off parallel builds for this invocation of make. */
if (! open_jobserver_semaphore(cp))
{
DWORD err = GetLastError();
- fatal (NILF, _("internal error: unable to open jobserver semaphore '%s': (Error %ld: %s)"),
+ fatal (NILF, _("internal error: unable to open jobserver semaphore '%s': (Error %ld: %s)"),
cp, err, map_windows32_error_to_string(err));
}
DB (DB_JOBS, (_("Jobserver client (semaphore %s)\n"), cp));
# endif
#endif
-#define PARALLEL_SYNC_FINE 1
-#define PARALLEL_SYNC_COARSE 2
+#define OUTPUT_SYNC_FINE 1
+#define OUTPUT_SYNC_COARSE 2
extern const gmk_floc *reading_file;
extern const gmk_floc **expanding_var;
extern int print_version_flag, print_directory_flag, check_symlink_flag;
extern int warn_undefined_variables_flag, trace_flag, posix_pedantic;
extern int not_parallel, second_expansion, clock_skew_detected;
-extern int rebuilding_makefiles, one_shell, parallel_sync;
+extern int rebuilding_makefiles, one_shell, output_sync;
/* can we run commands via 'sh -c xxx' or must we use batch files? */
extern int batch_mode_shell;
if (fmt != 0)
{
- if (parallel_sync)
+ if (output_sync)
log_working_directory (1, 1);
if (prefix)
VA_END (args);
putchar ('\n');
- if (parallel_sync)
+ if (output_sync)
log_working_directory (0, 1);
}
va_list args;
#endif
- if (parallel_sync)
+ if (output_sync)
log_working_directory (1, 1);
else
log_working_directory (1, 0);
putc ('\n', stderr);
fflush (stderr);
- if (parallel_sync)
+ if (output_sync)
log_working_directory (0, 1);
}
va_list args;
#endif
- if (parallel_sync)
+ if (output_sync)
log_working_directory (1, 1);
else
log_working_directory (1, 0);
fputs (_(". Stop.\n"), stderr);
- if (parallel_sync)
+ if (output_sync)
log_working_directory (0, 1);
die (2);
--- /dev/null
+# -*-perl-*-
+
+$description = "Test --output-sync (-O) option.";
+
+$details = "Test the synchronization of output from parallel jobs.";
+
+if (!$parallel_jobs) {
+ return -1;
+}
+
+if ($vos) {
+ $sleep_command = "sleep -seconds";
+}
+else {
+ $sleep_command = "sleep";
+}
+
+# The following subdirectories with Makefiles are used in several
+# of the following tests.
+mkdir('foo', 0777);
+mkdir('bar', 0777);
+
+open(MAKEFILE,"> foo/Makefile");
+print MAKEFILE <<EOF;
+all: foo
+
+foo: ; \@echo foo: start; $sleep_command 2; echo foo: end
+
+foo-fail: ; \@$sleep_command 2; false
+EOF
+close(MAKEFILE);
+
+open(MAKEFILE,"> bar/Makefile");
+print MAKEFILE <<EOF;
+all: bar baz
+
+bar: ; \@echo bar: start; $sleep_command 1; echo bar: end
+
+baz: ; \@echo baz: start; $sleep_command 4; echo baz: end
+EOF
+close(MAKEFILE);
+
+# Test coarse synchronization.
+run_make_test('
+all: make-foo make-bar
+
+make-foo: ; $(MAKE) -C foo
+
+make-bar: ; $(MAKE) -C bar',
+'-j -O2',
+"#MAKEPATH# -C foo
+#MAKEPATH# -C bar
+#MAKE#[1]: Entering directory '#PWD#/foo'
+#MAKE#[1]: Entering directory '#PWD#/foo'
+foo: start
+foo: end
+#MAKE#[1]: Leaving directory '#PWD#/foo'
+#MAKE#[1]: Leaving directory '#PWD#/foo'
+#MAKE#[1]: Entering directory '#PWD#/bar'
+#MAKE#[1]: Entering directory '#PWD#/bar'
+bar: start
+bar: end
+#MAKE#[1]: Leaving directory '#PWD#/bar'
+#MAKE#[1]: Entering directory '#PWD#/bar'
+baz: start
+baz: end
+#MAKE#[1]: Leaving directory '#PWD#/bar'
+#MAKE#[1]: Leaving directory '#PWD#/bar'\n");
+
+# Test fine synchronization.
+run_make_test('
+all: make-foo make-bar
+
+make-foo: ; $(MAKE) -C foo
+
+make-bar: ; $(MAKE) -C bar',
+'-j --output-sync',
+"#MAKEPATH# -C foo
+#MAKEPATH# -C bar
+#MAKE#[1]: Entering directory '#PWD#/foo'
+#MAKE#[1]: Entering directory '#PWD#/bar'
+#MAKE#[1]: Entering directory '#PWD#/bar'
+bar: start
+bar: end
+#MAKE#[1]: Leaving directory '#PWD#/bar'
+#MAKE#[1]: Entering directory '#PWD#/foo'
+foo: start
+foo: end
+#MAKE#[1]: Leaving directory '#PWD#/foo'
+#MAKE#[1]: Leaving directory '#PWD#/foo'
+#MAKE#[1]: Entering directory '#PWD#/bar'
+baz: start
+baz: end
+#MAKE#[1]: Leaving directory '#PWD#/bar'
+#MAKE#[1]: Leaving directory '#PWD#/bar'\n");
+
+# Test that messages from make itself are enclosed with
+# "Entering/Leaving directory" messages.
+run_make_test('
+all: make-foo-fail make-bar-bar
+
+make-foo-fail: ; $(MAKE) -C foo foo-fail
+
+make-bar-bar: ; $(MAKE) -C bar bar',
+'-j -O',
+"#MAKEPATH# -C foo foo-fail
+#MAKEPATH# -C bar bar
+#MAKE#[1]: Entering directory '#PWD#/foo'
+#MAKE#[1]: Entering directory '#PWD#/bar'
+#MAKE#[1]: Entering directory '#PWD#/bar'
+bar: start
+bar: end
+#MAKE#[1]: Leaving directory '#PWD#/bar'
+#MAKE#[1]: Leaving directory '#PWD#/bar'
+#MAKE#[1]: Entering directory '#PWD#/foo'
+Makefile:5: recipe for target 'foo-fail' failed
+#MAKE#[1]: Leaving directory '#PWD#/foo'
+#MAKE#[1]: Entering directory '#PWD#/foo'
+#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
+#MAKE#: *** [make-foo-fail] Error 2\n",
+512);
+
+# Remove temporary directories and contents.
+rmfiles('foo/Makefile');
+rmdir('foo');
+rmfiles('bar/Makefile');
+rmdir('bar');
+
+# This tells the test driver that the perl test script executed properly.
+1;
+++ /dev/null
-# -*-perl-*-
-
-$description = "Test parallel-sync (-P) option.";
-
-$details = "Test the synchronization of output from parallel jobs.";
-
-if (!$parallel_jobs) {
- return -1;
-}
-
-if ($vos) {
- $sleep_command = "sleep -seconds";
-}
-else {
- $sleep_command = "sleep";
-}
-
-# The following subdirectories with Makefiles are used in several
-# of the following tests.
-mkdir('foo', 0777);
-mkdir('bar', 0777);
-
-open(MAKEFILE,"> foo/Makefile");
-print MAKEFILE <<EOF;
-all: foo
-
-foo:
- \@echo foo: start; $sleep_command 2; echo foo: end
-
-foo-fail:
- \@$sleep_command 2; false
-EOF
-close(MAKEFILE);
-
-open(MAKEFILE,"> bar/Makefile");
-print MAKEFILE <<EOF;
-all: bar baz
-
-bar:
- \@echo bar: start; $sleep_command 1; echo bar: end
-
-baz:
- \@echo baz: start; $sleep_command 4; echo baz: end
-EOF
-close(MAKEFILE);
-
-# Test coarse synchronization.
-run_make_test('
-all: make-foo make-bar
-
-make-foo:
- $(MAKE) -C foo
-
-make-bar:
- $(MAKE) -C bar',
-'-j -P2',
-"#MAKEPATH# -C foo
-#MAKEPATH# -C bar
-#MAKE#[1]: Entering directory '#PWD#/foo'
-#MAKE#[1]: Entering directory '#PWD#/foo'
-foo: start
-foo: end
-#MAKE#[1]: Leaving directory '#PWD#/foo'
-#MAKE#[1]: Leaving directory '#PWD#/foo'
-#MAKE#[1]: Entering directory '#PWD#/bar'
-#MAKE#[1]: Entering directory '#PWD#/bar'
-bar: start
-bar: end
-#MAKE#[1]: Leaving directory '#PWD#/bar'
-#MAKE#[1]: Entering directory '#PWD#/bar'
-baz: start
-baz: end
-#MAKE#[1]: Leaving directory '#PWD#/bar'
-#MAKE#[1]: Leaving directory '#PWD#/bar'\n");
-
-# Test fine synchronization.
-run_make_test('
-all: make-foo make-bar
-
-make-foo:
- $(MAKE) -C foo
-
-make-bar:
- $(MAKE) -C bar',
-'-j -P',
-"#MAKEPATH# -C foo
-#MAKEPATH# -C bar
-#MAKE#[1]: Entering directory '#PWD#/foo'
-#MAKE#[1]: Entering directory '#PWD#/bar'
-#MAKE#[1]: Entering directory '#PWD#/bar'
-bar: start
-bar: end
-#MAKE#[1]: Leaving directory '#PWD#/bar'
-#MAKE#[1]: Entering directory '#PWD#/foo'
-foo: start
-foo: end
-#MAKE#[1]: Leaving directory '#PWD#/foo'
-#MAKE#[1]: Leaving directory '#PWD#/foo'
-#MAKE#[1]: Entering directory '#PWD#/bar'
-baz: start
-baz: end
-#MAKE#[1]: Leaving directory '#PWD#/bar'
-#MAKE#[1]: Leaving directory '#PWD#/bar'\n");
-
-# Test that messages from make itself are enclosed with
-# "Entering/Leaving directory" messages.
-run_make_test('
-all: make-foo-fail make-bar-bar
-
-make-foo-fail:
- $(MAKE) -C foo foo-fail
-
-make-bar-bar:
- $(MAKE) -C bar bar',
-'-j -P',
-"#MAKEPATH# -C foo foo-fail
-#MAKEPATH# -C bar bar
-#MAKE#[1]: Entering directory '#PWD#/foo'
-#MAKE#[1]: Entering directory '#PWD#/bar'
-#MAKE#[1]: Entering directory '#PWD#/bar'
-bar: start
-bar: end
-#MAKE#[1]: Leaving directory '#PWD#/bar'
-#MAKE#[1]: Leaving directory '#PWD#/bar'
-#MAKE#[1]: Entering directory '#PWD#/foo'
-Makefile:7: recipe for target 'foo-fail' failed
-#MAKE#[1]: Leaving directory '#PWD#/foo'
-#MAKE#[1]: Entering directory '#PWD#/foo'
-#MAKE#[1]: *** [foo-fail] Error 1
-#MAKE#[1]: Leaving directory '#PWD#/foo'
-#MAKE#[1]: Leaving directory '#PWD#/foo'
-#MAKEFILE#:5: recipe for target 'make-foo-fail' failed
-#MAKE#: *** [make-foo-fail] Error 2\n",
-512);
-
-# Remove temporary directories and contents.
-rmfiles('foo/Makefile');
-rmdir('foo');
-rmfiles('bar/Makefile');
-rmdir('bar');
-
-# This tells the test driver that the perl test script executed properly.
-1;