| 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;
|
|---|