3 $description = "Test --output-sync (-O) option.";
5 $details = "Test the synchronization of output from parallel jobs.";
7 # If we don't have output sync support, never mind.
8 exists $FEATURES{'output-sync'} or return -1;
10 # Output sync can't be tested without parallelization
11 $parallel_jobs or return -1;
15 $sleep_command = "sleep -seconds";
18 $sleep_command = "sleep";
21 # The following subdirectories with Makefiles are used in several
22 # of the following tests. The model is:
23 # foo/Makefile - has a "foo" target that waits for the bar target
24 # bar/Makefile - has a "bar" target that runs immediately
25 # - has a "baz" target that waits for the foo target
27 # So, you start the two sub-makes in parallel and first the "bar" target is
28 # built, followed by "foo", followed by "baz". The trick is that first each
29 # target prints a "start" statement, then waits (if appropriate), then prints
30 # an end statement. Thus we can tell if the -O flag is working, since
31 # otherwise these statements would be mixed together.
35 sub output_sync_clean {
36 rmfiles('foo/Makefile', 'bar/Makefile', @syncfiles);
41 # We synchronize the different jobs by having them wait for a sentinel file to
42 # be created, instead of relying on a certain amount of time passing.
43 # Unfortunately in this test we have to sleep after we see the sync file,
44 # since we also want to make the obtaining of the write synchronization lock
45 # reliable. If things are too fast, then sometimes a different job will steal
46 # the output sync lock and the output is mis-ordered from what we expect.
47 sub output_sync_wait {
48 return "while [ ! -f ../mksync.$_[0] ]; do :; done; rm -f ../mksync.$_[0].wait; $sleep_command 1";
51 return "date > ../mksync.$_[0]";
54 @syncfiles = qw(mksync.foo mksync.foo_start mksync.bar mksync.bar_start);
60 $set_foo = output_sync_set('foo');
61 $set_bar = output_sync_set('bar');
62 $set_foo_start = output_sync_set('foo_start');
63 $set_bar_start = output_sync_set('bar_start');
65 $wait_foo = output_sync_wait('foo');
66 $wait_bar = output_sync_wait('bar');
67 $wait_foo_start = output_sync_set('foo_start');
68 $wait_bar_start = output_sync_set('bar_start');
70 open(MAKEFILE,"> foo/Makefile");
74 foo: foo-base ; \@$set_foo
81 foo-job: foo-job-base ; \@$set_foo
91 \t\@echo foo-fail: start
93 \t\@echo foo-fail: end
98 open(MAKEFILE,"> bar/Makefile");
102 bar: bar-base ; \@$set_bar
107 bar-job: bar-job-base ; \@$set_bar
123 # Test per-make synchronization.
126 all: make-foo make-bar
128 make-foo: ; \$(MAKE) -C foo
130 make-bar: ; \$(MAKE) -C bar!,
133 #MAKE#[1]: Entering directory '#PWD#/foo'
136 #MAKE#[1]: Leaving directory '#PWD#/foo'
138 #MAKE#[1]: Entering directory '#PWD#/bar'
143 #MAKE#[1]: Leaving directory '#PWD#/bar'\n", 0, 6);
145 # Test per-target synchronization.
146 # Note we have to sleep again here after starting the foo makefile before
147 # starting the bar makefile, otherwise the "entering/leaving" messages for the
148 # submakes might be ordered differently than we expect.
153 \$xMAKEFLAGS += --no-print-directory
155 all: make-foo make-bar
157 make-foo: ; \$(MAKE) -C foo
159 make-bar: ; $sleep_command 1 ; \$(MAKE) -C bar!,
160 '-j --output-sync=target',
162 $sleep_command 1 ; #MAKEPATH# -C bar
163 #MAKE#[1]: Entering directory '#PWD#/bar'
166 #MAKE#[1]: Leaving directory '#PWD#/bar'
167 #MAKE#[1]: Entering directory '#PWD#/foo'
170 #MAKE#[1]: Leaving directory '#PWD#/foo'
171 #MAKE#[1]: Entering directory '#PWD#/bar'
174 #MAKE#[1]: Leaving directory '#PWD#/bar'\n", 0, 6);
176 # Rerun but this time suppress the directory tracking
178 run_make_test(undef, '-j --output-sync=target x=',
180 $sleep_command 1 ; #MAKEPATH# -C bar
188 # Test that messages from make itself are enclosed with
189 # "Entering/Leaving directory" messages.
192 all: make-foo-fail make-bar-bar
194 make-foo-fail: ; \$(MAKE) -C foo foo-fail
196 make-bar-bar: ; $sleep_command 1 ; \$(MAKE) -C bar bar!,
198 "#MAKEPATH# -C foo foo-fail
199 $sleep_command 1 ; #MAKEPATH# -C bar bar
200 #MAKE#[1]: Entering directory '#PWD#/bar'
203 #MAKE#[1]: Leaving directory '#PWD#/bar'
204 #MAKE#[1]: Entering directory '#PWD#/foo'
207 Makefile:20: recipe for target 'foo-fail' failed
208 #MAKE#[1]: *** [foo-fail] Error 1
209 #MAKE#[1]: Leaving directory '#PWD#/foo'
210 #MAKEFILE#:4: recipe for target 'make-foo-fail' failed
211 #MAKE#: *** [make-foo-fail] Error 2\n",
214 # Test the per-job synchronization.
215 # For this we'll have bar-job:
216 # print start, invoke bar-start, wait for foo-start, print end, print-bar-end
218 # wait for bar-start, print foo-start, wait for bar-end, print end
222 all: make-foo make-bar
224 make-foo: ; \$(MAKE) -C foo foo-job
226 make-bar: ; $sleep_command 1 ; \$(MAKE) -C bar bar-job!,
227 '-j --output-sync=line',
228 "#MAKEPATH# -C foo foo-job
229 $sleep_command 1 ; #MAKEPATH# -C bar bar-job
230 #MAKE#[1]: Entering directory '#PWD#/foo'
232 #MAKE#[1]: Leaving directory '#PWD#/foo'
233 #MAKE#[1]: Entering directory '#PWD#/bar'
235 #MAKE#[1]: Leaving directory '#PWD#/bar'
236 #MAKE#[1]: Entering directory '#PWD#/bar'
238 #MAKE#[1]: Leaving directory '#PWD#/bar'
239 #MAKE#[1]: Entering directory '#PWD#/foo'
241 #MAKE#[1]: Leaving directory '#PWD#/foo'\n", 0, 6);
244 # Remove temporary directories and contents.
247 # Ensure recursion doesn't mis-order or double-print output
253 '-j -Oline', "foo\nbar\n");
255 run_make_test(undef, '-j -Otarget', "foo\nbar\n");
257 # Ensure when make writes out command it's not misordered
263 '-j -Oline', "foobar\ntrue\n");
265 run_make_test(undef, '-j -Otarget', "foobar\ntrue\n");
267 # Ensure that shell functions inside recipes write stderr to the sync file
269 all: ; @: $(shell echo foo 1>&2)
271 '-w -Oline', "#MAKE#: Entering directory '#PWD#'\nfoo\n#MAKE#: Leaving directory '#PWD#'\n");
273 # Ensure that output generated while parsing makefiles is synced
276 $(shell echo foo 1>&2)
279 '-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");
287 $(shell echo d1 stderr 1>&2)
295 $(shell echo d2 stderr 1>&2)
298 # Force an ordering on the output
305 t1: ; \@\$(MAKE) -f $m1
306 t2: ; \@\$(MAKE) -f $m2
308 "-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");
312 # Ensure that output generated while parsing makefiles is synced
318 $(shell echo d1 stderr 1>&2)
327 t1: ; -\@\$(MAKE) -f $m1
329 "-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");
333 # This tells the test driver that the perl test script executed properly.