Imported Upstream version 4.2
[platform/upstream/make.git] / tests / scripts / features / output-sync
1 #                                                                    -*-perl-*-
2
3 $description = "Test --output-sync (-O) option.";
4
5 $details = "Test the synchronization of output from parallel jobs.";
6
7 # If we don't have output sync support, never mind.
8 exists $FEATURES{'output-sync'} or return -1;
9
10 # Output sync can't be tested without parallelization
11 $parallel_jobs or return -1;
12
13
14 if ($vos) {
15   $sleep_command = "sleep -seconds";
16 }
17 else {
18   $sleep_command = "sleep";
19 }
20
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
26 #
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.
32
33 @syncfiles = ();
34
35 sub output_sync_clean {
36     rmfiles('foo/Makefile', 'bar/Makefile', @syncfiles);
37     rmdir('foo');
38     rmdir('bar');
39 }
40
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";
49 }
50 sub output_sync_set {
51     return "date > ../mksync.$_[0]";
52 }
53
54 @syncfiles = qw(mksync.foo mksync.foo_start mksync.bar mksync.bar_start);
55
56 $tmout = 30;
57
58 output_sync_clean();
59 mkdir('foo', 0777);
60 mkdir('bar', 0777);
61
62 $set_foo = output_sync_set('foo');
63 $set_bar = output_sync_set('bar');
64 $set_foo_start = output_sync_set('foo_start');
65 $set_bar_start = output_sync_set('bar_start');
66
67 $wait_foo = output_sync_wait('foo');
68 $wait_bar = output_sync_wait('bar');
69 $wait_foo_start = output_sync_set('foo_start');
70 $wait_bar_start = output_sync_set('bar_start');
71
72 open(MAKEFILE,"> foo/Makefile");
73 print MAKEFILE <<EOF;
74 all: foo
75
76 foo: foo-base ; \@$set_foo
77
78 foo-base:
79 \t\@echo foo: start
80 \t\@$wait_bar
81 \t\@echo foo: end
82
83 foo-job: foo-job-base ; \@$set_foo
84
85 foo-job-base:
86 \t\@$wait_bar_start
87 \t\@echo foo: start
88 \t\@$set_foo_start
89 \t\@$wait_bar
90 \t\@echo foo: end
91
92 foo-fail:
93 \t\@echo foo-fail: start
94 \t\@$wait_bar
95 \t\@echo foo-fail: end
96 \t\@exit 1
97 EOF
98 close(MAKEFILE);
99
100 open(MAKEFILE,"> bar/Makefile");
101 print MAKEFILE <<EOF;
102 all: bar baz
103
104 bar: bar-base ; \@$set_bar
105 bar-base:
106 \t\@echo bar: start
107 \t\@echo bar: end
108
109 bar-job: bar-job-base ; \@$set_bar
110
111 bar-job-base:
112 \t\@echo bar: start
113 \t\@$set_bar_start
114 \t\@$wait_foo_start
115 \t\@echo bar: end
116
117 baz: baz-base
118 baz-base:
119 \t\@echo baz: start
120 \t\@$wait_foo
121 \t\@echo baz: end
122 EOF
123 close(MAKEFILE);
124
125 # Test per-make synchronization.
126 unlink(@syncfiles);
127 run_make_test(qq!
128 all: make-foo make-bar
129
130 make-foo: ; \$(MAKE) -C foo
131
132 make-bar: ; \$(MAKE) -C bar!,
133               '-j -Orecurse',
134 "#MAKEPATH# -C foo
135 #MAKE#[1]: Entering directory '#PWD#/foo'
136 foo: start
137 foo: end
138 #MAKE#[1]: Leaving directory '#PWD#/foo'
139 #MAKEPATH# -C bar
140 #MAKE#[1]: Entering directory '#PWD#/bar'
141 bar: start
142 bar: end
143 baz: start
144 baz: end
145 #MAKE#[1]: Leaving directory '#PWD#/bar'\n", 0, $tmout);
146
147 # Test per-target synchronization.
148 # Note we have to sleep again here after starting the foo makefile before
149 # starting the bar makefile, otherwise the "entering/leaving" messages for the
150 # submakes might be ordered differently than we expect.
151
152 unlink(@syncfiles);
153 run_make_test(qq!
154 x=1
155 \$xMAKEFLAGS += --no-print-directory
156
157 all: make-foo make-bar
158
159 make-foo: ; \$(MAKE) -C foo
160
161 make-bar: ; $sleep_command 1 ; \$(MAKE) -C bar!,
162               '-j --output-sync=target',
163 "#MAKEPATH# -C foo
164 $sleep_command 1 ; #MAKEPATH# -C bar
165 #MAKE#[1]: Entering directory '#PWD#/bar'
166 bar: start
167 bar: end
168 #MAKE#[1]: Leaving directory '#PWD#/bar'
169 #MAKE#[1]: Entering directory '#PWD#/foo'
170 foo: start
171 foo: end
172 #MAKE#[1]: Leaving directory '#PWD#/foo'
173 #MAKE#[1]: Entering directory '#PWD#/bar'
174 baz: start
175 baz: end
176 #MAKE#[1]: Leaving directory '#PWD#/bar'\n", 0, $tmout);
177
178 # Rerun but this time suppress the directory tracking
179 unlink(@syncfiles);
180 run_make_test(undef, '-j --output-sync=target x=',
181               "#MAKEPATH# -C foo
182 $sleep_command 1 ; #MAKEPATH# -C bar
183 bar: start
184 bar: end
185 foo: start
186 foo: end
187 baz: start
188 baz: end\n", 0, $tmout);
189
190 # Test that messages from make itself are enclosed with
191 # "Entering/Leaving directory" messages.
192 unlink(@syncfiles);
193 run_make_test(qq!
194 all: make-foo-fail make-bar-bar
195
196 make-foo-fail: ; \$(MAKE) -C foo foo-fail
197
198 make-bar-bar: ; $sleep_command 1 ; \$(MAKE) -C bar bar!,
199               '-j -O',
200 "#MAKEPATH# -C foo foo-fail
201 $sleep_command 1 ; #MAKEPATH# -C bar bar
202 #MAKE#[1]: Entering directory '#PWD#/bar'
203 bar: start
204 bar: end
205 #MAKE#[1]: Leaving directory '#PWD#/bar'
206 #MAKE#[1]: Entering directory '#PWD#/foo'
207 foo-fail: start
208 foo-fail: end
209 #MAKE#[1]: *** [Makefile:23: foo-fail] Error 1
210 #MAKE#[1]: Leaving directory '#PWD#/foo'
211 #MAKE#: *** [#MAKEFILE#:4: make-foo-fail] Error 2\n",
212 512);
213
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
217 # And foo-job:
218 #   wait for bar-start, print foo-start, wait for bar-end, print end
219
220 unlink(@syncfiles);
221 run_make_test(qq!
222 all: make-foo make-bar
223
224 make-foo: ; \$(MAKE) -C foo foo-job
225
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'
231 foo: start
232 #MAKE#[1]: Leaving directory '#PWD#/foo'
233 #MAKE#[1]: Entering directory '#PWD#/bar'
234 bar: start
235 #MAKE#[1]: Leaving directory '#PWD#/bar'
236 #MAKE#[1]: Entering directory '#PWD#/bar'
237 bar: end
238 #MAKE#[1]: Leaving directory '#PWD#/bar'
239 #MAKE#[1]: Entering directory '#PWD#/foo'
240 foo: end
241 #MAKE#[1]: Leaving directory '#PWD#/foo'\n", 0, $tmout);
242
243
244 # Remove temporary directories and contents.
245 output_sync_clean();
246
247 # Ensure recursion doesn't mis-order or double-print output
248 run_make_test(qq!
249 all:
250 \t\@echo foo
251 \t\@+echo bar
252 !,
253               '-j -Oline', "foo\nbar\n");
254
255 run_make_test(undef, '-j -Otarget', "foo\nbar\n");
256
257 # Ensure when make writes out command it's not misordered
258 run_make_test(qq!
259 all:
260 \t\@echo foobar
261 \ttrue
262 !,
263               '-j -Oline', "foobar\ntrue\n");
264
265 run_make_test(undef, '-j -Otarget', "foobar\ntrue\n");
266
267 # Ensure that shell functions inside recipes write stderr to the sync file
268 run_make_test(q!
269 all: ; @: $(shell echo foo 1>&2)
270 !,
271               '-w -Oline', "#MAKE#: Entering directory '#PWD#'\nfoo\n#MAKE#: Leaving directory '#PWD#'\n");
272
273 # Ensure that output generated while parsing makefiles is synced
274 # when appropriate.
275 run_make_test(q!
276 $(shell echo foo 1>&2)
277 all: ; echo bar
278 !,
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");
280
281 # Test recursion
282 $m1 = get_tmpfile();
283 $m2 = get_tmpfile();
284
285 open(M1, "> $m1");
286 print M1 <<'EOF';
287 $(shell echo d1 stderr 1>&2)
288 $(info d1 stdout)
289 all:; @:
290 EOF
291 close(M1);
292
293 open(M2, "> $m2");
294 print M2 <<'EOF';
295 $(shell echo d2 stderr 1>&2)
296 $(info d2 stdout)
297 all:; @:
298 # Force an ordering on the output
299 $(shell sleep 1)
300 EOF
301 close(M2);
302
303 run_make_test(qq!
304 all: t1 t2
305 t1: ; \@\$(MAKE) -f $m1
306 t2: ; \@\$(MAKE) -f $m2
307 !,
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");
309
310 rmfiles($m1, $m2);
311
312 # Ensure that output generated while parsing makefiles is synced
313 # when appropriate.
314 $m1 = get_tmpfile();
315
316 open(M1, "> $m1");
317 print M1 <<'EOF';
318 $(shell echo d1 stderr 1>&2)
319 $(info d1 stdout)
320 $(error d1 failed)
321 all:; @:
322 EOF
323 close(M1);
324
325 run_make_test(qq!
326 all: t1
327 t1: ; -\@\$(MAKE) -f $m1
328 !,
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#MAKE#: [#MAKEFILE#:3: t1] Error 2 (ignored)\n");
330
331 rmfiles($m1);
332
333 # Test $(error ...) functions in recipes
334
335 run_make_test(q!
336 foo: $(OBJS) ; echo $(or $(filter %.o,$^),$(error fail))
337 !,
338               '-O', "#MAKEFILE#:2: *** fail.  Stop.\n", 512);
339
340 # SV 47365: Make sure exec failure error messages are shown
341 # Is "127" not always the same everywhere?  We may have to detect it?
342
343 run_make_test(q!
344 all:: ; @./foo bar baz
345 !,
346               '-O', "#MAKE#: ./foo: Command not found\n#MAKE#: *** [#MAKEFILE#:2: all] Error 127\n", 512);
347
348 # This tells the test driver that the perl test script executed properly.
349 1;