| # -*-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. The model is: |
| # foo/Makefile - has a "foo" target that waits for the bar target |
| # bar/Makefile - has a "bar" target that runs immediately |
| # - has a "baz" target that waits for the foo target |
| # |
| # So, you start the two sub-makes in parallel and first the "bar" target is |
| # built, followed by "foo", followed by "baz". The trick is that first each |
| # target prints a "start" statement, then waits (if appropriate), then prints |
| # an end statement. Thus we can tell if the -O flag is working, since |
| # otherwise these statements would be mixed together. |
| |
| @syncfiles = (); |
| |
| sub output_sync_clean { |
| rmfiles('foo/Makefile', 'bar/Makefile', @syncfiles); |
| rmdir('foo'); |
| rmdir('bar'); |
| } |
| |
| # We synchronize the different jobs by having them wait for a sentinel file to |
| # be created, instead of relying on a certain amount of time passing. |
| # Unfortunately in this test we have to sleep after we see the sync file, |
| # since we also want to make the obtaining of the write synchronization lock |
| # reliable. If things are too fast, then sometimes a different job will steal |
| # the output sync lock and the output is mis-ordered from what we expect. |
| sub output_sync_wait { |
| return "while [ ! -f ../mksync.$_[0] ]; do :; done; rm -f ../mksync.$_[0].wait; $sleep_command 1"; |
| } |
| sub output_sync_set { |
| return "date > ../mksync.$_[0]"; |
| } |
| |
| @syncfiles = qw(mksync.foo mksync.foo_start mksync.bar mksync.bar_start); |
| |
| output_sync_clean(); |
| mkdir('foo', 0777); |
| mkdir('bar', 0777); |
| |
| $set_foo = output_sync_set('foo'); |
| $set_bar = output_sync_set('bar'); |
| $set_foo_start = output_sync_set('foo_start'); |
| $set_bar_start = output_sync_set('bar_start'); |
| |
| $wait_foo = output_sync_wait('foo'); |
| $wait_bar = output_sync_wait('bar'); |
| $wait_foo_start = output_sync_set('foo_start'); |
| $wait_bar_start = output_sync_set('bar_start'); |
| |
| open(MAKEFILE,"> foo/Makefile"); |
| print MAKEFILE <<EOF; |
| all: foo |
| |
| foo: foo-base ; \@$set_foo |
| |
| foo-base: |
| \t\@echo foo: start |
| \t\@$wait_bar |
| \t\@echo foo: end |
| |
| foo-job: foo-job-base ; \@$set_foo |
| |
| foo-job-base: |
| \t\@$wait_bar_start |
| \t\@echo foo: start |
| \t\@$set_foo_start |
| \t\@$wait_bar |
| \t\@echo foo: end |
| |
| foo-fail: |
| \t\@echo foo-fail: start |
| \t\@$wait_bar |
| \t\@echo foo-fail: end |
| \t\@false |
| EOF |
| close(MAKEFILE); |
| |
| open(MAKEFILE,"> bar/Makefile"); |
| print MAKEFILE <<EOF; |
| all: bar baz |
| |
| bar: bar-base ; \@$set_bar |
| bar-base: |
| \t\@echo bar: start |
| \t\@echo bar: end |
| |
| bar-job: bar-job-base ; \@$set_bar |
| |
| bar-job-base: |
| \t\@echo bar: start |
| \t\@$set_bar_start |
| \t\@$wait_foo_start |
| \t\@echo bar: end |
| |
| baz: baz-base |
| baz-base: |
| \t\@echo baz: start |
| \t\@$wait_foo |
| \t\@echo baz: end |
| EOF |
| close(MAKEFILE); |
| |
| # Test per-make synchronization. |
| unlink(@syncfiles); |
| run_make_test(qq! |
| all: make-foo make-bar |
| |
| make-foo: ; \$(MAKE) -C foo |
| |
| make-bar: ; \$(MAKE) -C bar!, |
| '-j -Orecurse', |
| "#MAKEPATH# -C foo |
| #MAKE#[1]: Entering directory '#PWD#/foo' |
| foo: start |
| foo: end |
| #MAKE#[1]: Leaving directory '#PWD#/foo' |
| #MAKEPATH# -C bar |
| #MAKE#[1]: Entering directory '#PWD#/bar' |
| bar: start |
| bar: end |
| baz: start |
| baz: end |
| #MAKE#[1]: Leaving directory '#PWD#/bar'\n", 0, 6); |
| |
| # Test per-target synchronization. |
| # Note we have to sleep again here after starting the foo makefile before |
| # starting the bar makefile, otherwise the "entering/leaving" messages for the |
| # submakes might be ordered differently than we expect. |
| |
| unlink(@syncfiles); |
| run_make_test(qq! |
| all: make-foo make-bar |
| |
| make-foo: ; \$(MAKE) -C foo |
| |
| make-bar: ; $sleep_command 1 ; \$(MAKE) -C bar!, |
| '-j --output-sync=target', |
| "#MAKEPATH# -C foo |
| $sleep_command 1 ; #MAKEPATH# -C bar |
| #MAKE#[1]: Entering directory '#PWD#/bar' |
| bar: start |
| bar: end |
| #MAKE#[1]: Entering directory '#PWD#/foo' |
| foo: start |
| foo: end |
| #MAKE#[1]: Leaving directory '#PWD#/foo' |
| baz: start |
| baz: end |
| #MAKE#[1]: Leaving directory '#PWD#/bar'\n", 0, 6); |
| |
| # Test that messages from make itself are enclosed with |
| # "Entering/Leaving directory" messages. |
| unlink(@syncfiles); |
| run_make_test(qq! |
| all: make-foo-fail make-bar-bar |
| |
| make-foo-fail: ; \$(MAKE) -C foo foo-fail |
| |
| make-bar-bar: ; $sleep_command 1 ; \$(MAKE) -C bar bar!, |
| '-j -O', |
| "#MAKEPATH# -C foo foo-fail |
| $sleep_command 1 ; #MAKEPATH# -C bar bar |
| #MAKE#[1]: Entering directory '#PWD#/bar' |
| bar: start |
| bar: end |
| #MAKE#[1]: Leaving directory '#PWD#/bar' |
| #MAKE#[1]: Entering directory '#PWD#/foo' |
| foo-fail: start |
| foo-fail: end |
| Makefile:20: recipe for target 'foo-fail' failed |
| #MAKE#[1]: *** [foo-fail] Error 1 |
| #MAKE#[1]: Leaving directory '#PWD#/foo' |
| #MAKEFILE#:4: recipe for target 'make-foo-fail' failed |
| #MAKE#: *** [make-foo-fail] Error 2\n", |
| 512); |
| |
| # Test the per-job synchronization. |
| # For this we'll have bar-job: |
| # print start, invoke bar-start, wait for foo-start, print end, print-bar-end |
| # And foo-job: |
| # wait for bar-start, print foo-start, wait for bar-end, print end |
| |
| unlink(@syncfiles); |
| run_make_test(qq! |
| all: make-foo make-bar |
| |
| make-foo: ; \$(MAKE) -C foo foo-job |
| |
| make-bar: ; $sleep_command 1 ; \$(MAKE) -C bar bar-job!, |
| '-j --output-sync=line', |
| "#MAKEPATH# -C foo foo-job |
| $sleep_command 1 ; #MAKEPATH# -C bar bar-job |
| #MAKE#[1]: Entering directory '#PWD#/foo' |
| foo: start |
| #MAKE#[1]: Entering directory '#PWD#/bar' |
| bar: start |
| bar: end |
| #MAKE#[1]: Leaving directory '#PWD#/bar' |
| foo: end |
| #MAKE#[1]: Leaving directory '#PWD#/foo'\n", 0, 6); |
| |
| |
| # Remove temporary directories and contents. |
| output_sync_clean(); |
| |
| # Ensure recursion doesn't mis-order or double-print output |
| run_make_test(qq! |
| all: |
| \t\@echo foo |
| \t\@+echo bar |
| !, |
| '-j -Oline', "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 -Oline', "foobar\ntrue\n"); |
| |
| run_make_test(undef, '-j -Otarget', "foobar\ntrue\n"); |
| |
| # This tells the test driver that the perl test script executed properly. |
| 1; |