diff options
Diffstat (limited to 'tests/scripts/features')
30 files changed, 3145 insertions, 541 deletions
diff --git a/tests/scripts/features/archives b/tests/scripts/features/archives index dcd38e5..809bf21 100644 --- a/tests/scripts/features/archives +++ b/tests/scripts/features/archives @@ -35,16 +35,17 @@ my $ar = get_config('AR') || 'ar'; my $redir = '2>&1'; $redir = '' if $osname eq 'VMS'; -my $arflags = 'rv'; +# This is the value from src/default.c +my $arflags = $osname eq 'aix' ? '-Xany -rv' : '-rv'; my $arvar = "AR=$ar"; # Newer versions of binutils can be built with --enable-deterministic-archives # which forces all timestamps (among other things) to always be 0, defeating # GNU make's archive support. See if ar supports the U option to disable it. unlink('libxx.a'); -$_ = `$ar U$arflags libxx.a a1.o $redir`; +$_ = `$ar ${arflags}U libxx.a a1.o $redir`; if ($? == 0) { - $arflags = 'Urv'; + $arflags = "${arflags}U"; $arvar = "$arvar ARFLAGS=$arflags"; } diff --git a/tests/scripts/features/default_names b/tests/scripts/features/default_names index 2e83880..3ecbaab 100644 --- a/tests/scripts/features/default_names +++ b/tests/scripts/features/default_names @@ -15,7 +15,7 @@ open(MAKEFILE,"> makefile"); print MAKEFILE "SECOND: ; \@echo It chose makefile\n"; close(MAKEFILE); -# DOS/WIN32/MacOSX platforms are case-insensitive / case-preserving, so +# DOS/W32/MacOSX platforms are case-insensitive / case-preserving, so # Makefile is the same file as makefile. Just test what we can here. my $case_sensitive = 0; diff --git a/tests/scripts/features/dircache b/tests/scripts/features/dircache new file mode 100644 index 0000000..e5e8469 --- /dev/null +++ b/tests/scripts/features/dircache @@ -0,0 +1,31 @@ +# -*-mode: perl-*- + +$description = "Test the directory cache behavior."; + +# The first wildcard should bring the entire directory into the cache Then we +# create a new file "behind make's back" then see if the next wildcard detects +# it. + +run_make_test(q! +_orig := $(wildcard ./*) +$(shell echo > anewfile) +_new := $(wildcard ./*) +$(info diff=$(filter-out $(_orig),$(_new))) +all:;@: +!, + '', "diff=./anewfile\n"); + +rmfiles('anewfile'); + +run_make_test(q! +_orig := $(wildcard ./*) +$(file >anewfile) +_new := $(wildcard ./*) +$(info diff=$(filter-out $(_orig),$(_new))) +all:;@: +!, + '', "diff=./anewfile\n"); + +rmfiles('anewfile'); + +1; diff --git a/tests/scripts/features/double_colon b/tests/scripts/features/double_colon index 58f126f..a039b0a 100644 --- a/tests/scripts/features/double_colon +++ b/tests/scripts/features/double_colon @@ -12,12 +12,9 @@ We test these features: Then we do the same thing for parallel builds: double-colon targets should always be built serially."; -# The Contents of the MAKEFILE ... - -open(MAKEFILE,"> $makefile"); - -print MAKEFILE <<'EOF'; +# TEST 0: A simple double-colon rule that isn't the goal target. +run_make_test(q! all: baz foo:: f1.h ; @echo foo FIRST @@ -38,37 +35,23 @@ f1.h f2.h: ; @echo $@ d :: ; @echo ok d :: d ; @echo oops - -EOF - -close(MAKEFILE); - -# TEST 0: A simple double-colon rule that isn't the goal target. - -&run_make_with_options($makefile, "all", &get_logfile, 0); -$answer = "aaa\nbbb\n"; -&compare_output($answer, &get_logfile(1)); +!, + "all", "aaa\nbbb\n"); # TEST 1: As above, in parallel if ($parallel_jobs) { - &run_make_with_options($makefile, "-j10 all", &get_logfile, 0); - $answer = "aaa\nbbb\n"; - &compare_output($answer, &get_logfile(1)); + run_make_test(undef, "-j10 all", "aaa\nbbb\n"); } # TEST 2: A simple double-colon rule that is the goal target -&run_make_with_options($makefile, "bar", &get_logfile, 0); -$answer = "aaa\naaa done\nbbb\n"; -&compare_output($answer, &get_logfile(1)); +run_make_test(undef, "bar", "aaa\naaa done\nbbb\n"); # TEST 3: As above, in parallel if ($parallel_jobs) { - &run_make_with_options($makefile, "-j10 bar", &get_logfile, 0); - $answer = "aaa\naaa done\nbbb\n"; - &compare_output($answer, &get_logfile(1)); + run_make_test(undef, "-j10 bar", "aaa\naaa done\nbbb\n"); } # TEST 4: Each double-colon rule is supposed to be run individually @@ -76,16 +59,12 @@ if ($parallel_jobs) { &utouch(-5, 'f2.h'); &touch('foo'); -&run_make_with_options($makefile, "foo", &get_logfile, 0); -$answer = "f1.h\nfoo FIRST\n"; -&compare_output($answer, &get_logfile(1)); +run_make_test(undef, "foo", "f1.h\nfoo FIRST\n"); # TEST 5: Again, in parallel. if ($parallel_jobs) { - &run_make_with_options($makefile, "-j10 foo", &get_logfile, 0); - $answer = "f1.h\nfoo FIRST\n"; - &compare_output($answer, &get_logfile(1)); + run_make_test(undef, "-j10 foo", "f1.h\nfoo FIRST\n"); } # TEST 6: Each double-colon rule is supposed to be run individually @@ -94,32 +73,24 @@ if ($parallel_jobs) { unlink('f2.h'); &touch('foo'); -&run_make_with_options($makefile, "foo", &get_logfile, 0); -$answer = "f2.h\nfoo SECOND\n"; -&compare_output($answer, &get_logfile(1)); +run_make_test(undef, "foo", "f2.h\nfoo SECOND\n"); # TEST 7: Again, in parallel. if ($parallel_jobs) { - &run_make_with_options($makefile, "-j10 foo", &get_logfile, 0); - $answer = "f2.h\nfoo SECOND\n"; - &compare_output($answer, &get_logfile(1)); + run_make_test(undef, "-j10 foo", "f2.h\nfoo SECOND\n"); } # TEST 8: Test circular dependency check; PR/1671 -&run_make_with_options($makefile, "d", &get_logfile, 0); -$answer = "ok\n$make_name: Circular d <- d dependency dropped.\noops\n"; -&compare_output($answer, &get_logfile(1)); +run_make_test(undef, "d", "ok\n$make_name: Circular d <- d dependency dropped.\noops\n"); # TEST 8: I don't grok why this is different than the above, but it is... # # Hmm... further testing indicates this might be timing-dependent? # #if ($parallel_jobs) { -# &run_make_with_options($makefile, "-j10 biz", &get_logfile, 0); -# $answer = "aaa\ntwo\nbbb\n"; -# &compare_output($answer, &get_logfile(1)); +# run_make_test(undef, "-j10 biz", "aaa\ntwo\nbbb\n"); #} unlink('foo','f1.h','f2.h'); @@ -133,16 +104,17 @@ unlink('foo','f1.h','f2.h'); &touch('two'); run_make_test(' +.RECIPEPREFIX = > .PHONY: all all: result result:: one - @echo $^ >>$@ - @echo $^ +> @echo $^ >>$@ +> @echo $^ result:: two - @echo $^ >>$@ - @echo $^ +> @echo $^ >>$@ +> @echo $^ ', '', @@ -161,23 +133,25 @@ a\ xb :: ; @echo two # Test 11: SV 44742 : All double-colon rules should be run in parallel build. -run_make_test('result :: 01 - @echo update - @touch $@ +run_make_test(' +.RECIPEPREFIX = > +result :: 01 +> @echo update +> @touch $@ result :: 02 - @echo update - @touch $@ +> @echo update +> @touch $@ result :: 03 - @echo update - @touch $@ +> @echo update +> @touch $@ result :: 04 - @echo update - @touch $@ +> @echo update +> @touch $@ result :: 05 - @echo update - @touch $@ +> @echo update +> @touch $@ 01 02 03 04 05: - @touch 01 02 03 04 05 +> @touch 01 02 03 04 05 ', '-j10 result', "update\nupdate\nupdate\nupdate\nupdate\n"); @@ -186,14 +160,10 @@ unlink('result', '01', '02', '03', '04', '05'); # Test 12: SV 44742 : Double-colon rules with parallelism run_make_test(' -root: all - echo root -all:: - echo all_one -all:: 3 - echo all_two -%: - sleep $* +root: all ; echo root +all:: ; echo all_one +all:: 3 ; echo all_two +%: ; sleep $* ', '-rs -j2 1 2 root', "all_one\nall_two\nroot\n"); @@ -212,9 +182,49 @@ FORCE: unlink('joe-is-forced'); +# sv 60188. +# Even though test.x is explicitly mentioned, terminal pattern rules still +# apply only if the prerequisite exists. +touch('hello.z'); + +# subtest 1. test.x is explicitly mentioned. +run_make_test(q! +all: hello.z +%.z:: test.x ; touch $@ +%.x: ; +!, + '', "#MAKE#: Nothing to be done for 'all'.\n"); + +unlink('hello.z'); + +# subtest 2. hello.x is derived from the stem. +touch('hello.z'); + +run_make_test(q! +all: hello.z +%.z:: %.x; touch $@ +%.x: ; touch $@ +!, + '', "#MAKE#: Nothing to be done for 'all'.\n"); + +unlink('hello.z'); + +# subtest 3 +# hello.x is explicitly mentioned on an unrelated rule and thus is not an +# intermediate file. +# Terminal pattern rules do not apply anyway and there is no rule to built +# 'hello.x'. +touch('hello.z'); +run_make_test(q! +all: hello.z +%.z:: %.x; touch $@ +%.x: ; +unrelated: hello.x +!, + '', "#MAKE#: *** No rule to make target 'hello.x', needed by 'hello.z'. Stop.\n", 512); + +unlink('hello.z'); + + # This tells the test driver that the perl test script executed properly. 1; - -### Local Variables: -### eval: (setq whitespace-action (delq 'auto-cleanup whitespace-action)) -### End: diff --git a/tests/scripts/features/errors b/tests/scripts/features/errors index f236d51..2cdaf31 100644 --- a/tests/scripts/features/errors +++ b/tests/scripts/features/errors @@ -31,6 +31,18 @@ all: !, '', "hi\nthere\n#MAKE#: *** [#MAKEFILE#:5: all] Error 1", 512); +# Windows error look completely different :-/ + +sub errors_getinfo +{ + my ($cmd, $args) = @_; + if ($port_type eq 'W32') { + return (2, "process_begin: CreateProcess(NULL, $cmd $args, ...) failed.\nmake (e=2): The system cannot find the file specified."); + } + + return (127, "#MAKE#: $cmd: $ERR_no_such_file"); +} + # TEST #3 # ------- @@ -38,35 +50,36 @@ all: my $unk = './foobarbazbozblat'; unlink($unk); -my $err = $ERR_no_such_file; - +my ($ernum, $erstr) = errors_getinfo($unk, "xx yy"); run_make_test(qq! one: ; -$unk xx yy -!, - 'one', "$unk xx yy\n#MAKE#: $unk: $err\n#MAKE#: [#MAKEFILE#:2: one] Error 127 (ignored)\n"); +!, 'one', + "$unk xx yy\n$erstr\n#MAKE#: [#MAKEFILE#:2: one] Error $ernum (ignored)\n"); # TEST #4 # ------- +($ernum, $erstr) = errors_getinfo($unk, "aa bb"); run_make_test(qq! two: ; $unk aa bb !, 'two -i', - "$unk aa bb\n#MAKE#: $unk: $err\n#MAKE#: [#MAKEFILE#:2: two] Error 127 (ignored)\n"); + "$unk aa bb\n$erstr\n#MAKE#: [#MAKEFILE#:2: two] Error $ernum (ignored)\n"); # TEST #5 # ------- run_make_test(undef, 'two', - "$unk aa bb\n#MAKE#: $unk: $err\n#MAKE#: *** [#MAKEFILE#:2: two] Error 127\n", 512); + "$unk aa bb\n$erstr\n#MAKE#: *** [#MAKEFILE#:2: two] Error $ernum\n", 512); # SV #56918 : Test the unknown command as the second recipe line +($ernum, $erstr) = errors_getinfo($unk, "qq rr"); run_make_test(qq! three: \t\@echo one \t$unk qq rr !, 'three', - "one\n$unk qq rr\n#MAKE#: $unk: $err\n#MAKE#: *** [#MAKEFILE#:4: three] Error 127\n", 512); + "one\n$unk qq rr\n$erstr\n#MAKE#: *** [#MAKEFILE#:4: three] Error $ernum\n", 512); # Try failing due to non-executable file @@ -86,7 +99,7 @@ if ($ERR_nonexe_file) { # Try failing by "running" a directory if ($ERR_exe_dir) { - mkdir('sd', 0775); + mkdir('sd', 0775) or print "mkdir: sd: $!\n"; run_make_test(q! PATH := . diff --git a/tests/scripts/features/exec b/tests/scripts/features/exec index 91181f4..f139cf8 100644 --- a/tests/scripts/features/exec +++ b/tests/scripts/features/exec @@ -3,40 +3,49 @@ use warnings; my $description = "Test that make can execute binaries as well as scripts with" - ." various shabangs and without a shebang"; + ." various shabangs and without a shbang"; my $details = "The various shells that this test uses are the default" ." /bin/sh, \$SHELL and the perl interpreter that is" ." executing this test program. The shells are used for the value" - ." of SHELL inside the test makefile and also as a shebang in the" + ." of SHELL inside the test makefile and also as a shbang in the" ." executed script. There is also a test which executes a script" - ." that has no shebang."; + ." that has no shbang."; # Only bother with this on UNIX systems $port_type eq 'UNIX' or return -1; +$^O =~ /cygwin/ and return -1; +my @shbangs = ('', '#!/bin/sh', "#!$perl_name"); +my @shells = ('', 'SHELL=/bin/sh'); + +# Try whatever shell the user has, as long as it's not a C shell. +# The C shell is not usable with make, due to not correctly handling +# file descriptors and possibly other issues. my $usersh = $origENV{SHELL}; -my $answer = 'hello, world'; +if ($usersh !~ /csh/) { + push @shbangs, ("#!$usersh"); + push @shells, ("SHELL=$usersh"); +} -my @shebangs = ('', '#!/bin/sh', "#!$usersh", "#!$perl_name"); -my @shells = ('', 'SHELL=/bin/sh', "SHELL=$usersh"); +my $answer = 'hello, world'; # tests [0-11] # Have a makefile with various SHELL= exec a shell program with varios -# shebangs or without a shebang at all. +# shbangs or without a shbang at all. my $stem = './exec.cmd'; my $k = 0; -for my $shebang (@shebangs) { +for my $shbang (@shbangs) { for my $shell (@shells) { my $cmd = $k ? "$stem.$k" : $stem; ++$k; unlink $cmd; open(CMD,"> $cmd"); - print CMD "$shebang\n"; + print CMD "$shbang\n"; print CMD "printf \"$answer\\n\";\n"; close(CMD); chmod 0700, $cmd; - run_make_test(q! + run_make_test("# shbang=$shbang\n# shell=$shell" . q! all:; @$(CMD) !, "$shell CMD=$cmd", "$answer\n"); diff --git a/tests/scripts/features/export b/tests/scripts/features/export index 81bff0c..ad58177 100644 --- a/tests/scripts/features/export +++ b/tests/scripts/features/export @@ -32,16 +32,17 @@ ifdef EXPORT_ALL_PSEUDO .EXPORT_ALL_VARIABLES: endif +.RECIPEPREFIX := > all: - @echo "FOO=$(FOO) BAR=$(BAR) BAZ=$(BAZ) BOZ=$(BOZ) BITZ=$(BITZ) BOTZ=$(BOTZ)" - @echo "FOO=$$FOO BAR=$$BAR BAZ=$$BAZ BOZ=$$BOZ BITZ=$$BITZ BOTZ=$$BOTZ" +> @echo "FOO=$(FOO) BAR=$(BAR) BAZ=$(BAZ) BOZ=$(BOZ) BITZ=$(BITZ) BOTZ=$(BOTZ)" +> @echo "FOO=$$FOO BAR=$$BAR BAZ=$$BAZ BOZ=$$BOZ BITZ=$$BITZ BOTZ=$$BOTZ" ', '', "FOO=foo BAR=bar BAZ=baz BOZ=boz BITZ=bitz BOTZ=botz FOO= BAR= BAZ=baz BOZ=boz BITZ=bitz BOTZ=\n"); # TEST 1: make sure vars inherited from the parent are exported -$extraENV{FOO} = 1; +$ENV{FOO} = 1; &run_make_test(undef, '', "FOO=foo BAR=bar BAZ=baz BOZ=boz BITZ=bitz BOTZ=botz FOO=foo BAR= BAZ=baz BOZ=boz BITZ=bitz BOTZ=\n"); @@ -85,9 +86,10 @@ B = b export $(FOO) export $(B)ar +.RECIPEPREFIX := > all: - @echo foo=$(foo) bar=$(bar) - @echo foo=$$foo bar=$$bar +> @echo foo=$(foo) bar=$(bar) +> @echo foo=$$foo bar=$$bar ', "", "foo=f-ok bar=b-ok\nfoo=f-ok bar=b-ok\n"); @@ -108,9 +110,10 @@ export foo bar unexport $(FOO) unexport $(B)ar +.RECIPEPREFIX := > all: - @echo foo=$(foo) bar=$(bar) - @echo foo=$$foo bar=$$bar +> @echo foo=$(foo) bar=$(bar) +> @echo foo=$$foo bar=$$bar ', '', "foo=f-ok bar=b-ok\nfoo= bar=\n"); @@ -140,7 +143,8 @@ all: ; @echo A=$$A B=$$B C=$$C D=$$D E=$$E F=$$F G=$$G H=$$H I=$$I J=$$J # TEST 8: Test unexporting multiple variables on the same line -@extraENV{qw(A B C D E F G H I J)} = qw(1 2 3 4 5 6 7 8 9 10); +@args{qw(A B C D E F G H I J)} = qw(1 2 3 4 5 6 7 8 9 10); +%ENV = (%ENV, %args); &run_make_test(' A = a @@ -174,7 +178,7 @@ a: ; @echo "\$$(export)=$(export) / \$$export=$$export" ', '', "\$(export)=456 / \$export=456\n"); -# TEST 9: Check "export" as a target +# TEST 10: Check "export" as a target &run_make_test(' a: export @@ -182,5 +186,25 @@ export: ; @echo "$@" ', '', "export\n"); +# Check export and assignment of a variable on the same line + +$ENV{hello} = 'moon'; + +run_make_test(q! +all: ; @echo hello=$(hello) hello=$$hello +export hello=sun +!, + '', "hello=sun hello=sun\n"); + +# Check unexport and assignment of a variable on the same line + +$ENV{hello} = 'moon'; + +run_make_test(q! +all: ; @echo hello=$(hello) hello=$$hello +unexport hello=sun +!, + '', "hello=sun hello=\n"); + # This tells the test driver that the perl test script executed properly. 1; diff --git a/tests/scripts/features/grouped_targets b/tests/scripts/features/grouped_targets index 615e962..6b3c561 100644 --- a/tests/scripts/features/grouped_targets +++ b/tests/scripts/features/grouped_targets @@ -129,5 +129,79 @@ f g h&:: ; @echo Z '', "Z"); +# sv 60188. +# Test that a file explicitly mentioned by the user and made by an implicit +# rule is not considered intermediate. + +touch('hello.z'); +touch('hello.q'); + +# subtest 1 +# hello.x is not explicitly mentioned and thus is an intermediate file. +run_make_test(q! +all: hello.z +%.z %.q: %.x ; touch $*.z $*.q +%.x: ; +!, '', "#MAKE#: Nothing to be done for 'all'.\n"); + +# subtest 2 +# test.x is explicitly mentioned and thus is not an intermediate file. +run_make_test(q! +all: hello.z +%.z %.q: %.x test.x ; @echo $*.z $*.q +%.x: ; +!, '', "hello.z hello.q\n"); + +# subtest 3 +# hello.x is explicitly mentioned on an unrelated rule and thus is not an +# intermediate file. +run_make_test(q! +all: hello.z +%.z %.q: %.x; @echo $*.z $*.q +%.x: ; +unrelated: hello.x +!, '', "hello.z hello.q\n"); + +unlink('hello.z'); +unlink('hello.q'); + +# SV 62809: Missing grouped target peer causes remake regardless of which +# target caused the rule to run. +touch(qw(gta)); # but not gtb +run_make_test(q! +gta gtb &: ; touch gta gtb +!, + 'gta', "touch gta gtb\n"); +unlink(qw(gta gtb)); + +# Ensure both goal targets are built if they depend on a grouped prereq +touch(qw(gta)); # but not gtb +run_make_test(q! +x1 x2: ; touch $@ + +x1: gta +x2: gtb + +gta gtb &: ; touch gta gtb +!, + 'x1 x2', "touch gta gtb\ntouch x1\ntouch x2\n"); + +# Now everything should be up to date +run_make_test(undef, 'x1 x2', + "#MAKE#: 'x1' is up to date.\n#MAKE#: 'x2' is up to date."); + +unlink(qw(x1 x2 gta gtb)); + +# If an also-make file is older than a prerequisite build both + +utouch(-20, 'gtb'); +utouch(-10, 'pre'); +touch(qw(gta)); +run_make_test(q! +gta gtb &: pre ; touch gta gtb +!, + 'gta', "touch gta gtb\n"); +unlink(qw(pre gta gtb)); + # This tells the test driver that the perl test script executed properly. 1; diff --git a/tests/scripts/features/implicit_search b/tests/scripts/features/implicit_search new file mode 100644 index 0000000..564dc5b --- /dev/null +++ b/tests/scripts/features/implicit_search @@ -0,0 +1,483 @@ +# -*-perl-*- + +$description = "Test implicit rule search."; + +$details = ""; + +# sv 48643 +# Each test has a %.c rule ahead of %.f rule. +# hello.f exists and hello.c is missing. + +unlink('hello.c', 'hello.tsk', 'hello.o', 'hello.x'); + +# Run every test with and without a suffix. +my @suffixes = ('', '.o'); +# Run every test with single and double colon rules. +my @rules = ('', ':'); + +for my $s (@suffixes) { +for my $r (@rules) { +touch('hello.f'); + +# Test that make finds the intended implicit rule based on existence of a +# prerequisite in the filesystem. +# +# '%.o: %.c' rule is skipped and '%.o: %.f' rule is chosen. +run_make_test(" +all: hello$s +%$s:$r %.c; \$(info hello.c) +%$s:$r %.f; \$(info hello.f) +", '-r', "hello.f\n#MAKE#: Nothing to be done for 'all'."); + +# Test that make finds the intended implicit rule based on the explicit +# prerequisite of the top goal and despite the existence of a +# prerequisite in the filesystem. +# +# hello.c is an explicit prerequisite of the top target (hello.o or hello). +# hello.c ought to exist. +# hello.c prerequisite causes '%.o: %.c' rule to be chosen. +run_make_test(" +hello$s: hello.c +%$s:$r %.c; \$(info hello.c) +%$s:$r %.f; \$(info hello.f) +", '-r', +"#MAKE#: *** No rule to make target 'hello.c', needed by 'hello$s'. Stop.\n", +512); + +# Test that make finds the intended implicit rule when the implicit +# prerequisite matches a target of an unrelated rule and despite the existence +# of a prerequisite of the other rule candidate in the filesystem. +# +# hello.c matches 'hello.c:' rule. This makes hello.c a target and thus ought +# to exist. +# hello.c prerequisite causes '%.o: %.c' rule to be chosen. +run_make_test(" +all: hello$s +%$s:$r %.c; \$(info hello.c) +%$s:$r %.f; \$(info hello.f) +hello.c:; @#HELPER# fail 1 +", '-r', "fail 1\n#MAKE#: *** [#MAKEFILE#:5: hello.c] Error 1\n", 512); + +# Test that make finds the intended implicit rule based on existence of a +# prerequisite in the filesystem, even when the prerequisite of another +# candidate rule is mentioned explicitly on an unrelated rule. +# +# '%.o: %.c' rule is skipped and '%.o: %.f' rule is chosen, even though hello.c +# is mentioned explicitly on 'unrelated: hello.c'. +# ought-to-exist does not apply to hello.c. +run_make_test(" +all: hello$s +%$s:$r %.c; \$(info hello.c) +%$s:$r %.f; \$(info hello.f) +unrelated: hello.c +", '-r', "hello.f\n#MAKE#: Nothing to be done for 'all'."); + +# Test that make finds the intended implicit rule based on existence of a +# prerequisite in the filesystem. +# +# '%.o: %.c' rule is skipped and '%.o: %.f' rule is chosen. +# Despite '%.o: %.c hello.c' rule having explicit prerequisite hello.c. +# ought-to-exist does not apply to hello.c. +run_make_test(" +all: hello$s +%$s:$r %.c hello.c; \$(info hello.c) +%$s:$r %.f; \$(info hello.f) +", '-r', "hello.f\n#MAKE#: Nothing to be done for 'all'."); + +# '%.o: %.c' rule is skipped and '%.o: %.f' rule is chosen. +# '%.o: %.f hello.f' rule has explicit prerequisite hello.f. +# ought-to-exist does not apply to hello.c. +run_make_test(" +all: hello$s +%$s:$r %.c; \$(info hello.c) +%$s:$r %.f hello.f; \$(info hello.f) +", '-r', "hello.f\n#MAKE#: Nothing to be done for 'all'."); + +# Rule '%: %.f' is chosen, because '%: %.f' requires no intermediates. +# '%: %.c', on the other hand, requires intemediate hello.c to be built by the +# default rule. +run_make_test(" +all: hello$s +%$s:$r %.c; \$(info \$<) +%$s:$r %.f; \$(info \$<) +.DEFAULT:; \$(info \$\@) true +unrelated: hello.c +", '-r', "hello.f\n#MAKE#: Nothing to be done for 'all'."); + + +# hello.f is missing. +# This time both hello.c and hello.f are missing and both '%: %.c' and '%: %.f' +# require an intermediate. +# The default rule builds intemerdiate hello.c. +# '%: %.c' rule is chosen to build hello. +unlink('hello.f'); +run_make_test(" +all: hello$s +%$s:$r %.c; \$(info \$<) +%$s:$r %.f; \$(info \$<) +.DEFAULT:; \@\$(info \$\@) #HELPER# fail 1 +unrelated: hello.c +", '-r', "hello.c\nfail 1\n#MAKE#: *** [#MAKEFILE#:5: hello.c] Error 1\n", 512); + +# hello.f is missing. +# No rule is found, because hello.c is not mentioned explicitly. +run_make_test(" +all: hello$s +%$s:$r %.c; \$(info \$<) +%$s:$r %.f; \$(info \$<) +.DEFAULT:; \@\$(info \$\@) #HELPER# fail 1 +", '-r', "hello$s\nfail 1\n#MAKE#: *** [#MAKEFILE#:5: hello$s] Error 1\n", 512); + +} +} + +# Almost the same tests as above, but this time an intermediate is built. + +touch('hello.f'); +for my $s (@suffixes) { +for my $r (@rules) { + +my $result = "#MAKE#: *** No rule to make target 'hello.tsk', needed by 'all'. Stop.\n"; +my $rcode = 512; +if ($s or $r) { + $result = "hello.f\nhello.tsk\n#MAKE#: Nothing to be done for 'all'."; + $rcode = 0; +} + +run_make_test(" +all: hello.tsk +%.tsk: %$s; \$(info hello.tsk) +%$s:$r %.c; \$(info hello.c) +%$s:$r %.f; \$(info hello.f) +", '-r', "$result", $rcode); + +run_make_test(" +all: hello.tsk +%.tsk: %$s hello$s; \$(info hello.tsk) +%$s:$r %.c; \$(info hello.c) +%$s:$r %.f; \$(info hello.f) +", '-r', $result, $rcode); + +run_make_test(" +all: hello.tsk +%.tsk: %$s; \$(info hello.tsk) +%$s:$r %.c hello$s; \$(info hello.c) +%$s:$r %.f; \$(info hello.f) +", '-r', $result, $rcode); + +} +} + +for my $r (@rules) { + +# Circular dependency hello.o <- hello.tsk is dropped. +run_make_test(" +all: hello.tsk +%.tsk: %.o; \$(info hello.tsk) +%.o:$r %.c; \$(info hello.c) +%.o:$r %.f %.tsk; \$(info hello.f) +", '-r', +"#MAKE#: Circular hello.o <- hello.tsk dependency dropped.\nhello.f\nhello.tsk\n#MAKE#: Nothing to be done for 'all'."); + +} + + +for my $s (@suffixes) { +for my $r (@rules) { + +run_make_test(" +all: hello.tsk +hello$s: hello.c +%.tsk: %$s; \$(info hello.tsk) +%$s:$r %.c; \$(info hello.c) +%$s:$r %.f; \$(info hello.f) +", '-r', +"#MAKE#: *** No rule to make target 'hello.c', needed by 'hello$s'. Stop.\n", +512); +} +} + +for my $s (@suffixes) { +for my $r (@rules) { + +my $result = "#MAKE#: *** No rule to make target 'hello.tsk', needed by 'all'. Stop.\n"; +if ($s or $r) { + $result = "fail 1\n#MAKE#: *** [#MAKEFILE#:6: hello.c] Error 1\n"; +} + +run_make_test(" +all: hello.tsk +%.tsk: %$s; \$(info hello.tsk) +%$s:$r %.c; \$(info hello.c) +%$s:$r %.f; \$(info hello.f) +hello.c:; @#HELPER# fail 1 +", '-r', $result, 512); +} +} + + +for my $s (@suffixes) { +for my $r (@rules) { + +run_make_test(" +all: hello.tsk +%.tsk: %$s; \$(info hello.tsk) +%$s:$r %.c; \$(info hello.c) +%$s:$r %.f; \$(info hello.f) +unrelated: hello$s +", '-r', "hello.f\nhello.tsk\n#MAKE#: Nothing to be done for 'all'."); +} +} + +for my $s (@suffixes) { +for my $r (@rules) { + +my $result = "#MAKE#: *** No rule to make target 'hello.tsk', needed by 'all'. Stop.\n"; +my $rcode = 512; +if ($s or $r) { + $result = "hello.f\nhello.tsk\n#MAKE#: Nothing to be done for 'all'."; + $rcode = 0; +} + +run_make_test(" +all: hello.tsk +%.tsk: %$s; \$(info hello.tsk) +%$s:$r %.c; \$(info hello.c) +%$s:$r %.f hello.f; \$(info hello.f) +", '-r', $result, $rcode); +} +} + +# One of the implicit rules has two prerequisites, hello.c and hello.x +# hello.c does not qualify as ought to exit. +# hello.x can be made from hello.z. +# This test exersizes the break, which prevents making hello.x as an +# intermediate from hello.z during compatibility search. +unlink('hello.f'); +touch('hello.z'); +for my $s (@suffixes) { +for my $r (@rules) { + +run_make_test(" +all: hello.tsk +%.tsk: %$s; \$(info hello.tsk) +%$s:$r %.c %.x; \$(info hello.c) +%$s:$r %.f; \$(info hello.f) +unrelated: hello$s +%.x:$r %.z; \$(info hello.z) +", '-r', +"#MAKE#: *** No rule to make target 'hello$s', needed by 'hello.tsk'. Stop.\n", +512); +} +} + +# Test that prerequisite 'hello.x' mentioned explicitly on an unrelated rule is +# not considered intermediate. +touch('hello.tsk'); +unlink('hello.x'); +run_make_test(" +all: hello.tsk +%.tsk: %.x; touch hello.tsk +%.x: ; +unrelated: hello.x +", '-r', "touch hello.tsk\n"); +unlink('hello.tsk'); + +touch ('hello.f'); +# Test implicit search of builtin rules. + +# %: %.c (and other builtin rules) are skipped. +# %: %.f is chosen. +run_make_test(q! +all: hello +!, 'FC="@echo f77" OUTPUT_OPTION=', "f77 hello.f -o hello\n"); + +# %.o: %.c (and other builtin rules) are skipped. +# %.o: %.f is chosen. +run_make_test(q! +all: hello.o +!, 'FC="@echo f77" OUTPUT_OPTION=', "f77 -c hello.f\n"); + + +# %: %.c is chosen. +# hello.c is an explicit prerequisite of the top target hello. +# hello.c ought to exist. +# hello.c prerequisite causes '%: %.c' rule to be chosen. +run_make_test(q! +hello: hello.c +!, 'FC="@echo f77" OUTPUT_OPTION=', +"#MAKE#: *** No rule to make target 'hello.c', needed by 'hello'. Stop.\n", +512); + +# %.o: %.c is chosen. +# hello.c is an explicit prerequisite of the top target hello.o. +# hello.c ought to exist. +# hello.c prerequisite causes '%.o: %.c' rule to be chosen. +run_make_test(q! +hello.o: hello.c +!, 'FC="@echo f77" OUTPUT_OPTION=', +"#MAKE#: *** No rule to make target 'hello.c', needed by 'hello.o'. Stop.\n", +512); + +# %: %.c (and other builtin rules) are skipped. +# %: %.f is chosen. +# ought-to-exist does not apply to hello.c. +run_make_test(q! +all: hello +unrelated: hello.c +!, 'FC="@echo f77" OUTPUT_OPTION=', "f77 hello.f -o hello\n"); + +# %.o: %.c (and other builtin rules) are skipped. +# %.o: %.f is chosen. +# ought-to-exist does not apply to hello.c. +run_make_test(q! +all: hello.o +unrelated: hello.c +!, 'FC="@echo f77" OUTPUT_OPTION=', "f77 -c hello.f\n"); + +# builtin rule %.o: %.f is removed. +# %.o: %.c (and other builtin rules) are skipped, because hello.c is missing. +# ought-to-exist does not apply to hello.c. +# %.o: %.c is chosen as a compatibility rule, because of hello.c. +run_make_test(q! +all: hello.o +unrelated: hello.c +%.o: %.f +!, '', +"#MAKE#: *** No rule to make target 'hello.c', needed by 'hello.o'. Stop.\n", +512); + + +# sv 17752. +# In this test the builtin match-anything rule '%: %.f' is used to build +# intermediate hello from hello.f, because hello is mentioned explicitly in +# the makefile. +run_make_test(q! +all: hello.tsk +%.tsk: %; $(info $@ from $<) +unrelated: hello +!, 'FC="@echo f77" OUTPUT_OPTION=', +"f77 hello.f -o hello\nhello.tsk from hello\n"); + +# In this test the builtin match-anything rule %: %.f cannot be used to build +# intermediate hello from hello.f, because hello is not mentioned explicitly in +# the makefile. +run_make_test(q! +all: hello.tsk +%.tsk: %; $(info $@ from $<) +!, 'FC="@echo f77" OUTPUT_OPTION=', +"#MAKE#: *** No rule to make target 'hello.tsk', needed by 'all'. Stop.\n", +512); + +# This is just like the one above, but compatibility rule '%.tsk: % %.x' has 2 +# prerequisites, '%' and '%.x'. +# '%' expands to 'hello' and matches the explicit 'hello' on the unrelated rule. +# '%.x' is an intermediate built from 'hello.xx' by rule '%.x: %.xx' during the +# second pass (intermed_ok == 1) of compatibility search. +# This test validates that compatibility search performs both intermed_ok == 0 +# and intermed_ok == 1 passes. +unlink('hello.x'); +touch('hello.xx'); +run_make_test(q! +all: hello.tsk +%.tsk: % %.x; $(info $@ from $^) +unrelated: hello +%.x: %.xx; $(info $@ from $<) +!, 'FC="@echo f77" OUTPUT_OPTION=', +"f77 hello.f -o hello\nhello.x from hello.xx\nhello.tsk from hello hello.x\n"); + +unlink('bye.o', 'bye.tsk', 'bye.x'); +# sv 21670. +# Default recipe is used to build bye.o. +run_make_test(q! +all: bye.tsk +%.tsk: %.o; $(info $@ from $<) +.DEFAULT:; $(info bye.o) +unrelated: bye.o +!, '-r', "bye.o\nbye.tsk from bye.o\n#MAKE#: Nothing to be done for 'all'."); + +touch('bye.xx'); +# This is just like the one above, but compatibility rule '%.tsk: %.o %.x' has 2 +# prerequisites, '%.o' and '%.x'. +# '%.o' expands to 'bye.o' and matches the explicit 'bye.o' on the unrelated rule. +# '%.x' is an intermediate built from 'bye.xx' by rule '%.x: %.xx' during the +# second pass (intermed_ok == 1) of compatibility search. +# This test validates that compatibility search performs both intermed_ok == 0 +# and intermed_ok == 1 passes. +run_make_test(q! +all: bye.tsk +%.tsk: %.o %.x; $(info $@ from $^) +.DEFAULT:; $(info bye.o) +unrelated: bye.o +%.x: %.xx; $(info $@ from $<) +!, '-r', +"bye.o\nbye.x from bye.xx\nbye.tsk from bye.o bye.x\n#MAKE#: Nothing to be done for 'all'."); + +unlink('hello.f', 'hello.z', 'hello.xx', 'bye.xx'); + + +# A target specific variable causes the file to be entered to the database as a +# prerequisite. Implicit search then treats this file as explicitly mentioned. +# Test that implicit search keeps target specific variables of this file intact. +# In this series of tests prerequisite 'hello.x' has a target specific variable +# and is built as an intermediate. Implicit search treats 'hello.x' as +# explicitly mentioned, but 'hello.x' does not qualify as ought-to-exist. +unlink('hello.x', 'hello.tsk'); + +# 'hello.x' is mentioned explicitly on the same implicit rule. +run_make_test(q! +all: hello.tsk +%.tsk: hello.x; $(info $@) +%.x:; $(flags) +hello.x: flags:=true +!, '-r', "true\nhello.tsk\n"); + +# Similar to the one above, but this time 'hello.x' is derived from the stem. +run_make_test(q! +all: hello.tsk +%.tsk: %.x; $(info $@) +%.x:; $(flags) +hello.x: flags:=true +!, '-r', "true\nhello.tsk\n"); + +# Similar to the one above, this time 'hello.x' is also mentioned explicitly on +# an unrelated rule. +run_make_test(q! +all: hello.tsk +%.tsk: %.x; $(info $@) +%.x:; $(flags) +hello.x: flags:=true +unrelated: hello.x +!, '-r', "true\nhello.tsk\n"); + +# 'hello.x' has a pattern specific variable. +run_make_test(q! +all: hello.tsk +%.tsk: %.x; $(info $@) +%.x:; $(flags) +%.x: flags:=true +!, '-r', "true\nhello.tsk\n"); + +# 'hello.x' has a target specific variable and a pattern specific variable. +run_make_test(q! +all: hello.tsk +%.tsk: %.x; $(info $@) +%.x:; $(flags) +hello.x: flags+=good +%.x: flags:=true +!, '-r', "true good\nhello.tsk\n"); + +# Intermediate prerequisite 'hello.x' has a target specific variable, a pattern +# specfic variable, matches on both rules '%.tsk: %.x' and 'big_%.tsk: %.x'. +run_make_test(q! +all: hello.tsk big_hello.tsk +%.tsk: %.x; $(info $@) +big_%.tsk: %.x; $(info $@) +%.x:; $(flags) +hello.x: flags+=good +%.x: flags:=true +!, '-r', "true good\nhello.tsk\nbig_hello.tsk\n"); + + +# This tells the test driver that the perl test script executed properly. +1; diff --git a/tests/scripts/features/include b/tests/scripts/features/include index 0c63c06..69d6718 100644 --- a/tests/scripts/features/include +++ b/tests/scripts/features/include @@ -8,16 +8,11 @@ Test extra whitespace at the end of the include, multiple -includes and sincludes (should not give an error) and make sure that errors are reported for targets that were also -included."; -$makefile2 = &get_tmpfile; +create_file('incl.mk', "ANOTHER: ; \@echo This is another included makefile\n"); -open(MAKEFILE,"> $makefile"); - -# The contents of the Makefile ... - -print MAKEFILE <<EOF; -\#Extra space at the end of the following file name -include $makefile2 -all: ; \@echo There should be no errors for this makefile. +run_make_test(qq!#Extra space at the end of the following file name +include incl.mk ! . q! +all: ; @echo There should be no errors for this makefile. -include nonexistent.mk -include nonexistent.mk @@ -27,27 +22,12 @@ sinclude nonexistent-2.mk sinclude makeit.mk error: makeit.mk -EOF - -close(MAKEFILE); - - -open(MAKEFILE,"> $makefile2"); - -print MAKEFILE "ANOTHER: ; \@echo This is another included makefile\n"; - -close(MAKEFILE); - -# Create the answer to what should be produced by this Makefile -&run_make_with_options($makefile, "all", &get_logfile); -$answer = "There should be no errors for this makefile.\n"; -&compare_output($answer, &get_logfile(1)); +!, + "all", "There should be no errors for this makefile.\n"); -&run_make_with_options($makefile, "ANOTHER", &get_logfile); -$answer = "This is another included makefile\n"; -&compare_output($answer, &get_logfile(1)); +run_make_test(undef, "ANOTHER", "This is another included makefile\n"); -$makefile = undef; +unlink('incl.mk'); # Try to build the "error" target; this will fail since we don't know # how to create makeit.mk, but we should also get a message (even though @@ -64,6 +44,22 @@ error: foo.mk ; @echo $@ 512 ); +# The same as above with an additional include directory. + +mkdir('hellod', 0777); + +run_make_test + (' +-include foo.mk +error: foo.mk ; @echo $@ +', + '-Ihellod', + "#MAKE#: *** No rule to make target 'foo.mk', needed by 'error'. Stop.\n", + 512 + ); + +rmdir('hellod'); + # Make sure that target-specific variables don't impact things. This could # happen because a file record is created when a target-specific variable is # set. @@ -157,12 +153,50 @@ include inc1 include inc2 inc2:; echo > $@ !, - '', "echo > inc2\necho > inc1\nDONE\n"); + '', "echo > inc1\necho > inc2\nDONE\n"); rmfiles('inc1', 'inc2'); +# Test include of make-able file doesn't show an error. +# Specify an additional include directory. + +mkdir('hellod', 0777); + +run_make_test(q! +.PHONY: default +default:; @echo DONE + +inc1:; echo > $@ +include inc1 +include inc2 +inc2:; echo > $@ +!, + '-Ihellod', "echo > inc1\necho > inc2\nDONE\n"); + +rmfiles('inc1', 'inc2'); + +# Test include of make-able file doesn't show an error. +# inc1 and inc2 are present in the specified include directory. +touch('hellod/inc1'); +touch('hellod/inc2'); + +run_make_test(q! +.PHONY: default +default:; @echo DONE + +inc1:; echo > $@ +include inc1 +include inc2 +inc2:; echo > $@ +!, + '-Ihellod', "DONE\n"); + +rmfiles('inc1', 'inc2', 'hellod/inc1', 'hellod/inc2'); + +rmdir('hellod'); + # No target gets correct error -run_make_test('', '', '#MAKE#: *** No targets. Stop.', 512); +run_make_test("\n", '', '#MAKE#: *** No targets. Stop.', 512); # No target in included file either, still gets correct error. touch('inc1.mk'); @@ -209,7 +243,7 @@ inc1:; echo > $@ include inc1 include inc2 !, - '', "#MAKEFILE#:7: inc2: $ERR_no_such_file\n#MAKE#: *** No rule to make target 'inc2'. Stop.\n", 512); + '', "echo > inc1\n#MAKEFILE#:7: inc2: $ERR_no_such_file\n#MAKE#: *** No rule to make target 'inc2'. Stop.\n", 512); rmfiles('inc1'); @@ -235,10 +269,34 @@ inc1: foo; echo > $@ '', "#MAKEFILE#:3: inc1: $ERR_no_such_file\n#MAKE#: *** No rule to make target 'foo', needed by 'inc1'. Stop.\n", 512); rmfiles('inc1'); + + # Check that included double-colon targets with no prerequisites aren't + # built. This should fail as hello.mk doesn't exist + + run_make_test(q! +.PHONY: default +default:;@echo 'FOO=$(FOO)' +include hello.mk +hello.mk:: ; echo 'FOO=bar' > $@ +!, + '', "#MAKEFILE#:4: hello.mk: $ERR_no_such_file", 512); + + # Check that included phony targets aren't built. + # This should fail as hello.mk doesn't exist + + run_make_test(q! +.PHONY: default +default:;@echo 'FOO=$(FOO)' +include hello.mk +hello.mk: ; echo 'FOO=bar' > $@ +.PHONY: hello.mk +!, + '', "#MAKEFILE#:4: hello.mk: $ERR_no_such_file", 512); } -# Including files that can't be read should show an error if (defined $ERR_unreadable_file) { + # Including files that can't be read should show an error + unlink('inc1'); create_file('inc1', 'FOO := foo'); chmod 0000, 'inc1'; @@ -248,7 +306,18 @@ all:;@echo $(FOO) !, '', "#MAKEFILE#:2: inc1: $ERR_unreadable_file\n#MAKE#: *** No rule to make target 'inc1'. Stop.", 512); -# Unreadable files that we know how to successfully recreate should work + # Including files that can't be read should show an error, even when there + # is a readable file in a subsequent include directory. + mkdir('hellod', 0777); + touch("hellod/inc1"); + + run_make_test(q! +include inc1 +all:;@echo $(FOO) +!, + '-Ihellod', "#MAKEFILE#:2: inc1: $ERR_unreadable_file\n#MAKE#: *** No rule to make target 'inc1'. Stop.", 512); + + # Unreadable files that we know how to successfully recreate should work run_make_test(sprintf(q! all:;@echo $(FOO) @@ -257,7 +326,140 @@ inc1:; @%s $@ && echo FOO := bar > $@ !, $CMD_rmfile), '', "bar"); - rmfiles('inc1'); + # Unreadable files that we know how to successfully recreate should work. + # Even when there is a readable file in an additional include directory. + + unlink('inc1'); + create_file('inc1', 'FOO := foo'); + chmod 0000, 'inc1'; + + run_make_test(sprintf(q! +all:;@echo $(FOO) +include inc1 +inc1:; @%s $@ && echo FOO := bar > $@ +!, $CMD_rmfile), + '-Ihellod', "bar"); + + rmfiles('inc1', 'hellod/inc1'); + rmdir('hellod'); +} + +# Check that the order of remaking include files is correct: should remake +# them in the same order they were encountered in the makefile. SV 58735 + +run_make_test(q! +-include i1 i2 +-include i3 +-include i4 +%:;@echo $@ +all:; +!, + '', "i1\ni2\ni3\ni4\n#MAKE#: 'all' is up to date.\n"); + +# Check that included files work if created after the first include failed +# https://savannah.gnu.org/bugs/?57676 + +run_make_test(q! +default:; @echo $(hello) +-include hello.mk +$(shell echo hello=world >hello.mk) +include hello.mk +!, + '', "world\n"); + +unlink('hello.mk'); + +# Check that included double-colon targets with no prerequisites aren't built. +# This should succeed since hello.mk already exists + +touch('hello.mk'); + +run_make_test(q! +.PHONY: default +default:;@echo 'FOO=$(FOO)' +include hello.mk +hello.mk:: ; echo 'FOO=bar' > $@ +!, + '', 'FOO='); + +unlink('hello.mk'); + +# Check that included double-colon targets with no prerequisites aren't built. +# This should succeed due to -include + +run_make_test(q! +.PHONY: default +default:;@echo 'FOO=$(FOO)' +-include hello.mk +hello.mk:: ; echo 'FOO=bar' > $@ +!, + '', 'FOO='); + +# Check that phony targets aren't built. +# This should succeed since hello.mk already exists + +touch('hello.mk'); + +run_make_test(q! +.PHONY: default +default:;@echo 'FOO=$(FOO)' +include hello.mk +hello.mk: ; echo 'FOO=bar' > $@ +.PHONY: hello.mk +!, + '', 'FOO='); + +unlink('hello.mk'); + +# Check that included double-colon targets with no prerequisites aren't built. +# This should succeed due to -include + +run_make_test(q! +.PHONY: default +default:;@echo 'FOO=$(FOO)' +-include hello.mk +hello.mk: ; echo 'FOO=bar' > $@ +.PHONY: hello.mk +!, + '', 'FOO='); + +# SV 56301 Verify pattern rules creating optional includes. +# -k shouldn't matter when creating include files. + +run_make_test(q! +all:; @echo hello +-include inc_a.mk +include inc_b.mk +%_a.mk %_b.mk:; exit 1 +!, + '', "exit 1\n#MAKEFILE#:4: Failed to remake makefile 'inc_b.mk'.\n", 512); + +run_make_test(undef, '-k', "exit 1\n#MAKEFILE#:4: Failed to remake makefile 'inc_b.mk'.\n", 512); + +# It seems wrong to me that this gives a different error message, but at +# least it doesn't keep going. +run_make_test(q! +all:; @echo hello +include inc_a.mk +-include inc_b.mk +%_a.mk %_b.mk:; exit 1 +!, + '', "exit 1\n#MAKEFILE#:3: inc_a.mk: $ERR_no_such_file\n#MAKE#: *** [#MAKEFILE#:5: inc_a.mk] Error 1\n", 512); + +run_make_test(undef, '-k', "exit 1\n#MAKEFILE#:3: inc_a.mk: $ERR_no_such_file\n#MAKE#: *** [#MAKEFILE#:5: inc_a.mk] Error 1\n#MAKEFILE#:3: Failed to remake makefile 'inc_a.mk'.\n", 512); + +# Check the default makefiles... this requires us to invoke make with no +# arguments. Also check MAKEFILES + +if ($port_type eq 'W32') { + $defaults = "GNUmakefile\nmakefile\nMakefile\nmakefile.mak"; +} else { + $defaults = "GNUmakefile\nmakefile\nMakefile"; } +$ENV{MAKEFILES} = 'foobar barfoo'; +run_make_with_options(undef, ['-E', '%:;@echo $@', '-E', 'all:;', '-E', '-include bizbaz', '-E', '-include bazbiz'], get_logfile(0)); +$answer = "bizbaz\nbazbiz\nfoobar\nbarfoo\n$defaults\n#MAKE#: 'all' is up to date.\n"; +&compare_output(subst_make_string($answer), &get_logfile(1)); + 1; diff --git a/tests/scripts/features/jobserver b/tests/scripts/features/jobserver index 73d10d9..8ecbe34 100644 --- a/tests/scripts/features/jobserver +++ b/tests/scripts/features/jobserver @@ -25,17 +25,16 @@ all:;@echo $@: "/$(SHOW)/" # Setting parallelism with the environment # Command line should take precedence over the environment -$extraENV{MAKEFLAGS} = "-j2 $np"; +$ENV{MAKEFLAGS} = "-j2 $np"; run_make_test(q! SHOW = $(patsubst --jobserver-auth=%,--jobserver-auth=<auth>,$(MAKEFLAGS)) recurse: ; @echo $@: "/$(SHOW)/"; $(MAKE) -f #MAKEFILE# all all:;@echo $@: "/$(SHOW)/" !, '', "recurse: /-j2 --jobserver-auth=<auth> $np/\nall: /-j2 --jobserver-auth=<auth> $np/\n"); -delete $extraENV{MAKEFLAGS}; # Test override of -jN -$extraENV{MAKEFLAGS} = "-j9 $np"; +$ENV{MAKEFLAGS} = "-j9 $np"; run_make_test(q! SHOW = $(patsubst --jobserver-auth=%,--jobserver-auth=<auth>,$(MAKEFLAGS)) recurse: ; @echo $@: "/$(SHOW)/"; $(MAKE) -j3 -f #MAKEFILE# recurse2 @@ -43,7 +42,6 @@ recurse2: ; @echo $@: "/$(SHOW)/"; $(MAKE) -f #MAKEFILE# all all:;@echo $@: "/$(SHOW)/" !, "-j2 $np", "recurse: /-j2 --jobserver-auth=<auth> $np/\n#MAKE#[1]: warning: -j3 forced in submake: resetting jobserver mode.\nrecurse2: /-j3 --jobserver-auth=<auth> $np/\nall: /-j3 --jobserver-auth=<auth> $np/\n"); -delete $extraENV{MAKEFLAGS}; # Test override of -jN with -j run_make_test(q! @@ -64,17 +62,18 @@ all:;@echo $@: "/$(SHOW)/" unlink('inc.mk'); run_make_test(q! +.RECIPEPREFIX = > -include inc.mk recur: -# @echo 'MAKEFLAGS = $(MAKEFLAGS)' - @rm -f inc.mk - @$(MAKE) -j2 -f #MAKEFILE# all +#> @echo 'MAKEFLAGS = $(MAKEFLAGS)' +> @rm -f inc.mk +> @$(MAKE) -j2 -f #MAKEFILE# all all: -# @echo 'MAKEFLAGS = $(MAKEFLAGS)' - @echo $@ +#> @echo 'MAKEFLAGS = $(MAKEFLAGS)' +> @echo $@ inc.mk: -# @echo 'MAKEFLAGS = $(MAKEFLAGS)' - @echo 'FOO = bar' > $@ +#> @echo 'MAKEFLAGS = $(MAKEFLAGS)' +> @echo 'FOO = bar' > $@ !, "$np -j2", "#MAKE#[1]: warning: -j2 forced in submake: resetting jobserver mode.\nall\n"); @@ -83,27 +82,79 @@ unlink('inc.mk'); # Test recursion which is hidden from make. # See Savannah bug #39934 # Or Red Hat bug https://bugzilla.redhat.com/show_bug.cgi?id=885474 -# Windows doesn't use a pipe, and doesn't close access, so this won't happen. +# Environments that don't use a pipe won't close access, so this won't happen. if ($port_type ne 'W32') { - open(MAKEFILE,"> Makefile2"); - print MAKEFILE ' - vpath %.c ../ - foo: - '; - close(MAKEFILE); + create_file('Makefile2', "vpath %.c ../\n", "foo:\n"); run_make_test(q! default: ; @ #MAKEPATH# -f Makefile2 !, - "-j2 $np", + "--jobserver-style=pipe -j2 $np", "#MAKE#[1]: warning: jobserver unavailable: using -j1. Add '+' to parent make rule. #MAKE#[1]: Nothing to be done for 'foo'."); rmfiles('Makefile2'); } -1; +# For Windows and named pipes, we don't need to worry about recursion +if ($port_type eq 'W32' || exists $FEATURES{'jobserver-fifo'}) { + create_file('Makefile2', "vpath %.c ../\n", "foo:\n"); + + run_make_test(q! +default: ; @ #MAKEPATH# -f Makefile2 +!, + "-j2 $np", +"#MAKE#[1]: Nothing to be done for 'foo'."); + + rmfiles('Makefile2'); +} + +# Ensure enter/leave directory messages appear before jobserver warnings -### Local Variables: -### eval: (setq whitespace-action (delq 'auto-cleanup whitespace-action)) -### End: +run_make_test(q! +all: ; @$(MAKE) -C . -f #MAKEFILE# recurse -j1 +recurse: ; @echo hi +!, + '-w -j2', "#MAKE#: Entering directory '#PWD#' +#MAKE#[1]: Entering directory '#PWD#' +#MAKE#[1]: warning: -j1 forced in submake: resetting jobserver mode. +hi +#MAKE#[1]: Leaving directory '#PWD#' +#MAKE#: Leaving directory '#PWD#'\n"); + +# Check for invalid jobserver-style options + +run_make_test(q! +all: a +all a: ; @echo $@ +!, + '--jobserver-style=foo -j8', + "#MAKE#: *** Unknown jobserver auth style 'foo'. Stop.", 512); + +# sv 62908. +# Test that when mkfifo fails, make switches to pipe and succeeds. +# Force mkfifo to fail by attempting to create a fifo in a non existent +# directory. +# run_make_test does not allow matching a multiline pattern, therefore run the +# test twice. +# First time look for /$ERR_no_such_file/ to ensure mkfifo failed. +# Second time look for /Nothing to be done/ to ensure make succeeded. +if (exists $FEATURES{'jobserver-fifo'}) { + $ENV{TMPDIR} = "nosuchdir"; + run_make_test("all:\n", '-j2', "/$ERR_no_such_file/"); + + $ENV{TMPDIR} = "nosuchdir"; + run_make_test(undef, '-j2', "/Nothing to be done/"); + + # Verify that MAKE_TMPDIR is preferred if provided + $ENV{MAKE_TMPDIR} = '.'; + $ENV{TMPDIR} = 'nosuchdir'; + + run_make_test(q! +recurse: ; @$(MAKE) -f #MAKEFILE# all +all:;@echo "$$MAKEFLAGS" +!, + "-j2 --no-print-directory", "/--jobserver-auth=fifo:\\./"); +} + +1; diff --git a/tests/scripts/features/load b/tests/scripts/features/load index fa4b86f..b462ed9 100644 --- a/tests/scripts/features/load +++ b/tests/scripts/features/load @@ -4,7 +4,7 @@ $description = "Test the load operator."; $details = "Test dynamic loading of modules."; # Don't do anything if this system doesn't support "load" -exists $FEATURES{load} or return -1; +exists $FEATURES{'load'} or return -1; my $cc = get_config('CC'); if (! $cc) { @@ -19,18 +19,22 @@ unlink(qw(testload.c testload.so)); open(my $F, '> testload.c') or die "open: testload.c: $!\n"; print $F <<'EOF' ; -#include <string.h> -#include <stdio.h> - #include "gnumake.h" +char* getenv (const char*); + int plugin_is_GPL_compatible; +int testload_gmk_setup (gmk_floc *); +int explicit_setup (gmk_floc *); + int testload_gmk_setup (gmk_floc *pos) { (void)pos; gmk_eval ("TESTLOAD = implicit", 0); + if (getenv("TESTAPI_KEEP")) + return -1; return 1; } @@ -39,6 +43,8 @@ explicit_setup (gmk_floc *pos) { (void)pos; gmk_eval ("TESTLOAD = explicit", 0); + if (getenv("TESTAPI_KEEP")) + return -1; return 1; } EOF @@ -46,14 +52,14 @@ close($F) or die "close: testload.c: $!\n"; # Make sure we can compile -my $cflags = get_config('CFLAGS'); -my $cppflags = get_config('CPPFLAGS'); -my $ldflags = get_config('LDFLAGS'); -my $sobuild = "$cc ".($srcdir? "-I$srcdir/src":'')." $cppflags $cflags -shared -fPIC $ldflags -o testload.so testload.c"; +my $cppflags = get_config('CPPFLAGS') . ($srcdir ? " -I$srcdir/src" : ''); +my $cflags = get_config('CFLAGS') . ' -fPIC'; +my $ldflags = get_config('LDFLAGS') . ' -shared'; +my $sobuild = "$cc $cppflags $cflags $ldflags -o testload.so testload.c"; my $clog = `$sobuild 2>&1`; if ($? != 0) { - $verbose and print "Failed to build testload.so:\n$sobuild\n$_"; + $verbose and print "Failed to build testload.so:\n$sobuild\n$clog"; return -1; } @@ -76,7 +82,7 @@ all: ; @echo pre=$(PRE) post=$(POST) $(TESTLOAD) !, '', "pre= post=testload.so explicit\n"); -# TEST 4 +# TEST 3 # Check multiple loads run_make_test(q! PRE := $(.LOADED) @@ -87,7 +93,7 @@ all: ; @echo pre=$(PRE) post=$(POST) $(TESTLOAD) !, '', "pre= post=testload.so implicit\n"); -# TEST 5 +# TEST 4 # Check auto-rebuild of loaded file that's out of date utouch(-10, 'testload.so'); touch('testload.c'); @@ -112,6 +118,32 @@ all: ; @echo pre=$(PRE) post=$(POST) $(TESTLOAD) %.so: %.c ; @echo "rebuilding $@"; !.$sobuild, '', "rebuilding testload.so\npre= post=testload.so explicit\n"); +# sv 63044. +# Test that the loaded shared object is present in .LOADED when the setup +# routine returns -1. +$ENV{TESTAPI_KEEP} = 1; +run_make_test(q! +PRE := $(.LOADED) +load testload.so +POST := $(.LOADED) +all: ; @echo pre=$(PRE) post=$(POST) $(TESTLOAD) +!, + '--warn-undefined-variables', "pre= post=testload.so implicit\n"); + +# Check that we don't auto-rebuild of loaded file that's out of date +# if we return -1 from the setup +utouch(-10, 'testload.so'); +touch('testload.c'); + +$ENV{TESTAPI_KEEP} = 1; +run_make_test(q! +PRE := $(.LOADED) +load ./testload.so +POST := $(.LOADED) +all: ; @echo pre=$(PRE) post=$(POST) $(TESTLOAD) +testload.so: testload.c ; @echo "rebuilding $@"; !.$sobuild, + '', "pre= post=testload.so implicit\n"); + unlink(qw(testload.c testload.so)) unless $keep; # This tells the test driver that the perl test script executed properly. diff --git a/tests/scripts/features/loadapi b/tests/scripts/features/loadapi index ba14928..a72f1f1 100644 --- a/tests/scripts/features/loadapi +++ b/tests/scripts/features/loadapi @@ -24,8 +24,12 @@ print $F <<'EOF' ; #include "gnumake.h" +char *getenv (const char*); + int plugin_is_GPL_compatible; +int testapi_gmk_setup (); + static char * test_eval (const char *buf) { @@ -67,12 +71,26 @@ func_test (const char *funcname, unsigned int argc, char **argv) } int -testapi_gmk_setup () +testapi_gmk_setup (const gmk_floc *floc) { + const char *verbose = getenv ("TESTAPI_VERBOSE"); + gmk_add_function ("test-expand", func_test, 1, 1, GMK_FUNC_DEFAULT); gmk_add_function ("test-noexpand", func_test, 1, 1, GMK_FUNC_NOEXPAND); gmk_add_function ("test-eval", func_test, 1, 1, GMK_FUNC_DEFAULT); gmk_add_function ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.", func_test, 0, 0, 0); + + if (verbose) + { + printf ("testapi_gmk_setup\n"); + + if (verbose[0] == '2') + printf ("%s:%lu\n", floc->filenm, floc->lineno); + } + + if (getenv ("TESTAPI_KEEP")) + return -1; + return 1; } EOF @@ -121,6 +139,89 @@ all:;@echo '$(test-noexpand $(TEST))' !, '', "\$(TEST)\n"); + +# During all subsequent tests testapi.so exists. +# +my @loads = ('', q! +load testapi.so +load testapi.so +-load testapi.so +-load testapi.so +$(eval load testapi.so) +$(eval -load testapi.so) +!); + +for my $extra_loads (@loads) { +my $n = 5; +if ($extra_loads) { + $n = 12; +} +# sv 63045. +# Test that having unloaded a shared object make loads it again, even if the +# shared object is not updated. +$ENV{TESTAPI_VERBOSE} = 1; +run_make_test(" +load testapi.so +$extra_loads +all:; \$(info \$(test-expand hello)) +testapi.so: force; \$(info \$@) +force:; +.PHONY: force +", '', "testapi_gmk_setup\ntestapi.so\ntestapi_gmk_setup\nhello\n#MAKE#: 'all' is up to date.\n"); + +# sv 63045. +# Same as above, but testapi_gmk_setup returned -1. +$ENV{TESTAPI_KEEP} = 1; +$ENV{TESTAPI_VERBOSE} = 1; +run_make_test(" +load testapi.so +$extra_loads +all:; \$(info \$(test-expand hello)) +testapi.so: force; \$(info \$@) +force:; +.PHONY: force +", '', "testapi_gmk_setup\nhello\n#MAKE#: 'all' is up to date.\n"); + +# sv 63045. +# Test that make exits, unless make can successfully update an unloaded shared +# object. +$ENV{TESTAPI_VERBOSE} = 1; +run_make_test(" +load testapi.so +$extra_loads +all:; \$(info \$(test-expand hello)) +testapi.so: force; @#HELPER# fail 1 +force:; +.PHONY: force +", '', "testapi_gmk_setup\nfail 1\n#MAKE#: *** [#MAKEFILE#:$n: testapi.so] Error 1\n", 512); + +# sv 63045. +# Same as above, but testapi_gmk_setup returned -1. +$ENV{TESTAPI_KEEP} = 1; +$ENV{TESTAPI_VERBOSE} = 1; +run_make_test(" +load testapi.so +$extra_loads +all:; \$(info \$(test-expand hello)) +testapi.so: force; @#HELPER# fail 1 +force:; +.PHONY: force +", '', "testapi_gmk_setup\nhello\n#MAKE#: 'all' is up to date.\n"); + +# sv 63100. +# Test that make supplies the correct floc when the shared object is loaded +# again. +$ENV{TESTAPI_VERBOSE} = 2; +run_make_test(" +load testapi.so +$extra_loads +all:; \$(info \$(test-expand hello)) +testapi.so: force; \$(info \$@) +force:; +.PHONY: force +", '', "testapi_gmk_setup\n#MAKEFILE#:2\ntestapi.so\ntestapi_gmk_setup\n#MAKEFILE#:2\nhello\n#MAKE#: 'all' is up to date.\n"); +} + unlink(qw(testapi.c testapi.so)) unless $keep; # This tells the test driver that the perl test script executed properly. diff --git a/tests/scripts/features/mult_rules b/tests/scripts/features/mult_rules index e706e17..bddd501 100644 --- a/tests/scripts/features/mult_rules +++ b/tests/scripts/features/mult_rules @@ -69,10 +69,20 @@ $answer = "EXTRA EXTRA\n"; unlink("defs.h","test.h","config.h","extra.h"); -1; - - - - - +# sv 62650. +# Test the message that make prints when a file found by directory search +# is preferred over the local one. +run_make_test(q! +vpath hello.c src +all: hello.c; $(info $@ from $^) +hello.c: ; $(info 1 $@) +src/hello.c: ; $(info 2 $@) +!, '', + "#MAKEFILE#:4: Recipe was specified for file 'hello.c' at #MAKEFILE#:4, +#MAKEFILE#:4: but 'hello.c' is now considered the same file as 'src/hello.c'. +#MAKEFILE#:4: Recipe for 'hello.c' will be ignored in favor of the one for 'src/hello.c'. +2 src/hello.c +all from src/hello.c +#MAKE#: 'all' is up to date.\n"); +1; diff --git a/tests/scripts/features/output-sync b/tests/scripts/features/output-sync index 1d09174..13a54ca 100644 --- a/tests/scripts/features/output-sync +++ b/tests/scripts/features/output-sync @@ -116,20 +116,24 @@ EOF close(MAKEFILE); # Test per-make 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: ; \$(MAKE) -C bar!, +make-bar: ; #HELPER# -q sleep 1 ; \$(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 +#HELPER# -q sleep 1 ; #MAKEPATH# -C bar #MAKE#[1]: Entering directory '#PWD#/bar' bar: start bar: end @@ -338,5 +342,30 @@ all:: ; @./foo bar baz '-O', "#MAKE#: ./foo: $ERR_no_such_file\n#MAKE#: *** [#MAKEFILE#:2: all] Error 127\n", 512); } +if ($port_type eq 'UNIX') { +# POSIX doesn't require sh to set PPID so test this +my $cmd = create_command(); +add_options($cmd, '-f', '/dev/null', '-E', q!all:;@echo $$PPID!); +my $fout = 'ppidtest.out'; +run_command_with_output($fout, @$cmd); +$_ = read_file_into_string($fout); +chomp($_); +if (/^[0-9]+$/) { +use POSIX (); +# SV 63157. +# Test that make removes temporary files, even when a signal is received. +# The general test_driver postprocessing will ensure the temporary file used +# to synchronize output and the jobserver fifo are both removed. +# sleep is needed to let make write its "... Terminated" message to the log +# file. +run_make_test(q! +pid:=$(shell echo $$PPID) +all:; @kill -TERM $(pid) && sleep 16 +!, '-O -j2', '/#MAKE#: \*\*\* \[#MAKEFILE#:3: all] Terminated/', POSIX::SIGTERM); +} + +unlink($fout); +} + # This tells the test driver that the perl test script executed properly. 1; diff --git a/tests/scripts/features/parallelism b/tests/scripts/features/parallelism index 08f94a6..98ee8a3 100644 --- a/tests/scripts/features/parallelism +++ b/tests/scripts/features/parallelism @@ -7,46 +7,47 @@ if (!$parallel_jobs) { return -1; } -run_make_test(" +run_make_test(q! all : def_1 def_2 def_3 -def_1 : ; \@#HELPER# file ONE wait THREE out TWO -def_2 : ; \@#HELPER# wait FOUR file THREE -def_3 : ; \@#HELPER# wait ONE file FOUR", +def_1 : ; @#HELPER# file ONE wait THREE out TWO +def_2 : ; @#HELPER# wait FOUR file THREE +def_3 : ; @#HELPER# wait ONE file FOUR!, '-j4', "file ONE\nwait ONE\nfile FOUR\nwait FOUR\nfile THREE\nwait THREE\nTWO"); rmfiles(qw(ONE TWO THREE FOUR)); # Verify -j added to MAKEFLAGS in the makefile -run_make_test(" +run_make_test(q! MAKEFLAGS += -j4 all : def_1 def_2 def_3 -def_1 : ; \@#HELPER# file ONE wait THREE out TWO -def_2 : ; \@#HELPER# wait FOUR file THREE -def_3 : ; \@#HELPER# wait ONE file FOUR", +def_1 : ; @#HELPER# file ONE wait THREE out TWO +def_2 : ; @#HELPER# wait FOUR file THREE +def_3 : ; @#HELPER# wait ONE file FOUR!, '', "file ONE\nwait ONE\nfile FOUR\nwait FOUR\nfile THREE\nwait THREE\nTWO"); rmfiles(qw(ONE TWO THREE FOUR)); # Command line should take precedence -run_make_test(" +run_make_test(q! MAKEFLAGS += -j2 all : def_1 def_2 def_3 -def_1 : ; \@#HELPER# file ONE wait THREE out TWO -def_2 : ; \@#HELPER# wait FOUR file THREE -def_3 : ; \@#HELPER# wait ONE file FOUR", +def_1 : ; @#HELPER# file ONE wait THREE out TWO +def_2 : ; @#HELPER# wait FOUR file THREE +def_3 : ; @#HELPER# wait ONE file FOUR!, '-j4', "file ONE\nwait ONE\nfile FOUR\nwait FOUR\nfile THREE\nwait THREE\nTWO"); rmfiles(qw(ONE TWO THREE FOUR)); # Test parallelism with included files. Here we sleep/echo while # building the included files, to test that they are being built in # parallel. -run_make_test(" -all: 1 2; \@#HELPER# out success +run_make_test(q! +all: 1 2; @#HELPER# out success -include 1.inc 2.inc +.RECIPEPREFIX := > 1.inc: -\t\@#HELPER# file ONE.inc wait THREE.inc file TWO.inc -\t\@echo '1: ; \@#HELPER# file ONE wait THREE file TWO' > \$\@ +> @#HELPER# file ONE.inc wait THREE.inc file TWO.inc +> @echo '1: ; @#HELPER# file ONE wait THREE file TWO' > $@ 2.inc: -\t\@#HELPER# wait ONE.inc file THREE.inc -\t\@echo '2: ; \@#HELPER# wait ONE file THREE' > \$\@", +> @#HELPER# wait ONE.inc file THREE.inc +> @echo '2: ; @#HELPER# wait ONE file THREE' > $@!, "-j4", "file ONE.inc\nwait ONE.inc\nfile THREE.inc\nwait THREE.inc\nfile TWO.inc\nfile ONE\nwait ONE\nfile THREE\nwait THREE\nfile TWO\nsuccess\n", 0, 7); rmfiles(qw(ONE.inc TWO.inc THREE.inc ONE TWO THREE 1.inc 2.inc)); @@ -54,17 +55,17 @@ rmfiles(qw(ONE.inc TWO.inc THREE.inc ONE TWO THREE 1.inc 2.inc)); # Test parallelism with included files--this time recurse first and make # sure the jobserver works. -run_make_test(" -recurse: ; \@\$(MAKE) --no-print-directory -f #MAKEFILE# INC=yes all -all: 1 2; \@#HELPER# out success +run_make_test(q! +recurse: ; @$(MAKE) --no-print-directory -f #MAKEFILE# INC=yes all +all: 1 2; @#HELPER# out success INC = no -ifeq (\$(INC),yes) +ifeq ($(INC),yes) -include 1.inc 2.inc endif -1.inc: ; \@#HELPER# file ONE.inc wait THREE.inc file TWO.inc; echo '1: ; \@#HELPER# file ONE wait THREE file TWO' > \$\@ -2.inc: ; \@#HELPER# wait ONE.inc file THREE.inc; echo '2: ; \@#HELPER# wait ONE file THREE' > \$\@", +1.inc: ; @#HELPER# file ONE.inc wait THREE.inc file TWO.inc; echo '1: ; @#HELPER# file ONE wait THREE file TWO' > $@ +2.inc: ; @#HELPER# wait ONE.inc file THREE.inc; echo '2: ; @#HELPER# wait ONE file THREE' > $@!, "-j4", "file ONE.inc\nwait ONE.inc\nfile THREE.inc\nwait THREE.inc\nfile TWO.inc\nfile ONE\nwait ONE\nfile THREE\nwait THREE\nfile TWO\nsuccess\n", 0, 7); rmfiles(qw(ONE.inc TWO.inc THREE.inc ONE TWO THREE 1.inc 2.inc)); @@ -74,47 +75,42 @@ rmfiles(qw(ONE.inc TWO.inc THREE.inc ONE TWO THREE 1.inc 2.inc)); # function in an exported recursive variable. I added some code to check # for this situation and print a message if it occurred. This test used # to trigger this code when I added it but no longer does after the fix. -# We have to increase the timeout from the default (5s) on this test. -run_make_test(" -export HI = \$(shell \$(\$\@.CMD)) +run_make_test(q! +export HI = $(shell $($@.CMD)) first.CMD = #HELPER# out hi second.CMD = #HELPER# sleep 4 .PHONY: all first second all: first second -first second: ; \@#HELPER# out \$\@ sleep 1 out \$\@", - '-j2', "first\nsleep 1\nfirst\nsecond\nsleep 1\nsecond", 0, 7); +first second: ; @#HELPER# out $@ sleep 1 out $@!, + '-j2', "first\nsleep 1\nfirst\nsecond\nsleep 1\nsecond", 0); # Michael Matz <matz@suse.de> reported a bug where if make is running in # parallel without -k and two jobs die in a row, but not too close to each # other, then make will quit without waiting for the rest of the jobs to die. -run_make_test(" +run_make_test(q! .PHONY: all fail.1 fail.2 fail.3 ok all: fail.1 ok fail.2 fail.3 -.RECIPEPREFIX := > - -fail.1 fail.2 fail.3: -> \@#HELPER# sleep \$(patsubst fail.%,%,\$\@) -> \@#HELPER# out Fail -> \@#HELPER# fail 1 +fail.1: ; @#HELPER# -q sleep 1 out $@ file fail.1 fail 1 +fail.2: ; @#HELPER# -q sleep 2 out $@ wait fail.1 file fail.2 fail 1 +fail.3: ; @#HELPER# -q sleep 3 out $@ wait fail.2 file fail.3 fail 1 -ok: -> \@#HELPER# sleep 4 -> \@#HELPER# out OK", - '-rR -j5', "sleep 1\nFail\nfail 1 -#MAKE#: *** [#MAKEFILE#:10: fail.1] Error 1 +ok: ; @#HELPER# -q sleep 4 wait fail.3 out OK!, + '-rR -j5', "fail.1\nfail 1 +#MAKE#: *** [#MAKEFILE#:5: fail.1] Error 1 #MAKE#: *** Waiting for unfinished jobs.... -sleep 2\nFail\nfail 1 -#MAKE#: *** [#MAKEFILE#:10: fail.2] Error 1 -sleep 3\nFail\nfail 1 -#MAKE#: *** [#MAKEFILE#:10: fail.3] Error 1 -sleep 4\nOK", +fail.2\nfail 1 +#MAKE#: *** [#MAKEFILE#:6: fail.2] Error 1 +fail.3\nfail 1 +#MAKE#: *** [#MAKEFILE#:7: fail.3] Error 1 +OK", 512); +rmfiles(qw(fail.1 fail.2 fail.3)); # Test for Savannah bug #15641. # @@ -148,7 +144,7 @@ rmfiles('target'); # TEST #11: Make sure -jN from MAKEFLAGS is processed even when we re-exec # See Savannah bug #33873 -$extraENV{MAKEFLAGS} = '-j4'; +$ENV{MAKEFLAGS} = '-j4'; run_make_test(q! things = thing1 thing2 @@ -160,7 +156,6 @@ inc.mk: ; @touch $@ !, '', "file thing2start\nwait thing2start\nfile thing1start\nwait thing1start\nfile thing2end\nwait thing2end\nthing1end\n"); -delete $extraENV{MAKEFLAGS}; rmfiles(qw(inc.mk thing1start thing1end thing2start thing2end)); # Ensure intermediate/secondary files are not pruned incorrectly. @@ -191,7 +186,7 @@ fff1.mk: ; touch $@ !, '-j2', "touch fff1.mk\nfile TWO\nwait TWO\nfile ONE\n"); -unlink('fff1.mk', 'ONE', 'TWO'); +rmfiles('fff1.mk', 'ONE', 'TWO'); # Test if a sub-make needs to re-exec and the makefile is built via # sub-make. Reported by Masahiro Yamada <yamada.masahiro@socionext.com> @@ -212,7 +207,7 @@ endif !, '--no-print-directory -j2', "touch fff1.mk\nfile TWO\nwait TWO\nfile ONE\nrecurse\n"); -unlink('fff1.mk', 'ONE', 'TWO'); +rmfiles('fff1.mk', 'ONE', 'TWO'); # Make sure that all jobserver FDs are closed if we need to re-exec the diff --git a/tests/scripts/features/patternrules b/tests/scripts/features/patternrules index 6510c38..0b35408 100644 --- a/tests/scripts/features/patternrules +++ b/tests/scripts/features/patternrules @@ -18,32 +18,32 @@ $dir =~ s,.*/([^/]+)$,../$1,; run_make_test(q! .PHONY: all -all: case.1 case.2 case.3 +all: case.1 case.2 case.3 case.4 # We can't have this, due to "Implicit Rule Search Algorithm" step 5c #xxx: void # 1 - existing file -%.1: void - @exit 1 -%.1: #MAKEFILE# - @exit 0 +%.1: void ; @exit 1 +%.1: #MAKEFILE# ; @exit 0 # 2 - phony -%.2: void - @exit 1 -%.2: 2.phony - @exit 0 +%.2: void ; @exit 1 +%.2: 2.phony ; @exit 0 .PHONY: 2.phony # 3 - implicit-phony -%.3: void - @exit 1 -%.3: 3.implicit-phony - @exit 0 +%.3: void ; @exit 1 +%.3: 3.implicit-phony ; @exit 0 3.implicit-phony: -!, '', ''); + +# 4 - explicitly mentioned file made by an implicit rule +%.4: void ; @exit 1 +%.4: test.x ; @exit 0 +%.x: ; +!, + '', ''); # TEST #1: make sure files that are built via implicit rules are marked # as targets (Savannah bug #12202). @@ -55,18 +55,14 @@ TARGETS := foo foo.out all: $(TARGETS) -%: %.in - @echo $@ +%: %.in ; @echo $@ -%.out: % - @echo $@ +%.out: % ; @echo $@ foo.in: ; @: ', -'', -'foo -foo.out'); + '', "foo\nfoo.out"); # TEST #2: make sure intermediate files that also happened to be @@ -75,23 +71,17 @@ foo.out'); run_make_test(' $(dir)/foo.o: -$(dir)/foo.y: - @echo $@ +$(dir)/foo.y: ; @echo $@ -%.c: %.y - touch $@ +%.c: %.y ; touch $@ -%.o: %.c - @echo $@ +%.o: %.c ; @echo $@ .PHONY: install install: $(dir)/foo.c ', -"dir=$dir", -"$dir/foo.y -touch $dir/foo.c -$dir/foo.o"); + "dir=$dir", "$dir/foo.y\ntouch $dir/foo.c\n$dir/foo.o"); unlink("$dir/foo.c"); @@ -109,9 +99,8 @@ run_make_test(' $(dir)/foo.bar: ', -"dir=$dir", -"#MAKE#: *** [#MAKEFILE#:6: $dir/foo.bar] Error 1", -512); + "dir=$dir", + "#MAKE#: *** [#MAKEFILE#:6: $dir/foo.bar] Error 1", 512); unlink("$dir/foo.bar"); @@ -123,25 +112,16 @@ run_make_test(' .PHONY: all all: foo.c foo.o -%.h %.c: %.in - touch $*.h - touch $*.c +%.h %.c: %.in ; touch $*.h ; touch $*.c -%.o: %.c %.h - echo $+ >$@ +%.o: %.c %.h ; echo $+ >$@ -%.o: %.c - @echo wrong rule +%.o: %.c ; @echo wrong rule -foo.in: - touch $@ +foo.in: ; touch $@ ', -'', -'touch foo.in -touch foo.h -touch foo.c -echo foo.c foo.h >foo.o'); + '', "touch foo.in\ntouch foo.h ; touch foo.c\necho foo.c foo.h >foo.o\nrm foo.h"); unlink('foo.in', 'foo.h', 'foo.c', 'foo.o'); @@ -151,10 +131,8 @@ unlink('foo.in', 'foo.h', 'foo.c', 'foo.o'); run_make_test(' all: foo.s1 foo.s2 p1.foo p2.foo -p1.% p2.%: %.orig - @echo $@ -%.s1 %.s2: %.orig - @echo $@ +p1.% p2.%: %.orig ; @echo $@ +%.s1 %.s2: %.orig ; @echo $@ .PHONY: foo.orig ', @@ -215,16 +193,14 @@ run_make_test(' all: foo.x foo-mt.x ', -'', -"one\ntwo"); - -1; + '', "one\ntwo"); # Test pattern rules building the same targets -# See SV 54233. Rely on our standard test timeout to break the loop +# See SV 54233. touch('a.c'); +# a.lnk isn't listed as removed, because it's not actually created run_make_test(q! all: a.elf a.dbg @@ -234,19 +210,467 @@ all: a.elf a.dbg !, '-j2', ": a.elf a.lnk\n: a.elf a.dbg\n"); -unlink('a.c'); +# SV 60435 : a.lnk is removed, because it is intermediate. +run_make_test(q! +all: a.elf a.dbg + +%.elf %.lnk: %.c ; touch $*.elf $*.lnk + +%.elf %.dbg: %.lnk ; touch $*.elf $*.dbg +!, + '-j2', "touch a.elf a.lnk\ntouch a.elf a.dbg\nrm a.lnk\n"); + +unlink('a.elf', 'a.dbg'); + +# SV 60435 : a.lnk is not intermediate, because it is explicitly mentioned. +run_make_test(q! +all: a.elf a.dbg + +%.elf %.lnk: %.c ; touch $*.elf $*.lnk + +%.elf %.dbg: %.lnk ; touch $*.elf $*.dbg + +install: a.lnk +.PHONY: install +!, + '-j2', "touch a.elf a.lnk\ntouch a.elf a.dbg\n"); + +unlink('a.c', 'a.elf', 'a.dbg', 'a.lnk'); # SV 56655: Test patterns matching files containing whitespace touch('some file.yy'); run_make_test(q! %.xx : %.yy ; @echo matched -!, '"some file.xx"', "matched\n"); +!, + '"some file.xx"', "matched\n"); unlink('some file.xx', 'some file.yy'); + +# sv 60188. +# Test that a file explicitly mentioned by the user and made by an implicit +# rule is not considered intermediate. + +touch('hello.z'); +unlink('hello.x', 'test.x'); + +# subtest 1 +# hello.x is not explicitly mentioned and thus is an intermediate file. +run_make_test(q! +all: hello.z +%.z: %.x ; touch $@ +%.x: ; +!, + '', "#MAKE#: Nothing to be done for 'all'.\n"); + +# subtest 2 +# test.x is explicitly mentioned and thus is not an intermediate file. +run_make_test(q! +all: hello.z +%.z: %.x test.x ; touch $@ +%.x: ; +!, + '', "touch hello.z"); + +# subtest 3 +# hello.x is explicitly mentioned on an unrelated rule and thus is not an +# intermediate file. +touch('hello.z'); +run_make_test(q! +all: hello.z +%.z: %.x; touch $@ +%.x: ; +unrelated: hello.x +!, + '', "touch hello.z"); + +unlink('hello.z'); + +# sv 60188. +# Test that a file explicitly mentioned by the user and made by an implicit +# rule is not considered intermediate, even when the builtin rules are used. + +touch('hello.x'); +touch('test.x'); +touch('hello.tsk'); + +# subtest 1 +# hello.o is not explicitly mentioned and thus is an intermediate file. +run_make_test(q! +all: hello.tsk +%.tsk: %.z ; @echo $@ +%.z : %.x ; @echo $@ +!, + '', "#MAKE#: Nothing to be done for 'all'.\n"); + +# subtest 2 +# test.z is explicitly mentioned and thus is not an intermediate file. +# test.z is built first because until it's built we don't know if we +# need to rebuild the intermediate hello.z +run_make_test(q! +all: hello.tsk +%.tsk: %.z test.z ; @echo $@ +%.z : %.x ; @echo $@ +!, + '', "test.z\nhello.z\nhello.tsk\n"); + +# subtest 3 +# hello.o is not explicitly mentioned and thus is an intermediate file. +run_make_test(q! +all: hello.tsk +dep:=%.o +%.tsk: $(dep) ; @echo $@ +!, + '', "#MAKE#: Nothing to be done for 'all'.\n"); + +# subtest 4 +# Even when test.z is constructed from 2 variables it is still explicitly +# mentioned and thus is not an intermediate file. +# test.z is built first because until it's built we don't know if we +# need to rebuild the intermediate hello.z +run_make_test(q! +all: hello.tsk +name:=test +suf:=.z +%.tsk: %.z $(name)$(suf) ; @echo $@ +%.z: %.x ; @echo $@ +!, + '', "test.z\nhello.z\nhello.tsk\n"); + +unlink('hello.x', 'test.x', 'hello.tsk'); + +# Test that chained pattern rules with multiple targets remove all intermediate +# files. +# sv 60435. + +# subtest 1. +# a.1 and a.2 are intermediate and should be removed. + +run_make_test(q! +a.4: +%.4: %.1 %.15 ; cat $^ >$@ +%.1 %.15: ; touch $*.1 $*.15 +!, + '', "touch a.1 a.15\ncat a.1 a.15 >a.4\nrm a.15 a.1"); + +unlink('a.4'); + +# subtest 2. +# a.1 and a.2 are intermediate and should be removed. +# a.3 is explicit and should not be removed. +run_make_test(q! +a.4: +%.4: %.1 %.15 a.3 ; cat $^ >$@ +%.1 %.15: ; touch $*.1 $*.15 +%.3: ; touch $@ +!, + '', "touch a.3\ntouch a.1 a.15\ncat a.1 a.15 a.3 >a.4\nrm a.15 a.1"); + +unlink('a.3', 'a.4'); + +# subtest 3. +# a.1 and a.2 are intermediate and should be removed. +# a.3 is explicit and should not be removed. +run_make_test(q! +a.4: +%.4: %.1 %.15 a.3 ; cat $^ >$@ +%.1 %.15 %.3: ; touch $*.1 $*.15 $*.3 +!, + '', "touch a.1 a.15 a.3\ncat a.1 a.15 a.3 >a.4\nrm a.15 a.1"); + +unlink('a.3', 'a.4'); + +# subtest 4. +# a.1 and a.2 are intermediate and should be removed. +# a.3 is explicit and should not be removed. +run_make_test(q! +a.4: +%.4: %.1 %.15 a.3 ; cat $^ >$@ +%.3 %.1 %.15: ; touch $*.1 $*.15 $*.3 +!, + '', "touch a.1 a.15 a.3\ncat a.1 a.15 a.3 >a.4\nrm a.15 a.1"); + +unlink('a.3', 'a.4'); + +# subtest 5. +# a.1 and a.2 are intermediate and should be removed. +# a.3 is explicit and should not be removed. +run_make_test(q! +a.4: +%.4: a.3 %.1 %.15 ; cat $^ >$@ +%.1 %.15 %.3: ; touch $*.1 $*.15 $*.3 +!, + '', "touch a.1 a.15 a.3\ncat a.3 a.1 a.15 >a.4\nrm a.15 a.1"); + +unlink('a.3', 'a.4'); + +# subtest 6. +# a.2 is intermediate and should be removed. +# a.1 is mentioned explicitly on an unrelated rule and should not be removed. +run_make_test(q! +a.3: +%.3: %.1 %.2 ; cat $^ >$@ +%.1 %.2: ; touch $*.1 $*.2 +install: a.1 +.PHONY: install +!, + '', "touch a.1 a.2\ncat a.1 a.2 >a.3\nrm a.2"); + +unlink('a.1', 'a.3'); + +# Test removal of intermediate files. + +# subtest 1. +# hello.x is removed, because it is intermediate. +run_make_test(q! +hello.tsk: +%.tsk: %.x; touch $@ +%.x: ; touch $@ +!, + '', "touch hello.x\ntouch hello.tsk\nrm hello.x"); + +unlink('hello.tsk'); + +# subtest 2. +# Even though hello.x is intermediate, it is not removed, because it is not +# created. +touch('hello.x'); + +run_make_test(q! +hello.tsk: +%.tsk: %.x; touch $@ +%.x: ; touch $@ +!, + '', "touch hello.tsk"); + +unlink('hello.x', 'hello.tsk'); + +# subtest 2. +# Even though hello.x is intermediate, it is not removed, because it is not +# created. +run_make_test(q! +hello.tsk: +%.tsk: %.x; touch $@ +%.x: ; : $@ +!, + '', ": hello.x\ntouch hello.tsk"); + +unlink('hello.tsk'); + +# A target explicitly listed as a prerequisite of a pattern rule, is still +# considered mentioned and "ought to exist". + +run_make_test(q! +1.all: 1.q ; touch $@ +%.q: 1.r ; touch $@ +%.r: ; touch $@ +!, + '', "touch 1.r\ntouch 1.q\ntouch 1.all\n"); + +unlink('1.all', '1.q', '1.r'); + +# SV 63098: Verify that missing also_made in pattern rules gives a warning but +# doesn't fail. + +run_make_test(q! +%a %b : ; touch $*a +!, + 'gta', "touch gta\n#MAKEFILE#:2: warning: pattern recipe did not update peer target 'gtb'.\n"); +unlink(qw(gta)); + +# We don't warn if we didn't update the file +utouch(-10, qw(gta)); +run_make_test(q! +%a %b : xyzzy ; $(OP) +xyzzy: ; +ifdef RUN +OP = @echo no +endif +!, + '-rR gta', "#MAKE#: 'gta' is up to date.\n"); + +run_make_test(undef, '-rR gta RUN=1', "no\n"); +unlink(qw(gta)); + +run_make_test(q! +all:; +include gta +%a %b : ; touch $*a +!, + '', "touch gta\n#MAKEFILE#:4: warning: pattern recipe did not update peer target 'gtb'.\n#MAKE#: 'all' is up to date."); +unlink(qw(gta)); + +run_make_test(q! +%.c %.h : %.y; touch $*.c +%.o: %.c; touch $@ +foo.y: ; touch $@ +!, + 'foo.o', "touch foo.y\ntouch foo.c\n#MAKEFILE#:2: warning: pattern recipe did not update peer target 'foo.h'.\ntouch foo.o\nrm foo.c"); +unlink(qw(foo.y foo.c foo.o)); + +if (0) { +# SV 12078: Missing grouped pattern peer causes remake regardless of which +# target caused the rule to run. +touch(qw(gta)); # but not gtb +run_make_test(q! +%a %b : ; touch $*a $*b +!, + 'gta', "touch gta gtb\n"); +unlink(qw(gta gtb)); + +# Ensure both goal targets are built if they depend on a grouped pattern +touch(qw(gta)); # but not gtb +run_make_test(q! +x y: ; touch $@ + +x: gta +y: gtb + +%a %b : ; touch $*a $*b +!, + 'x y', "touch gta gtb\ntouch x\ntouch y\n"); + +# Now everything should be up to date +run_make_test(undef, 'x y', + "#MAKE#: 'x' is up to date.\n#MAKE#: 'y' is up to date."); + +unlink(qw(x y gta gtb)); + +# sv 12078 : make sure we notice when all targets need to be rebuilt +# a.1st exists but b.1st doesn't: make sure a.2nd is out of date as well + +utouch(-20, 'a.1st'); +utouch(-10, 'a.2nd', 'b.2nd'); + +run_make_test(q! +1st := a.1st b.1st +2nd := ${1st:.1st=.2nd} +.PHONY: all +all: ${2nd} +a.% b.% : ; touch a.$* b.$* +${2nd}: %.2nd: %.1st ; cp $< $@ +! + , '', "touch a.1st b.1st\ncp a.1st a.2nd\ncp b.1st b.2nd\n"); + +unlink(qw(a.1st b.1st a.2nd b.2nd)); + +# Variation: b.1st exists but is newer + +utouch(-20, 'a.1st'); +utouch(-10, 'a.2nd', 'b.2nd'); +touch(qw(b.1st)); + +run_make_test(undef, '', "cp b.1st b.2nd\n"); + +unlink(qw(a.1st b.1st a.2nd b.2nd)); +} + +# sv 62206. + +# The following combinations are generated with and without second expansion. +# 1. +# all: bye.x +# %.x: ... +# +# 2. +# all: lib/bye.x +# %.x: ... +# +# 3. +# all: lib/bye.x +# lib/%.x: ... +# +# The following combination is not generated, because there is no rule to +# build bye.x, no stem substitution takes place, not of interest of this test. +# 4. +# all: bye.x +# lib/%.x: ... + +my @dir = ('', 'lib/'); # With and without last slash. +my @secondexpansion = ('', '.SECONDEXPANSION:'); + +for my $se (@secondexpansion) { +for my $d (@dir) { # The directory of the prerequisite of 'all'. +for my $r (@dir) { # The directory of the target in the rule definition. +(!$d && $r) && next; # Combination 4. +my $dollar = $se ? '$' : ''; + +# The prerequisite should only have directory if the prerequisite of 'all' has +# it and if the prequisite pattern in the rule definition does not have it. +# That is combination 2. +my $pdir = $d && !$r ? $d : ''; + +my $prereqs = "${pdir}bye.1"; + +# One func, one %. +run_make_test(" +$se +all: ${d}bye.x +$r%.x: $dollar\$(firstword %.1); \$(info \$@ from \$^) +.PHONY: $prereqs +", '', "${d}bye.x from $prereqs\n#MAKE#: Nothing to be done for 'all'.\n"); + +$prereqs = "${pdir}bye.1 ${pdir}bye.2"; + +# Multiple funcs, each has one %. +run_make_test(" +$se +all: ${d}bye.x +$r%.x: $dollar\$(firstword %.1) $dollar\$(firstword %.2); \$(info \$@ from \$^) +.PHONY: $prereqs +", '', "${d}bye.x from $prereqs\n#MAKE#: Nothing to be done for 'all'.\n"); + +$prereqs = "${pdir}bye.1 ${pdir}bye.2 ${pdir}bye.3 ${pdir}bye.4"; + +# Multiple funcs, each has multiple %. +run_make_test(" +$se +all: ${d}bye.x +$r%.x: $dollar\$(wordlist 1, 99, %.1 %.2) $dollar\$(wordlist 1, 99, %.3 %.4); \$(info \$@ from \$^) +.PHONY: $prereqs +", '', "${d}bye.x from $prereqs\n#MAKE#: Nothing to be done for 'all'.\n"); + +$prereqs = "${pdir}bye.1 ${pdir}bye.2 ${pdir}bye.3 ${pdir}bye.4"; + +# Nested functions. +run_make_test(" +$se +all: ${d}bye.x +$r%.x: $dollar\$(wordlist 1, 99, $dollar\$(wordlist 1, 99, %.1 %.2)) $dollar\$(wordlist 1, 99, $dollar\$(wordlist 1,99, %.3 %.4)); \$(info \$@ from \$^) +.PHONY: $prereqs +", '', "${d}bye.x from $prereqs\n#MAKE#: Nothing to be done for 'all'.\n"); + +$prereqs = "${pdir}bye1%2% ${pdir}bye ${pdir}3bye4%5 ${pdir}6bye ${pdir}bye7%8 ${pdir}bye9 ${pdir}bye10% ${pdir}11bye12 13"; + +# Multiple funcs, each has multiple words, each word has multiple %, sole %, +# various corner cases. +# Make should substitute the first % and only the first % in each word with the +# stem. +run_make_test(" +$se +all: ${d}bye.x +$r%.x: $dollar\$(wordlist 1, 99, %1%2% % 3%4%5 6%) %7%8 %9 $dollar\$(wordlist 1, 99, %10% 11%12) 13; \$(info \$@ from \$^) +.PHONY: $prereqs +", '', "${d}bye.x from $prereqs\n#MAKE#: Nothing to be done for 'all'.\n"); + +if ($port_type eq 'UNIX') { +# Test that make does not use some hardcoded array of a finite size on stack. +# Long prerequisite name. This prerequisite name is over 66K long. +my $prefix = 'abcdefgh' x 128 x 33; # 33K long. +my $suffix = 'stuvwxyz' x 128 x 33; # 33K long. +$prereqs = "${pdir}${prefix}bye${suffix}.1 ${pdir}${prefix}bye${suffix}.2"; + +run_make_test(" +$se +all: ${d}bye.x +$r%.x: $dollar\$(wordlist 1, 99, ${prefix}%${suffix}.1 ${prefix}%${suffix}.2); \$(info \$@ from \$^) +.PHONY: $prereqs +", '', "${d}bye.x from $prereqs\n#MAKE#: Nothing to be done for 'all'.\n"); +} + +} +} +} + # This tells the test driver that the perl test script executed properly. 1; - -### Local Variables: -### eval: (setq whitespace-action (delq 'auto-cleanup whitespace-action)) -### End: diff --git a/tests/scripts/features/reinvoke b/tests/scripts/features/reinvoke index d2a1f50..07cbbfb 100644 --- a/tests/scripts/features/reinvoke +++ b/tests/scripts/features/reinvoke @@ -17,9 +17,7 @@ $omkfile = $makefile; run_make_test(' all: ; @echo running rules. -#MAKEFILE# incl.mk: incl-1.mk - @echo rebuilding $@ - @echo >> $@ +#MAKEFILE# incl.mk: incl-1.mk ; @echo rebuilding $@; echo >> $@ include incl.mk', '', "rebuilding incl.mk\nrunning rules.\n"); @@ -45,17 +43,17 @@ all: ; @echo hello a : b ; echo >> $@ -b : c ; [ -f $@ ] || echo >> $@ +b : c ; test -f $@ || echo >> $@ c: ; echo >> $@ include $(F)', - 'F=a', "[ -f b ] || echo >> b\nhello\n"); + 'F=a', "test -f b || echo >> b\nhello\n"); # Now try with the file we're not updating being the actual file we're # including: this and the previous one test different parts of the code. -run_make_test(undef, 'F=b', "[ -f b ] || echo >> b\nhello\n"); +run_make_test(undef, 'F=b', "test -f b || echo >> b\nhello\n"); &rmfiles('a','b','c'); @@ -74,9 +72,109 @@ foo30723: ; @touch $@ unlink('foo30723'); +# If ANY makefile is rebuilt then we should re-exec + +run_make_test(' +all: ; @echo RESTARTS=$(MAKE_RESTARTS) + +m1.d: ; @echo $@; touch $@ + +m2.d: m1.d ; @test -f $< || { echo $@; touch $@; } + +include m1.d +-include m2.d +', + '', "m1.d\nRESTARTS=1\n"); + +unlink('m1.d', 'm2.d'); + +# Same as before but be sure we get error messages for un-created makefiles +run_make_test(' +all: ; @echo RESTARTS=$(MAKE_RESTARTS) + +m1.d: ; @echo $@; touch $@ + +m2.d: m1.d ; @test -f $< || { echo $@; touch $@; } + +include m1.d m2.d +', '', + # This runs afoul of https://savannah.gnu.org/bugs/?61226 + 0 ? "m1.d\n#MAKEFILE#:8: m2.d: $ERR_no_such_file" + : "m1.d\nRESTARTS=1", + 0 ? 512 : 0); + +unlink('m1.d', 'm2.d'); + +# sv 61226. +# This set of four cases tests two aspects of make. +# +# 1. If a rule has no prerequisites or recipe, and the target of the rule is a +# nonexistent file, then make imagines this target to have been updated +# whenever its rule is run. +# +# 2. Make does not re-execute itself in this case of imagined target. +# +# Test case 1. +# Make imagines hello.d was updated by a rule without recipe and without +# prereqs. +# This should succeed. +# Make should not re-execute itself. +run_make_test(' +hello.o: hello.d; $(info RESTARTS=$(MAKE_RESTARTS)) +hello.d: +include hello.d +', '', "RESTARTS=\n#MAKE#: 'hello.o' is up to date."); + +# Test case 2. +# Make imagines hello.d was updated by a rule with a recipe and without +# prereqs. +# This should succeed. +# Make should not re-execute itself. +run_make_test(' +hello.o: hello.d; $(info RESTARTS=$(MAKE_RESTARTS)) +hello.d:; $(info $@) +include hello.d +', '', "hello.d\nRESTARTS=\n#MAKE#: 'hello.o' is up to date."); + +&touch('hello.td'); +# Test case 3. +# Make imagines hello.d was updated by a rule without a recipe and with +# prereqs. +# This should succeed. +# Make should not re-execute itself. +run_make_test(' +hello.o: hello.d; $(info RESTARTS=$(MAKE_RESTARTS)) +hello.d: hello.td +include hello.d +', '', "RESTARTS=\n#MAKE#: 'hello.o' is up to date."); + +# Test case 4. +# Same test as three tests above, but the rule has both recipe and prereqs. +# Make should report this error. +run_make_test(' +hello.o: hello.d; $(info $@) +hello.d: hello.td; $(info $@) +include hello.d +', '', + # This runs afoul of https://savannah.gnu.org/bugs/?61226 + 0 ? "hello.d\n#MAKEFILE#:4: hello.d: $ERR_no_such_file" + : "hello.d\nhello.o\n#MAKE#: 'hello.o' is up to date.", + 0 ? 512 : 0); + +unlink('hello.td'); + +# Test DV 62088 : make sure we don't re-invoke for stdin makefiles. +# The test framework doesn't seem to have a good way to do this. + +create_file('input.mk', "all:;\$(info all)\n"); + +close(STDIN); +open(STDIN, "<", 'input.mk') || die "input.mk: $!\n"; + +run_make_test('', '-sf -', "all\n"); + +close(STDIN); +unlink('input.mk'); + # This tells the test driver that the perl test script executed properly. 1; - -### Local Variables: -### eval: (setq whitespace-action (delq 'auto-cleanup whitespace-action)) -### End: diff --git a/tests/scripts/features/se_explicit b/tests/scripts/features/se_explicit index c28641c..d1247d4 100644 --- a/tests/scripts/features/se_explicit +++ b/tests/scripts/features/se_explicit @@ -185,9 +185,9 @@ foo: $$@.o ; # Not creating libcat.a here prevents segfault, libcat.a: ; @touch $@ !, - '', q!#MAKEFILE#:16: Recipe was specified for file '-lcat' at #MAKEFILE#:19, + '', q!#MAKEFILE#:16: Recipe was specified for file '-lcat' at #MAKEFILE#:16, #MAKEFILE#:16: but '-lcat' is now considered the same file as 'libcat.a'. -#MAKEFILE#:16: Recipe for 'libcat.a' will be ignored in favor of the one for '-lcat'.!); +#MAKEFILE#:16: Recipe for '-lcat' will be ignored in favor of the one for 'libcat.a'.!); unlink('libcat.a'); # SV 28456 : Don't reset $$< for default recipes @@ -200,4 +200,305 @@ biz: $$(info $$<) !, '', "baz\n#MAKE#: Nothing to be done for 'biz'.\n"); + +# sv 60659. Second expansion of automatic variables inside a function in the +# prerequisite list. +# $$@ expands to the target in the 1st and following rules. +# $$<,$$^,$$+,$$|,$$?,$$*,$$% expand to the empty string in the prerequisite +# list of the 1st rule. +# $$<,$$^,$$+,$$|,$$?,$$*,$$% in the prerequisite list of the 2nd (and +# following) rule expand to the values from the 1st rule. + + +# subtest 1. Explicit rules. 1st rule. +run_make_test(q! +.SECONDEXPANSION: +all: 2.x +2.x: 5.z 6.z 5.z $$(info @=$$@,<=$$<,^=$$^,+=$$+,|=$$|,?=$$?,*=$$*,%=$$%) ; +%.z: ; +!, '', +"@=2.x,<=,^=,+=,|=,?=,*=,%= +#MAKE#: Nothing to be done for 'all'.\n"); + + +# subtest 2. Explicit rules. 2nd rule. +run_make_test(q! +.SECONDEXPANSION: +all: 15.x 1.x +15.x: 5.z 6.z 5.z | 7.z 7.z 8.z +1.x: 1.z 2.z 2.z | 3.z 4.z +15.x 1.x: 9.z $$(info @=$$@,<=$$<,^=$$^,+=$$+,|=$$|,?=$$?,*=$$*,%=$$%) ; +%.z: ; +!, '', +"@=15.x,<=5.z,^=5.z 6.z,+=5.z 6.z 5.z,|=7.z 8.z,?=,*=,%= +@=1.x,<=1.z,^=1.z 2.z,+=1.z 2.z 2.z,|=3.z 4.z,?=,*=,%= +#MAKE#: Nothing to be done for 'all'.\n"); + + +# subtest 3. Grouped targets in explicit rules. 1st rule. +run_make_test(q! +.SECONDEXPANSION: +all: 15.x +15.x 1.x&: 5.z 6.z 5.z $$(info @=$$@,<=$$<,^=$$^,+=$$+,|=$$|,?=$$?,*=$$*,%=$$%) ; +%.z: ; +!, '', +"@=15.x,<=,^=,+=,|=,?=,*=,%= +@=1.x,<=,^=,+=,|=,?=,*=,%= +#MAKE#: Nothing to be done for 'all'.\n"); + + +# subtest 4. Grouped targets in explicit rules. 2nd rule. +run_make_test(q! +.SECONDEXPANSION: +all: 15.x 1.x +15.x: 5.z 6.z 5.z | 7.z 7.z 8.z +1.x: 1.z 2.z 2.z | 3.z 4.z +15.x 1.x&: 9.z $$(info @=$$@,<=$$<,^=$$^,+=$$+,|=$$|,?=$$?,*=$$*,%=$$%) ; +%.z: ; +!, '', +"@=15.x,<=5.z,^=5.z 6.z,+=5.z 6.z 5.z,|=7.z 8.z,?=,*=,%= +@=1.x,<=1.z,^=1.z 2.z,+=1.z 2.z 2.z,|=3.z 4.z,?=,*=,%= +#MAKE#: Nothing to be done for 'all'.\n"); + + +# Double colon rules. +# Because each double colon rule is independent of the other double colon rules +# for the same target, each automatic variable in the prerequisite list, other +# than $$@, second expands to the empty string in any rule, 1st, 2nd or later. + +# subtest 5. 1st double colon rule. +run_make_test(q! +.SECONDEXPANSION: +all: 2.x +2.x:: 5.z 6.z 5.z $$(info @=$$@,<=$$<,^=$$^,+=$$+,|=$$|,?=$$?,*=$$*,%=$$%) ; +%.z: ; +!, '', +"@=2.x,<=,^=,+=,|=,?=,*=,%= +#MAKE#: Nothing to be done for 'all'.\n"); + + +# subtest 6. 2nd double colon rule. +run_make_test(q! +.SECONDEXPANSION: +all: 15.x 1.x +15.x:: 5.z 6.z 5.z | 7.z 7.z 8.z ; +1.x:: 1.z 2.z 2.z | 3.z 4.z ; +15.x 1.x:: 9.z $$(info @=$$@,<=$$<,^=$$^,+=$$+,|=$$|,?=$$?,*=$$*,%=$$%) ; +%.z: ; +!, '', +"@=15.x,<=,^=,+=,|=,?=,*=,%= +@=1.x,<=,^=,+=,|=,?=,*=,%= +#MAKE#: Nothing to be done for 'all'.\n"); + + +# sv 62324. +# Integrity self check. +run_make_test(q! +.SECONDEXPANSION: +all: bye.x +bye.x: $$(firstword bye.1; +!, '', "#MAKEFILE#:4: *** unterminated call to function 'firstword': missing ')'. Stop.", 512); + +unlink('hello.tsk', 'test.o', 'bye.tsk', 'hello.o', 'hello.h', 'hello.q', 'bye.c', 'bye.o'); + +# sv 62706. +# Test that makes avoids second expanding prerequisites of the targets which +# are not built. +# Here, hello.tsk is built and its prerequisites are second expanded. +# bye.tsk is not built and its prerequisites are not second expanded. +run_make_test(q! +.SECONDEXPANSION: +hello.tsk: hello.o $$(info second expansion of $$@ prereqs); $(info $@ from $<) +bye.tsk: bye.o $$(info second expansion of $$@ prereqs); $(info $@ from $<) +hello.o: $$(info second expansion of $$@ prereqs); $(info $@) +bye.o: $$(info second expansion of $$@ prereqs); $(info $@) +!, 'hello.tsk', +"second expansion of hello.tsk prereqs +second expansion of hello.o prereqs +hello.o +hello.tsk from hello.o +#MAKE#: 'hello.tsk' is up to date.\n"); + +# sv 62706. +# Multipe rules per target. +run_make_test(q! +.SECONDEXPANSION: + +all: hello.tsk +dep1:=hello.o +dep2:=hello.h +hello.tsk: $$(dep1) +hello.tsk: $$(dep2); $(info $@ from $^) +hello.o:; $(info $@) +hello.h:; $(info $@) +!, 'hello.tsk', +"hello.h +hello.o +hello.tsk from hello.h hello.o +#MAKE#: 'hello.tsk' is up to date.\n"); + +# sv 62706. +# Multiple targets per rule. +run_make_test(q! +.SECONDEXPANSION: +hello.tsk bye.tsk: hello.o $$(info second expansion of $$@ prereqs); $(info $@ from $<) +bye.tsk: bye.o $$(info second expansion of $$@ prereqs) +hello.o: $$(info second expansion of $$@ prereqs); $(info $@) +bye.o: $$(info second expansion of $$@ prereqs); $(info $@) +!, 'hello.tsk', +"second expansion of hello.tsk prereqs +second expansion of hello.o prereqs +hello.o +hello.tsk from hello.o +#MAKE#: 'hello.tsk' is up to date.\n"); + +# sv 62706. +# Grouped targets. +run_make_test(q! +.SECONDEXPANSION: +world.tsk: world.o $$(info 1 second expansion of $$@ prereqs) +hello.tsk world.tsk &: hello.o $$(info 2 second expansion of $$@ prereqs); $(info $@ from $<) +bye.tsk: bye.o $$(info second expansion of $$@ prereqs); $(info $@ from $<) +hello.o: $$(info second expansion of $$@ prereqs); $(info $@) +world.o: $$(info second expansion of $$@ prereqs); $(info $@) +bye.o: $$(info second expansion of $$@ prereqs); $(info $@) +!, 'hello.tsk', +"2 second expansion of hello.tsk prereqs +second expansion of hello.o prereqs +hello.o +2 second expansion of world.tsk prereqs +1 second expansion of world.tsk prereqs +second expansion of world.o prereqs +world.o +hello.tsk from hello.o +#MAKE#: 'hello.tsk' is up to date.\n"); + +# sv 62706. +# Order only. +run_make_test(q! +.SECONDEXPANSION: +hello.tsk:| hello.o $$(info second expansion of $$@ prereqs); $(info $@ from $|) +bye.tsk:| bye.o $$(info second expansion of $$@ prereqs); $(info $@ from $|) +hello.o:| $$(info second expansion of $$@ prereqs); $(info $@) +bye.o:| $$(info second expansion of $$@ prereqs); $(info $@) +!, 'hello.tsk', +"second expansion of hello.tsk prereqs +second expansion of hello.o prereqs +hello.o +hello.tsk from hello.o +#MAKE#: 'hello.tsk' is up to date.\n"); + +# sv 62706. +# Double colon. 1 rule per target. +run_make_test(q! +.SECONDEXPANSION: +hello.tsk:: hello.o $$(info second expansion of $$@ prereqs); $(info $@ from $<) +bye.tsk:: bye.o $$(info second expansion of $$@ prereqs); $(info $@ from $<) +hello.o:: $$(info second expansion of $$@ prereqs); $(info $@) +bye.o:: $$(info second expansion of $$@ prereqs); $(info $@) +!, 'hello.tsk', +"second expansion of hello.tsk prereqs +second expansion of hello.o prereqs +hello.o +hello.tsk from hello.o +#MAKE#: 'hello.tsk' is up to date.\n"); + +# sv 62706. +# Double colon. 2 rules per targets. +run_make_test(q! +.SECONDEXPANSION: +hello.tsk:: hello.o $$(info 1 second expansion of $$@ prereqs); $(info 1 $@ from $<) +hello.tsk:: hello.o $$(info 2 second expansion of $$@ prereqs); $(info 2 $@ from $<) +bye.tsk:: bye.o $$(info 1 second expansion of $$@ prereqs); $(info 1 $@ from $<) +bye.tsk:: bye.o $$(info 2 second expansion of $$@ prereqs); $(info 2 $@ from $<) +hello.o:: $$(info 1 second expansion of $$@ prereqs); $(info 1 $@) +hello.o:: $$(info 2 second expansion of $$@ prereqs); $(info 2 $@) +bye.o:: $$(info 1 second expansion of $$@ prereqs); $(info 1 $@) +bye.o:: $$(info 2 second expansion of $$@ prereqs); $(info 2 $@) +!, 'hello.tsk', +"1 second expansion of hello.tsk prereqs +1 second expansion of hello.o prereqs +1 hello.o +2 second expansion of hello.o prereqs +2 hello.o +1 hello.tsk from hello.o +2 second expansion of hello.tsk prereqs +2 hello.tsk from hello.o +#MAKE#: 'hello.tsk' is up to date.\n"); + +# sv 62706. +# Test that the prerequisites of 'hello.tsk' are second expanded once. +run_make_test(q! +.SECONDEXPANSION: +all: hello.tsk hello.q +hello.tsk: hello.o $$(info second expansion of $$@ prereqs); $(info $@ from $^) +hello.o: $$(info second expansion of $$@ prereqs); $(info $@) +hello.q: hello.tsk $$(info second expansion of $$@ prereqs); $(info $@ from $^) +!, '', +"second expansion of hello.tsk prereqs +second expansion of hello.o prereqs +hello.o +hello.tsk from hello.o +second expansion of hello.q prereqs +hello.q from hello.tsk +#MAKE#: Nothing to be done for 'all'.\n"); + +# sv 62706. +# Merge vpath file and local file. +# Test that both sets of prerequisites from 'hello.c' rule and from +# 'src/hello.c' rule are second expanded. +run_make_test(q! +.SECONDEXPANSION: +vpath hello.c src +all: hello.c; $(info $@ from $^) +hello.c: $$(info second expansion of hello.c prereqs); $(info 1 $@) +src/hello.c: $$(info second expansion of src/hello.c prereqs); $(info 2 $@) +!, '', +"#MAKEFILE#:5: Recipe was specified for file 'hello.c' at #MAKEFILE#:5, +#MAKEFILE#:5: but 'hello.c' is now considered the same file as 'src/hello.c'. +#MAKEFILE#:5: Recipe for 'hello.c' will be ignored in favor of the one for 'src/hello.c'. +second expansion of src/hello.c prereqs +second expansion of hello.c prereqs +2 src/hello.c +all from src/hello.c +#MAKE#: 'all' is up to date.\n"); + +# sv 62706. +# .DEFAULT. +run_make_test(q! +.SECONDEXPANSION: +bye:=bye.c +all: hello.o +.DEFAULT: $$(info second expansion of prereqs of default recipe @ = $$@) ; $(info default recipe $@) +!, '', +"default recipe hello.o +#MAKE#: Nothing to be done for 'all'.\n"); + +unlink('hello.1'); + +# sv 62706. +# No side effects from second expansion of unrelated rules. +run_make_test(q! +.SECONDEXPANSION: +hello.tsk:; exit 1 +unrelated: $$(shell touch hello.1); +!, '', +"exit 1 +#MAKE#: *** [#MAKEFILE#:3: hello.tsk] Error 1\n", 512); + +# sv 62706. +# Second expansion of intermediate prerequisites. +# The rule to build hello.x is explicit. +# .SECONDARY marks hello.x as intermediate. +# Test that $$(deps) is secondary expanded. +run_make_test(q! +deps:=hello.h +.SECONDEXPANSION: +.SECONDARY: hello.x +all: hello.x +hello.x: $$(deps); $(info $@) +hello.h:; $(info $@) +!, '', "hello.h\nhello.x\n#MAKE#: Nothing to be done for 'all'.\n"); + + 1; diff --git a/tests/scripts/features/se_implicit b/tests/scripts/features/se_implicit index 866d1fb..c9d7ca9 100644 --- a/tests/scripts/features/se_implicit +++ b/tests/scripts/features/se_implicit @@ -262,5 +262,245 @@ run_make_test(q! !, 'q/ux', "q/u\nq/u\n"); + + +# sv 60188. +# Test that a file explicitly mentioned by the user and made by an implicit +# rule is not considered intermediate. + +touch('hello.z'); + +# subtest 1. +# hello.x is derived from the stem and thus is an intermediate file. +run_make_test(q! +.SECONDEXPANSION: +dep:=.x +all: hello.z +%.z: %$$(dep) ; @echo $@ +%.x: ; +!, '', "#MAKE#: Nothing to be done for 'all'.\n"); + + +# subtest 2. +# test.x is explicitly mentioned and thus is not an intermediate file. +run_make_test(q! +.SECONDEXPANSION: +dep:=test.x +all: hello.z +%.z: %.x $$(dep) ; @echo $@ +%.x: ; +!, '', "hello.z\n"); + +# subtest 3. +# make is building hello.z and does not second expand the prerequisites of rule +# 'unrelated: $$(dep)'. '$$(dep)' stays not expanded and 'hello.x' is never +# entered to the database. Make considers 'hello.x' intermediate while building +# 'hello.z'. Because 'hello.z' is present and 'hello.x' is missing and +# 'hello.x' is intermediate, there is no need to rebuild 'hello.z'. +run_make_test(q! +.SECONDEXPANSION: +dep:=hello.x +all: hello.z +%.z: %.x; @echo $@ +%.x: ; +unrelated: $$(dep) +!, '', "#MAKE#: Nothing to be done for 'all'.\n"); + +# subtest 4. +# Just like subtest 3. $$(dep) is not second expanded. 'hello.x' is +# intermediate. +run_make_test(q! +.SECONDEXPANSION: +dep:=hello.x +all: hello.z +%.z: %.x; @echo $@ +%.x: ; +%.q: $$(dep) +!, '', "#MAKE#: Nothing to be done for 'all'.\n"); + +unlink('hello.z'); + + +# sv 60188. +# Test that a file explicitly mentioned by the user and made by an implicit +# rule is not considered intermediate, even when the builtin rules are used. + +touch('hello.x'); +touch('hello.tsk'); + +# subtest 1. +# hello.z is explicitly mentioned and thus is not an intermediate file. +run_make_test(q! +.SECONDEXPANSION: +dep:=hello.z +all: hello.tsk +%.tsk: $$(dep) ; @echo $@ +%.z : %.x ; @echo $@ +!, '', "hello.z\nhello.tsk"); + +# subtest 2. +# hello.z is derived from the stem and thus is an intermediate file. +run_make_test(q! +.SECONDEXPANSION: +dep:=.z +all: hello.tsk +%.tsk: %$$(dep) ; @echo $@ +%.z : %.x ; @echo $@ +!, '', "#MAKE#: Nothing to be done for 'all'.\n"); + +unlink('hello.x'); +unlink('hello.tsk'); + + +# sv 60659. Second expansion of automatic variables inside a function in the +# prerequisite list. +# $$@ expands to the target in the 1st and following rules. +# $$* expands to the stem in the 1st and following rules. +# $$<,$$^,$$+,$$|,$$?,$$% expand to the empty string in the prerequisite list +# of the 1st rule. +# $$<,$$^,$$+,$$|,$$?,$$% in the prerequisite list of the 2nd (and following) +# rule expand to the values from the 1st rule. +# $$% cannot be used in prerequisites, because in pattern rules % is +# substituted for stem. + + +# subtest 1. Pattern rules. 1st rule. +run_make_test(q! +.SECONDEXPANSION: +all: 2.x +%.x: 5.z 6.z 5.z $$(info @=$$@,<=$$<,^=$$^,+=$$+,|=$$|,?=$$?,*=$$*) ; +%.z: ; +!, '', +"@=2.x,<=,^=,+=,|=,?=,*=2 +#MAKE#: Nothing to be done for 'all'.\n"); + + +# subtest 2. Pattern rules. 2nd rule. +run_make_test(q! +.SECONDEXPANSION: +all: 2.x 1.x +2.x: 5.z 6.z 5.z | 7.z 7.z 8.z +1.x: 1.z 2.z 2.z | 3.z 4.z +%.x: 9.z $$(info @=$$@,<=$$<,^=$$^,+=$$+,|=$$|,?=$$?,*=$$*) ; +%.z: ; +!, '', +"@=2.x,<=5.z,^=5.z 6.z,+=5.z 6.z 5.z,|=7.z 8.z,?=,*=2 +@=1.x,<=1.z,^=1.z 2.z,+=1.z 2.z 2.z,|=3.z 4.z,?=,*=1 +#MAKE#: Nothing to be done for 'all'.\n"); + + +# subtest 3. Static pattern rules. 1st rule. +run_make_test(q! +.SECONDEXPANSION: +all: 2.x +2.x: %.x: 5.z 6.z 5.z $$(info @=$$@,<=$$<,^=$$^,+=$$+,|=$$|,?=$$?,*=$$*) ; +%.z: ; +!, '', +"@=2.x,<=,^=,+=,|=,?=,*=2 +#MAKE#: Nothing to be done for 'all'.\n"); + + +# subtest 4. Static pattern rules. 2nd rule. +run_make_test(q! +.SECONDEXPANSION: +all: 15.x 1.x +15.x: 5.z 6.z 5.z | 7.z 7.z 8.z +1.x: 1.z 2.z 2.z | 3.z 4.z +15.x 1.x: %.x: 9.z $$(info @=$$@,<=$$<,^=$$^,+=$$+,|=$$|,?=$$?,*=$$*) ; +%.z: ; +!, '', +"@=15.x,<=5.z,^=5.z 6.z,+=5.z 6.z 5.z,|=7.z 8.z,?=,*=15 +@=1.x,<=1.z,^=1.z 2.z,+=1.z 2.z 2.z,|=3.z 4.z,?=,*=1 +#MAKE#: Nothing to be done for 'all'.\n"); + + +# subtest 5. Grouped targets in implicit rules. 1st rule. +run_make_test(q! +.SECONDEXPANSION: +all: 2.x +%.x %.xx&: 5.z 6.z 5.z $$(info @=$$@,<=$$<,^=$$^,+=$$+,|=$$|,?=$$?,*=$$*) ; +%.z: ; +!, '', +"@=2.x,<=,^=,+=,|=,?=,*=2 +#MAKE#: Nothing to be done for 'all'.\n"); + + +# subtest 6. Grouped targets in implicit rules. 2nd rule. +run_make_test(q! +.SECONDEXPANSION: +all: 2.x 1.xx +2.x: 5.z 6.z 5.z | 7.z 7.z 8.z +1.xx: 1.z 2.z 2.z | 3.z 4.z +%.x %.xx&: 9.z $$(info @=$$@,<=$$<,^=$$^,+=$$+,|=$$|,?=$$?,*=$$*) ; +%.z: ; +!, '', +"@=2.x,<=5.z,^=5.z 6.z,+=5.z 6.z 5.z,|=7.z 8.z,?=,*=2 +@=1.xx,<=1.z,^=1.z 2.z,+=1.z 2.z 2.z,|=3.z 4.z,?=,*=1 +#MAKE#: Nothing to be done for 'all'.\n"); + + +# subtest 7. Double colon rule. +run_make_test(q! +.SECONDEXPANSION: +all: 2.x +%.x:: 5.z 6.z 5.z $$(info @=$$@,<=$$<,^=$$^,+=$$+,|=$$|,?=$$?,*=$$*) ; +5.z 6.z: ; +!, '', +"@=2.x,<=,^=,+=,|=,?=,*=2 +#MAKE#: Nothing to be done for 'all'.\n"); + +# sv 62324. +# Integrity self check. +run_make_test(q! +.SECONDEXPANSION: +all: bye.x +%.x: $$(firstword %.1; +!, '', "#MAKE#: *** unterminated call to function 'firstword': missing ')'. Stop.", 512); + +# sv 62706. +# Test that makes avoids second expanding prerequisites of the rules which are +# not tried during implicit search. +# Here, make tries rules '%.tsk: %.o' and '%.o' and their prerequisites are +# second expanded. +# Rules '%.bin: %.x' and '%.x:' are not used in implicit search for 'hello.tsk' +# and 'hello.o' and their prerequisites are not expanded. +run_make_test(q! +.SECONDEXPANSION: +%.bin: %.x $$(info second expansion of $$@ prereqs); $(info $@ from $<) +%.tsk: %.o $$(info second expansion of $$@ prereqs); $(info $@ from $<) +%.x: $$(info second expansion of $$@ prereqs); $(info $@) +%.o: $$(info second expansion of $$@ prereqs); $(info $@) +!, '-R hello.tsk', +"second expansion of hello.o prereqs +second expansion of hello.tsk prereqs +hello.o +hello.tsk from hello.o +#MAKE#: 'hello.tsk' is up to date.\n"); + +# sv 62706. +# No side effects from second expansion of unrelated rules. +run_make_test(q! +.SECONDEXPANSION: +all: hello.tsk +%.tsk: %.o; exit 1 +hello.o:; +%.q: $$(shell touch hello.1); +!, '', +"exit 1 +#MAKE#: *** [#MAKEFILE#:4: hello.tsk] Error 1\n", 512); + +# sv 62706. +# Second expansion of intermediate prerequisites. +# The rule to build hello.x is implicit. +# Test that $$(deps) is secondary expanded. +run_make_test(q! +deps:=hello.h +.SECONDEXPANSION: +all: hello.tsk +%.tsk: %.x; $(info $@) +%.x: $$(deps); $(info $@) +hello.h:; $(info $@) +!, '', "hello.h\nhello.x\nhello.tsk\n#MAKE#: Nothing to be done for 'all'.\n"); + # This tells the test driver that the perl test script executed properly. 1; diff --git a/tests/scripts/features/se_statpat b/tests/scripts/features/se_statpat index b1e59e1..935ff3f 100644 --- a/tests/scripts/features/se_statpat +++ b/tests/scripts/features/se_statpat @@ -91,17 +91,142 @@ baz.a.2 # run_make_test(q! .SECONDEXPANSION: -foo$$bar: f%r: % $$*.1 - @echo '$*' +foo$$bar: f%r: % $$*.1 ; @echo '$*' -oo$$ba oo$$ba.1: - @echo '$@' +oo$$ba oo$$ba.1: ; @echo '$@' !, '', 'oo$ba oo$ba.1 oo$ba '); +# sv 62324. +# Integrity self check. +run_make_test(q! +.SECONDEXPANSION: +all: bye.x +bye.x: %.x: $$(firstword %.1; +!, '', "#MAKEFILE#:4: *** unterminated call to function 'firstword': missing ')'. Stop.", 512); + +#unlink('hello.tsk', 'bye.tsk', 'hello.o', 'hello.q', 'bye.o'); + +# sv 62706. +# Test that makes avoids second expanding prerequisites of the targets which +# are not built. +# Here, hello.tsk is built and its prerequisites are second expanded. +# bye.tsk is not built and its prerequisites are not second expanded. + +# Static pattern rules. +run_make_test(q! +.SECONDEXPANSION: +hello.tsk: %.tsk: %.o $$(info second expansion of $$@ prereqs); $(info $@ from $<) +bye.tsk: %.tsk: %.o $$(info second expansion of $$@ prereqs); $(info $@ from $<) +hello.o: $$(info second expansion of $$@ prereqs); $(info $@) +bye.o: $$(info second expansion of $$@ prereqs); $(info $@) +!, 'hello.tsk', +"second expansion of hello.tsk prereqs +second expansion of hello.o prereqs +hello.o +hello.tsk from hello.o +#MAKE#: 'hello.tsk' is up to date.\n"); + +# sv 62706. +# Order only prereqs. +run_make_test(q! +.SECONDEXPANSION: +hello.tsk: %.tsk:| %.o $$(info second expansion of $$@ prereqs); $(info $@ from $|) +bye.tsk: %.tsk:| %.o $$(info second expansion of $$@ prereqs); $(info $@ from $|) +hello.o:| $$(info second expansion of $$@ prereqs); $(info $@) +bye.o:| $$(info second expansion of $$@ prereqs); $(info $@) +!, 'hello.tsk', +"second expansion of hello.tsk prereqs +second expansion of hello.o prereqs +hello.o +hello.tsk from hello.o +#MAKE#: 'hello.tsk' is up to date.\n"); + +# sv 62706. +# Double colon. 1 rule per target. +run_make_test(q! +.SECONDEXPANSION: +hello.tsk:: %.tsk: %.o $$(info second expansion of $$@ prereqs); $(info $@ from $<) +bye.tsk:: %.tsk: %.o $$(info second expansion of $$@ prereqs); $(info $@ from $<) +hello.o:: $$(info second expansion of $$@ prereqs); $(info $@) +bye.o:: $$(info second expansion of $$@ prereqs); $(info $@) +!, 'hello.tsk', +"second expansion of hello.tsk prereqs +second expansion of hello.o prereqs +hello.o +hello.tsk from hello.o +#MAKE#: 'hello.tsk' is up to date.\n"); + +# sv 62706. +# Double colon. 2 rules per target. +run_make_test(q! +.SECONDEXPANSION: +hello.tsk:: %.tsk: %.o $$(info 1 second expansion of $$@ prereqs); $(info 1 $@ from $<) +hello.tsk:: %.tsk: %.o $$(info 2 second expansion of $$@ prereqs); $(info 2 $@ from $<) +bye.tsk:: %.tsk: %.o $$(info 1 second expansion of $$@ prereqs); $(info 1 $@ from $<) +bye.tsk:: %.tsk: %.o $$(info 2 second expansion of $$@ prereqs); $(info 2 $@ from $<) +hello.o:: $$(info 1 second expansion of $$@ prereqs); $(info 1 $@) +hello.o:: $$(info 2 second expansion of $$@ prereqs); $(info 2 $@) +bye.o:: $$(info 1 second expansion of $$@ prereqs); $(info 1 $@) +bye.o:: $$(info 2 second expansion of $$@ prereqs); $(info 2 $@) +!, 'hello.tsk', +"1 second expansion of hello.tsk prereqs +1 second expansion of hello.o prereqs +1 hello.o +2 second expansion of hello.o prereqs +2 hello.o +1 hello.tsk from hello.o +2 second expansion of hello.tsk prereqs +2 hello.tsk from hello.o +#MAKE#: 'hello.tsk' is up to date.\n"); + +# sv 62706. +# Test that the prerequisites of 'hello.tsk' are second expanded once. +run_make_test(q! +.SECONDEXPANSION: +all: hello.tsk hello.q +hello.tsk: %.tsk: %.o $$(info second expansion of $$@ prereqs); $(info $@ from $^) +hello.o: $$(info second expansion of $$@ prereqs); $(info $@) +hello.q: %.q: %.tsk $$(info second expansion of $$@ prereqs); $(info $@ from $^) +!, '', +"second expansion of hello.tsk prereqs +second expansion of hello.o prereqs +hello.o +hello.tsk from hello.o +second expansion of hello.q prereqs +hello.q from hello.tsk +#MAKE#: Nothing to be done for 'all'.\n"); + +unlink('hello.1'); + +# sv 62706. +# No side effects from second expansion of unrelated rules. +run_make_test(q! +.SECONDEXPANSION: +all: hello.tsk +hello.tsk: %.tsk: %.o; exit 1 +hello.o:; +bye.tsk: %.tsk: $$(shell touch hello.1); +!, '', +"exit 1 +#MAKE#: *** [#MAKEFILE#:4: hello.tsk] Error 1\n", 512); + +# sv 62706. +# Second expansion of intermediate prerequisites. +# The rule to build hello.x is static pattern. +# .SECONDARY marks hello.x as intermediate. +# Test that $$(deps) is secondary expanded. +run_make_test(q! +deps:=hello.h +.SECONDEXPANSION: +.SECONDARY: hello.x +all: hello.x +hello.x: %.x: $$(deps); $(info $@) +hello.h:; $(info $@) +!, '', "hello.h\nhello.x\n#MAKE#: Nothing to be done for 'all'.\n"); # This tells the test driver that the perl test script executed properly. 1; diff --git a/tests/scripts/features/statipattrules b/tests/scripts/features/statipattrules index 3f363de..e4e118e 100644 --- a/tests/scripts/features/statipattrules +++ b/tests/scripts/features/statipattrules @@ -72,13 +72,15 @@ foo.baz: ;@: # perprerequisite's stem (Savannah bug #16053). # run_make_test(' +.RECIPEPREFIX := > + all.foo.bar: %.foo.bar: %.one all.foo.bar: %.bar: %.two all.foo.bar: - @echo $* - @echo $^ +> @echo $* +> @echo $^ .DEFAULT:;@: ', @@ -92,6 +94,7 @@ all.one all.foo.two'); # (Savannah bug #16053). # run_make_test(' +.RECIPEPREFIX := > .SECONDEXPANSION: all.foo.bar: %.foo.bar: %.one $$*-one @@ -99,8 +102,8 @@ all.foo.bar: %.foo.bar: %.one $$*-one all.foo.bar: %.bar: %.two $$*-two all.foo.bar: - @echo $* - @echo $^ +> @echo $* +> @echo $^ .DEFAULT:;@: ', @@ -108,4 +111,201 @@ all.foo.bar: 'all.foo all.one all-one all.foo.two all.foo-two'); +# Test #8: +# sv 60188. +# Static pattern rules are considered explicit rules: no prerequisite of +# a static pattern rule can ever be considered intermediate. + +touch('hello.z'); + +# subtest 1 +run_make_test(q! +hello.z: %.z: %.x ; @echo $@ +%.x: ; +!, '', "hello.z\n"); + +# subtest 2 +run_make_test(q! +hello.z: %.z: %.x test.x ; @echo $@ +%.x: ; +!, '', "hello.z\n"); + +# subtest 3 +# 'hello.x' is mentioned explicitly on an unrelated rule. +run_make_test(q! +hello.z: %.z: %.x ; @echo $@ +%.x: ; +unrelated: hello.x +!, '', "hello.z\n"); + +unlink('hello.z'); + +# sv 17374 Ensure double-colon static pattern rules work + +touch(qw(a.src b.src)); + +run_make_test(q! +all: a.tgt b.tgt +a.tgt b.tgt:: %.tgt : %.src ; cp $< $@ +!, + '', "cp a.src a.tgt\ncp b.src b.tgt\n"); + +unlink(qw(a.src b.src a.tgt b.tgt)); + +my @dir = ('', 'lib/'); # With and without last slash. +my @secondexpansion = ('', '.SECONDEXPANSION:'); + +# The following combinations are generated with and without second expansion. +# 1. +# all: bye.x +# bye.x: %.x: ... +# +# 2. +# all: lib/bye.x +# lib/bye.x: %.x: ... +# +# 3. +# all: lib/bye.x +# lib/bye.x: lib/%.x: ... +# +# The following combination is not generated, because there is no rule to +# build bye.x, no stem substitution takes place, not of interest of this test. +# 4. +# all: bye.x +# bye.x: lib/%.x: ... +# + +for my $se (@secondexpansion) { +for my $d (@dir) { # The directory of the prerequisite of 'all'. +for my $r (@dir) { # The directory of the prerequisite in the rule definition. +(!$d && $r) && next; # Combination 4. +my $dollar = $se ? '$' : ''; + +# The prerequisite should only have directory if the prerequisite of 'all' has +# it and if the prequisite pattern in the rule definition does not have it. +# That is combination 2. +my $pdir = $d && !$r ? $d : ''; + + +# One func, one %. +my $prereqs = "${pdir}bye.1"; +run_make_test(" +$se +.PHONY: $prereqs +all: ${d}bye.x +${d}bye.x: $r%.x: $dollar\$(firstword %.1); \$(info \$@ from \$^) +", '', "${d}bye.x from $prereqs\n#MAKE#: Nothing to be done for 'all'.\n"); + + +# Multiple funcs, each has one %. +$prereqs = "${pdir}bye.1 ${pdir}bye.2"; +run_make_test(" +$se +.PHONY: $prereqs +all: ${d}bye.x +${d}bye.x: $r%.x: $dollar\$(firstword %.1) $dollar\$(firstword %.2); \$(info \$@ from \$^) +", '', "${d}bye.x from $prereqs\n#MAKE#: Nothing to be done for 'all'.\n"); + + +# Multiple funcs, each has multiple %. +$prereqs = "${pdir}bye.1 ${pdir}bye.2 ${pdir}bye.3 ${pdir}bye.4"; +run_make_test(" +$se +.PHONY: $prereqs +all: ${d}bye.x +${d}bye.x: $r%.x: $dollar\$(wordlist 1, 99, %.1 %.2) $dollar\$(wordlist 1, 99, %.3 %.4); \$(info \$@ from \$^) +", '', "${d}bye.x from $prereqs\n#MAKE#: Nothing to be done for 'all'.\n"); + + +# Multiple funcs, each has multiple %, each prerequisite has multiple %. +$prereqs = "${pdir}bye_%_%.1 ${pdir}bye_%_%.2 ${pdir}bye_%_%.3 ${pdir}bye_%_%.4"; +run_make_test(" +$se +.PHONY: $prereqs +all: ${d}bye.x +${d}bye.x: $r%.x: $dollar\$(wordlist 1, 99, %_%_%.1 %_%_%.2) $dollar\$(wordlist 1, 99, %_%_%.3 %_%_%.4); \$(info \$@ from \$^) +", '', "${d}bye.x from $prereqs\n#MAKE#: Nothing to be done for 'all'.\n"); + + +# Nested functions. +$prereqs = "${pdir}bye.1 ${pdir}bye.2 ${pdir}bye.3 ${pdir}bye.4"; +run_make_test(" +$se +.PHONY: $prereqs +all: ${d}bye.x +${d}bye.x: $r%.x: $dollar\$(wordlist 1, 99, $dollar\$(wordlist 1, 99, %.1 %.2)) $dollar\$(wordlist 1, 99, $dollar\$(wordlist 1,99, %.3 %.4)); \$(info \$@ from \$^) +", '', "${d}bye.x from $prereqs\n#MAKE#: Nothing to be done for 'all'.\n"); + + +# Multiple funcs, each has multiple words, each word has multiple %, sole %, +# various corner cases. +# Make should substitude the first % and only the first % in each word with the +# stem. +$prereqs = "${pdir}bye1%2% ${pdir}bye 3${pdir}bye4%5 6${pdir}bye ${pdir}bye7%8 ${pdir}bye9 ${pdir}bye10% 11${pdir}bye12 13"; +run_make_test(" +$se +.PHONY: $prereqs +all: ${d}bye.x +${d}bye.x: $r%.x: $dollar\$(wordlist 1, 99, %1%2% % 3%4%5 6%) %7%8 %9 $dollar\$(wordlist 1, 99, %10% 11%12) 13; \$(info \$@ from \$^) +", '', "${d}bye.x from $prereqs\n#MAKE#: Nothing to be done for 'all'.\n"); + + +if ($port_type eq 'UNIX') { +# Test that make does not use some hardcoded array of a finite size on stack. +# Long prerequisite name. This prerequisite name is over 66K long. +my $prefix = 'abcdefgh' x 128 x 33; # 33K long. +my $suffix = 'stuvwxyz' x 128 x 33; # 33K long. +$prereqs = "${prefix}${pdir}bye${suffix}.1 ${prefix}${pdir}bye${suffix}.2"; +run_make_test(" +$se +.PHONY: $prereqs +all: ${d}bye.x +${d}bye.x: $r%.x: $dollar\$(wordlist 1, 99, ${prefix}%${suffix}.1 ${prefix}%${suffix}.2); \$(info \$@ from \$^) +", '', "${d}bye.x from $prereqs\n#MAKE#: Nothing to be done for 'all'.\n"); +} + + +# Empty stem. +$prereqs = "${pdir}.1"; +run_make_test(" +$se +.PHONY: $prereqs +all: ${d}bye.x +${d}bye.x: $r%bye.x: $dollar\$(firstword %.1); \$(info \$@ from \$^) +", '', "${d}bye.x from $prereqs\n#MAKE#: Nothing to be done for 'all'.\n"); + + +# A word expands to an empty prerequisite. +run_make_test(" +$se +all: ${d}bye.x +${d}bye.x: $r%.x: $dollar\$(%); \$(info \$@ from \$^) +", '', "${d}bye.x from \n#MAKE#: Nothing to be done for 'all'.\n"); + +} +} +} + +# Escaped %. +# The following combinations are generated without second expansion. +# 1. +# all: the%weird\\_hello_pattern\\.x +# the\\%weird\\_hello_pattern\\.x: the\\%weird\\_%_pattern\\.x: ... +# +# 2. +# all: lib/the%weird\\_hello_pattern\\.x +# lib/the\\%weird\\_hello_pattern\\.x: lib/the\\%weird\\_%_pattern\\.x: ... +# +# Other combinations or second expansion are not tested, because escaped % is +# not implemented for those. + +for my $d (@dir) { +my $prereqs = "${d}the%weird\\\\_hello_pattern%\\\\.1 ${d}the%weird\\\\_hello_pattern%\\\\.2"; +run_make_test(" +.PHONY: $prereqs +all: ${d}the%weird\\\\_hello_pattern\\\\.x +${d}the\\%weird\\\\_hello_pattern\\\\.x: ${d}the\\%weird\\\\_%_pattern\\\\.x: \$(wordlist 1, 99, ${d}the\\%weird\\\\_%_pattern%\\\\.1 ${d}the\\%weird\\\\_%_pattern%\\\\.2); \$(info \$@ from \$^) +", '', "${d}the%weird\\\\_hello_pattern\\\\.x from $prereqs\n#MAKE#: Nothing to be done for 'all'.\n"); +} + 1; diff --git a/tests/scripts/features/targetvars b/tests/scripts/features/targetvars index 2929b2c..5088251 100644 --- a/tests/scripts/features/targetvars +++ b/tests/scripts/features/targetvars @@ -12,8 +12,9 @@ export BAR = bar one: override FOO = one one two: ; @echo $(FOO) $(BAR) two: BAR = two +.RECIPEPREFIX = > three: ; BAR=1000 - @echo $(FOO) $(BAR) +> @echo $(FOO) $(BAR) # Some things that shouldn not be target vars funk : override funk : override adelic @@ -86,7 +87,6 @@ run_make_test(undef, "foo.q bar.q", "qvar = rvar\nqvar =\n"); run_make_test(undef, "foo.t bar.s", "qvar = qvar\nqvar =\n"); - # TEST #8 # For PR/1378: Target-specific vars don't inherit correctly @@ -183,7 +183,7 @@ run_make_test(undef, 'foo PATTERN=yes', "ok ok foo pat\nok ok foo pat\n"); # (> make default buffer length) run_make_test(' -base_metals_fmd_reports.sun5 base_metals_fmd_reports CreateRealPositions CreateMarginFunds deals_changed_since : BUILD_OBJ=$(shell if [ -f "build_information.generate" ]; then echo "$(OBJ_DIR)/build_information.o"; else echo "no build information"; fi ) +base_metals_fmd_reports.sun5 base_metals_fmd_reports CreateRealPositions CreateMarginFunds deals_changed_since : BUILD_OBJ=$(shell if test -f "build_information.generate" ; then echo "$(OBJ_DIR)/build_information.o"; else echo "no build information"; fi ) deals_changed_since: ; @echo $(BUILD_OBJ) ', @@ -270,17 +270,158 @@ all: ; $sname >/dev/null # Don't use the general PATH if not found on the target path -$extraENV{PATH} = "$ENV{PATH}:sd"; +$ENV{PATH} = "$ENV{PATH}:sd"; + +my ($ernum, $erstr); +if ($port_type eq 'W32') { + $ernum = 1; + $erstr = "'$sname' is not recognized as an internal or external command,\noperable program or batch file."; +} else { + $ernum = 127; + $erstr = "#MAKE#: $sname: $ERR_no_such_file"; +} run_make_test(qq! all: PATH := .. all: ; $sname !, - '', "$sname\n#MAKE#: $sname: $ERR_no_such_file\n#MAKE#: *** [#MAKEFILE#:3: all] Error 127", 512); + '', "$sname\n$erstr\n#MAKE#: *** [#MAKEFILE#:3: all] Error $ernum", 512); unlink("sd/$sname"); rmdir ('sd'); +# SV 59230: Conditional (non-)assignment of target-specific variables should +# preserve export settings. + +$ENV{hello} = 'moon'; +run_make_test(q! +all:; @echo hello=$$hello +dummy: hello?=world +!, + '', 'hello=moon'); + +# SV 59230: Assignment of a global variable should not affect export of a +# target specific variable. + +$ENV{hello} = "moon"; +run_make_test(q! +all:; @echo hello=$$hello +hello=sun +dummy: hello?=world +!, + '', 'hello=sun'); + +# Support target-specific unexport + +$ENV{hello} = "moon"; +run_make_test(q! +unexport hello=sun +all: base exp +base exp: ; @echo hello=$$hello +exp: export hello=world +!, + '', "hello=\nhello=world\n"); + +$ENV{hello} = "moon"; +run_make_test(q! +hello=sun +all: base exp +base exp: ; @echo hello=$$hello +exp: unexport hello=world +!, + '', "hello=sun\nhello=\n"); + +run_make_test(q! +all:; @echo hello=$$hello +unexport hello=sun +dummy: hello?=world +!, + '', 'hello='); + +$ENV{hello} = "moon"; +run_make_test(q! +all:; @echo hello=$$hello +hello=sun +dummy: unexport hello=world +!, + '', 'hello=sun'); + +run_make_test(q! +all: mid +mid: base + +ifeq ($(midexport),export) +mid: export hello=mid +else ifeq ($(midexport),unexport) +mid: unexport hello=mid +else +mid: hello=mid +endif + +ifeq ($(baseexport),export) +base: export hello=base +else ifeq ($(baseexport),unexport) +base: unexport hello=base +else +base: hello=base +endif + +all mid base:; @echo $@ make=$(hello) shell=$$hello +!, + '', "base make=base shell=\nmid make=mid shell=\nall make= shell=\n"); + +# Test base settings with env var +$ENV{hello} = "environ"; +run_make_test(undef, + '', "base make=base shell=base\nmid make=mid shell=mid\nall make=environ shell=environ\n"); + +$ENV{hello} = "environ"; +run_make_test(undef, + 'baseexport=export', "base make=base shell=base\nmid make=mid shell=mid\nall make=environ shell=environ\n"); + +$ENV{hello} = "environ"; +run_make_test(undef, + 'baseexport=unexport', "base make=base shell=\nmid make=mid shell=mid\nall make=environ shell=environ\n"); + +# Test mid settings with env var +$ENV{hello} = "environ"; +run_make_test(undef, + 'midexport=export', "base make=base shell=base\nmid make=mid shell=mid\nall make=environ shell=environ\n"); + +$ENV{hello} = "environ"; +run_make_test(undef, + 'midexport=export baseexport=unexport', "base make=base shell=\nmid make=mid shell=mid\nall make=environ shell=environ\n"); + +$ENV{hello} = "environ"; +run_make_test(undef, + 'midexport=unexport', "base make=base shell=\nmid make=mid shell=\nall make=environ shell=environ\n"); + +$ENV{hello} = "environ"; +run_make_test(undef, + 'midexport=unexport baseexport=export', "base make=base shell=base\nmid make=mid shell=\nall make=environ shell=environ\n"); + +# Test base settings without env var +run_make_test(undef, + 'baseexport=export', "base make=base shell=base\nmid make=mid shell=\nall make= shell=\n"); + +run_make_test(undef, + 'baseexport=unexport', "base make=base shell=\nmid make=mid shell=\nall make= shell=\n"); + +# Test mid settings with env var +run_make_test(undef, + 'midexport=export', "base make=base shell=base\nmid make=mid shell=mid\nall make= shell=\n"); + +run_make_test(undef, + 'midexport=export baseexport=unexport', "base make=base shell=\nmid make=mid shell=mid\nall make= shell=\n"); + +run_make_test(undef, + 'midexport=unexport', "base make=base shell=\nmid make=mid shell=\nall make= shell=\n"); + +run_make_test(undef, + 'midexport=unexport baseexport=export', "base make=base shell=base\nmid make=mid shell=\nall make= shell=\n"); + + + # TEST #19: Test define/endef variables as target-specific vars # run_make_test(' @@ -296,7 +437,3 @@ rmdir ('sd'); # '', "local\n"); 1; - -### Local Variables: -### eval: (setq whitespace-action (delq 'auto-cleanup whitespace-action)) -### End: diff --git a/tests/scripts/features/temp_stdin b/tests/scripts/features/temp_stdin new file mode 100644 index 0000000..b06df53 --- /dev/null +++ b/tests/scripts/features/temp_stdin @@ -0,0 +1,118 @@ +# -*-mode: perl-*- + +$description = "Test handling of temporary file created from stdin."; + +# These tests rely on the test_driver checking for leftover temporary content + +create_file('input.mk', "world:=1\n"); +create_file('bye.mk', "moon:=2\n"); + +# sv 62118,62145. +# Test that makes leaves no temp file when make code is piped to stdin and -v, +# -h or an invalid option is specified. +my @opts = ('-v', '-h', '--nosuchopt'); +my @exit_codes = (0, 0, 512); +for my $i (0 .. $#opts) { + close(STDIN); + open(STDIN, "<", 'input.mk') || die "$0: cannot open input.mk for reading: $!"; + run_make_test(q! +all:; $(info hello world) +!, + "$opts[$i] -f-", "/uilt for /", $exit_codes[$i]); +} + +# sv 62118,62145. +# Test that a stdin temp file is removed. +close(STDIN); +open(STDIN, "<", 'input.mk') || die "$0: cannot open input.mk for reading: $!"; +run_make_test(q! +all:; $(info world=$(world)) +!, + '-f-', "world=1\n#MAKE#: 'all' is up to date.\n"); + +# sv 62118,62145. +# Test that a stdin temp file is removed, even when make re-execs. +# Also test that make honors TMPDIR to create the temp file. +# Ensure touching bye.mk causes re-exec. +&utouch(-600, 'bye.mk'); +close(STDIN); +open(STDIN, "<", 'input.mk') || die "$0: cannot open input.mk for reading: $!"; +run_make_test(q! +include bye.mk +all:; $(info hello) +$(MAKE_RESTARTS)bye.mk: force; touch $@ +force: +!, + '-R --debug=b -f-', "/Re-executing.+?--temp-stdin=\Q$temppath\E/"); + +if ($port_type eq 'UNIX') { +# POSIX doesn't require sh to set PPID so test this +my $cmd = create_command(); +add_options($cmd, '-f', '/dev/null', '-E', q!all:;@echo $$PPID!); +my $fout = 'ppidtest.out'; +run_command_with_output($fout, @$cmd); +$_ = read_file_into_string($fout); +chomp($_); +if (/^[0-9]+$/) { +use POSIX (); + +# sv 63157. +# Test that make removes the temporary file which holds make code from stdin, +# even when a signal is received. +# include bye.mk and bye.mk: rule is needed to cause make to keep the temporary +# file for re-exec. Without re-exec make will remove the file before the signal +# arrives. +# sleep is needed to let make write its "... Terminated" message to the log +# file. +&utouch(-600, 'bye.mk'); +close(STDIN); +open(STDIN, "<", 'input.mk') || die "$0: cannot open input.mk for reading: $!"; +run_make_test(q! +include bye.mk +pid:=$(shell echo $$PPID) +all:; +bye.mk: force; @kill -TERM $(pid) && sleep 16 +force: +!, '-f-', '/#MAKE#: \*\*\* \[#MAKEFILE#:5: bye.mk] Terminated/', POSIX::SIGTERM); +} +unlink($fout); + +# sv 62118,62145. +# Test that a stdin temp file is removed, when execvp fails to re-exec make. +# In order to cause execvp to fail, copy the tested make binary to the temp +# directory and take away the 'x' bit. +use File::Spec; +use File::Copy; + +my $tmakedir = File::Spec->catfile($cwdpath, 'tmakedir'); +mkdir($tmakedir, 0770); +my $makecopy = File::Spec->catfile($tmakedir, 'make'); +copy("$mkpath", $makecopy); +# Set file mode bits, because perl copy won't. +chmod 0700, $makecopy; + +my @make_orig = @make_command; +@make_command = ($makecopy); + +# Ensure touching bye.mk causes re-exec. +&utouch(-600, 'bye.mk'); +close(STDIN); +open(STDIN, "<", 'input.mk') || die "$0: cannot open input.mk for reading: $!"; +run_make_test(" +include bye.mk +all:; \$(info hello) +\$(MAKE_RESTARTS)bye.mk: force; touch \$@ && chmod u-x $makecopy +force: +", + "-f-", "touch bye.mk && chmod u-x $makecopy\nmake: $makecopy: $ERR_nonexe_file\n", 32512); + +@make_command = @make_orig; +unlink($makecopy); +rmdir($tmakedir); +} + +close(STDIN); +unlink('input.mk', 'bye.mk'); + +# This tells the test driver that the perl test script executed properly. +1; diff --git a/tests/scripts/features/varnesting b/tests/scripts/features/varnesting index d8f3ffb..0fbb332 100644 --- a/tests/scripts/features/varnesting +++ b/tests/scripts/features/varnesting @@ -9,8 +9,7 @@ variable2 := Hello y = $(subst 1,2,$(x)) z = y a := $($($(z))) -all: - @echo $(a) +all: ; @echo $(a) ', '', "Hello\n"); @@ -21,15 +20,8 @@ all: run_make_test(' VARIABLE = $(eval VARIABLE := echo hi)$(VARIABLE) -wololo: - @$(VARIABLE) +wololo: ; @$(VARIABLE) ', '', "hi\n"); 1; - - - - - - diff --git a/tests/scripts/features/vpath b/tests/scripts/features/vpath index ec24165..7c034b5 100644 --- a/tests/scripts/features/vpath +++ b/tests/scripts/features/vpath @@ -1,65 +1,34 @@ # -*-perl-*- -$description = "The following test creates a makefile to test the \n" - ."vpath directive which allows you to specify a search \n" - ."path for a particular class of filenames, those that\n" - ."match a particular pattern."; - -$details = "This tests the vpath directive by specifying search directories\n" - ."for one class of filenames with the form: vpath pattern directories" - ."\nIn this test, we specify the working directory for all files\n" - ."that end in c or h. We also test the variables $@ (which gives\n" - ."target name) and $^ (which is a list of all dependencies \n" - ."including the directories in which they were found). It also\n" - ."uses the function firstword used to extract just the first\n" - ."dependency from the entire list."; - -open(MAKEFILE,"> $makefile"); - -# The Contents of the MAKEFILE ... - -print MAKEFILE "vpath %.c foo\n"; -print MAKEFILE "vpath %.c $workdir\n"; -print MAKEFILE "vpath %.h $workdir\n"; -print MAKEFILE "objects = main.o kbd.o commands.o display.o insert.o\n"; -print MAKEFILE "edit: \$(objects)\n"; -print MAKEFILE "\t\@echo cc -o \$@ \$^\n"; -print MAKEFILE "main.o : main.c defs.h\n"; -print MAKEFILE "\t\@echo cc -c \$(firstword \$^)\n"; -print MAKEFILE "kbd.o : kbd.c defs.h command.h\n"; -print MAKEFILE "\t\@echo cc -c kbd.c\n"; -print MAKEFILE "commands.o : command.c defs.h command.h\n"; -print MAKEFILE "\t\@echo cc -c commands.c\n"; -print MAKEFILE "display.o : display.c defs.h buffer.h\n"; -print MAKEFILE "\t\@echo cc -c display.c\n"; -print MAKEFILE "insert.o : insert.c defs.h buffer.h\n"; -print MAKEFILE "\t\@echo cc -c insert.c\n"; - -# END of Contents of MAKEFILE - -close(MAKEFILE); +$description = "Test vpath for particular classes of filenames."; +$details = ""; @files_to_touch = ("$workdir${pathsep}main.c","$workdir${pathsep}defs.h", - "$workdir${pathsep}kbd.c","$workdir${pathsep}command.h", - "$workdir${pathsep}commands.c","$workdir${pathsep}display.c", - "$workdir${pathsep}buffer.h","$workdir${pathsep}insert.c", - "$workdir${pathsep}command.c"); + "$workdir${pathsep}kbd.c","$workdir${pathsep}command.h", + "$workdir${pathsep}commands.c","$workdir${pathsep}display.c", + "$workdir${pathsep}buffer.h","$workdir${pathsep}insert.c", + "$workdir${pathsep}command.c"); &touch(@files_to_touch); -&run_make_with_options($makefile,"",&get_logfile); - -# Create the answer to what should be produced by this Makefile -$answer = "cc -c $workdir${pathsep}main.c\ncc -c kbd.c\ncc -c commands.c\n" - ."cc -c display.c\n" - ."cc -c insert.c\ncc -o edit main.o kbd.o commands.o display.o " - ."insert.o\n"; +run_make_test(q! +vpath %.c foo +vpath %.c #WORK# +vpath %.h #WORK# +objects = main.o kbd.o commands.o display.o insert.o +edit: $(objects) ; @echo cc -o $@ $^ +main.o : main.c defs.h ; @echo cc -c $(firstword $^) +kbd.o : kbd.c defs.h command.h ; @echo cc -c kbd.c +commands.o : command.c defs.h command.h ; @echo cc -c commands.c +display.o : display.c defs.h buffer.h ; @echo cc -c display.c +insert.o : insert.c defs.h buffer.h ; @echo cc -c insert.c +!, + '', "cc -c $workdir${pathsep}main.c\ncc -c kbd.c\ncc -c commands.c\n" + ."cc -c display.c\ncc -c insert.c\n" + ."cc -o edit main.o kbd.o commands.o display.o insert.o\n"); -if (&compare_output($answer,&get_logfile(1))) -{ - unlink @files_to_touch; -} +unlink(@files_to_touch); # TEST 2: after vpath lookup ensure we don't get incorrect circular dependency # warnings due to change of struct file ptr. Savannah bug #13529. @@ -78,4 +47,68 @@ vpath-d/fail.te: rmdir('vpath-d'); +# Test VPATH vs vpath + +run_make_test(q! +VPATH = #WORK#:#PWD# +vpath %.c foo +vpath %.c #WORK# +vpath %.c #PWD# +vpath %.h #WORK# +vpath %.c +vpath +all: ; @echo ALL IS WELL +!, + '', "ALL IS WELL\n"); + +# Test interaction of -lfoo and vpath + +my @dirs_to_make = qw(a1 b1 a2 b2 b3); +for my $d (@dirs_to_make) { + mkdir($d, 0777); +} + +my @files_to_touch = ("a1${pathsep}lib1.a", + "a1${pathsep}libc.a", + "b1${pathsep}lib1.so", + "a2${pathsep}lib2.a", + "b2${pathsep}lib2.so", + "lib3.a", + "b3${pathsep}lib3.so"); +&touch(@files_to_touch); + +my $answer = "a1${pathsep}lib1.a a1${pathsep}libc.a " . + "a2${pathsep}lib2.a lib3.a\n"; +if ($port_type eq 'VMS-DCL') { + $answer =~ s/ /,/g; +} + +run_make_test(' +vpath %.h b3 +vpath %.a a1 +vpath %.so b1 +vpath % a2 b2 +vpath % b3 +all: -l1 -lc -l2 -l3; @echo $^ +', + '', $answer); + +unlink(@files_to_touch); +for my $d (@dirs_to_make) { + rmdir($d); +} + +# Check that if we find find files with VPATH, we don't do pattern search + +mkdir("vpa"); + +run_make_test(q! +VPATH = vpa +%.x: ; @echo pattern $@ +vpa/foo.x: ; @echo vpath $@ +!, + 'foo.x', "vpath vpa/foo.x\n"); + +rmdir("vpa"); + 1; diff --git a/tests/scripts/features/vpath2 b/tests/scripts/features/vpath2 deleted file mode 100644 index c8de29b..0000000 --- a/tests/scripts/features/vpath2 +++ /dev/null @@ -1,45 +0,0 @@ -$description = "This is part 2 in a series to test the vpath directive\n" - ."It tests the three forms of the directive:\n" - ." vpath pattern directive\n" - ." vpath pattern (clears path associated with pattern)\n" - ." vpath (clears all paths specified with vpath)\n"; - -$details = "This test simply adds many search paths using various vpath\n" - ."directive forms and clears them afterwards. It has a simple\n" - ."rule to print a message at the end to confirm that the makefile\n" - ."ran with no errors.\n"; - -open(MAKEFILE,"> $makefile"); - -# The Contents of the MAKEFILE ... - -print MAKEFILE "VPATH = $workdir:$scriptdir\n"; -print MAKEFILE "vpath %.c foo\n"; -print MAKEFILE "vpath %.c $workdir\n"; -print MAKEFILE "vpath %.c $scriptdir\n"; -print MAKEFILE "vpath %.h $workdir\n"; -print MAKEFILE "vpath %.c\n"; -print MAKEFILE "vpath\n"; -print MAKEFILE "all:\n"; -print MAKEFILE "\t\@echo ALL IS WELL\n"; -# END of Contents of MAKEFILE - -close(MAKEFILE); - -&run_make_with_options($makefile,"",&get_logfile); - -# Create the answer to what should be produced by this Makefile -$answer = "ALL IS WELL\n"; - -&compare_output($answer,&get_logfile(1)); - -1; - - - - - - - - - diff --git a/tests/scripts/features/vpath3 b/tests/scripts/features/vpath3 deleted file mode 100644 index 839fb72..0000000 --- a/tests/scripts/features/vpath3 +++ /dev/null @@ -1,41 +0,0 @@ -# -*-perl-*- - -$description = "Test the interaction of the -lfoo feature and vpath"; -$details = ""; - -my @dirs_to_make = qw(a1 b1 a2 b2 b3); -for my $d (@dirs_to_make) { - mkdir($d, 0777); -} - -my @files_to_touch = ("a1${pathsep}lib1.a", - "a1${pathsep}libc.a", - "b1${pathsep}lib1.so", - "a2${pathsep}lib2.a", - "b2${pathsep}lib2.so", - "lib3.a", - "b3${pathsep}lib3.so"); -&touch(@files_to_touch); - -my $answer = "a1${pathsep}lib1.a a1${pathsep}libc.a " . - "a2${pathsep}lib2.a lib3.a\n"; -if ($port_type eq 'VMS-DCL') { - $answer =~ s/ /,/g; -} - -run_make_test(' -vpath %.h b3 -vpath %.a a1 -vpath %.so b1 -vpath % a2 b2 -vpath % b3 -all: -l1 -lc -l2 -l3; @echo $^ -', - '', $answer); - -unlink(@files_to_touch); -for my $d (@dirs_to_make) { - rmdir($d); -} - -1; diff --git a/tests/scripts/features/vpathgpath b/tests/scripts/features/vpathgpath index 5e6217b..5c5996c 100644 --- a/tests/scripts/features/vpathgpath +++ b/tests/scripts/features/vpathgpath @@ -40,7 +40,7 @@ close(MAKEFILE); $off = -500; -sub touchfiles { +sub gtouchfiles { foreach (@_) { ($f = $_) =~ s,VP/,$VP,g; &utouch($off, $f); @@ -51,7 +51,7 @@ sub touchfiles { # Run the general-case test -&touchfiles("VP/foo.d", "VP/bar.d", "VP/foo.c", "VP/bar.c", "foo.b", "bar.d"); +>ouchfiles("VP/foo.d", "VP/bar.d", "VP/foo.c", "VP/bar.c", "foo.b", "bar.d"); &run_make_with_options($makefile,"general",&get_logfile()); diff --git a/tests/scripts/features/vpathplus b/tests/scripts/features/vpathplus index 978aecb..da16983 100644 --- a/tests/scripts/features/vpathplus +++ b/tests/scripts/features/vpathplus @@ -5,13 +5,23 @@ $details = ""; $VP = "$workdir$pathsep"; -open(MAKEFILE,"> $makefile"); +@touchedfiles = (); + +$off = -500; -# The Contents of the MAKEFILE ... +sub touchfiles { + foreach (@_) { + &utouch($off, $_); + $off += 10; + push(@touchedfiles, $_); + } +} -print MAKEFILE "VPATH = $VP\n"; +&touchfiles("$VP/foo.d", "$VP/bar.d", "$VP/foo.c", "$VP/bar.c", "foo.b", "bar.d"); -print MAKEFILE <<'EOMAKE'; +# Run the general-case test + +run_make_test(qq!VPATH = $VP! . q! .SUFFIXES: .a .b .c .d .PHONY: general rename notarget intermediate @@ -20,12 +30,9 @@ print MAKEFILE <<'EOMAKE'; %.c: %.d: -%.a : %.b - cat $^ > $@ -%.b : %.c - cat $^ > $@ 2>/dev/null || exit 1 -%.c :: %.d - cat $^ > $@ +%.a : %.b ; cat $^ > $@ +%.b : %.c ; cat $^ > $@ 2>/dev/null || exit 1 +%.c :: %.d ; cat $^ > $@ # General testing info: @@ -39,71 +46,32 @@ rename: $(VPATH)/foo.c foo.d # Target not made testing info: notarget: notarget.b -notarget.c: notarget.d - -@echo "not creating $@ from $^" +notarget.c: notarget.d ; -@echo "not creating $@ from $^" # Intermediate files: intermediate: inter.a - -EOMAKE - -close(MAKEFILE); - -@touchedfiles = (); - -$off = -500; - -sub touchfiles { - foreach (@_) { - &utouch($off, $_); - $off += 10; - push(@touchedfiles, $_); - } -} - -# Run the general-case test - -&touchfiles("$VP/foo.d", "$VP/bar.d", "$VP/foo.c", "$VP/bar.c", "foo.b", "bar.d"); - -&run_make_with_options($makefile,"general",&get_logfile); +!, + 'general', "cat bar.d > bar.c\ncat ${VP}foo.c bar.c > foo.b 2>/dev/null || exit 1\n"); push(@touchedfiles, "bar.c"); -$answer = "cat bar.d > bar.c -cat ${VP}foo.c bar.c > foo.b 2>/dev/null || exit 1 -"; -&compare_output($answer,&get_logfile(1)); - # Test rules that don't make the target correctly &touchfiles("$VP/notarget.c", "notarget.b", "notarget.d"); -&run_make_with_options($makefile,"notarget",&get_logfile,512); - -$answer = "not creating notarget.c from notarget.d -cat notarget.c > notarget.b 2>/dev/null || exit 1 -$make_name: *** [$makefile:13: notarget.b] Error 1 -"; - -&compare_output($answer,&get_logfile(1)); +run_make_test(undef, 'notarget', "not creating notarget.c from notarget.d\ncat notarget.c > notarget.b 2>/dev/null || exit 1\n#MAKE#: *** [#MAKEFILE#:11: notarget.b] Error 1\n", 512); # Test intermediate file handling (part 1) &touchfiles("$VP/inter.d"); -&run_make_with_options($makefile,"intermediate",&get_logfile); - -push(@touchedfiles, "inter.a", "inter.b"); - my $be = pack("L", 1) eq pack("N", 1); my $intfiles = $be ? "inter.c inter.b" : "inter.b inter.c"; -$answer = "cat ${VP}inter.d > inter.c -cat inter.c > inter.b 2>/dev/null || exit 1 -cat inter.b > inter.a -rm $intfiles -"; -&compare_output($answer,&get_logfile(1)); + +run_make_test(undef, 'intermediate', "cat ${VP}inter.d > inter.c\ncat inter.c > inter.b 2>/dev/null || exit 1\ncat inter.b > inter.a\nrm $intfiles\n"); + +push(@touchedfiles, "inter.a", "inter.b"); # Test intermediate file handling (part 2) @@ -111,21 +79,10 @@ rm $intfiles &utouch(-10, "$VP/inter.b"); &touch("$VP/inter.d"); -push(@touchedfiles, "$VP/inter.b", "$VP/inter.d"); - -&run_make_with_options($makefile,"intermediate",&get_logfile); +run_make_test(undef, 'intermediate', "cat ${VP}inter.d > inter.c\ncat inter.c > inter.b 2>/dev/null || exit 1\ncat inter.b > inter.a\nrm inter.c\n"); -$answer = "cat ${VP}inter.d > inter.c -cat inter.c > inter.b 2>/dev/null || exit 1 -cat inter.b > inter.a -rm inter.c -"; -&compare_output($answer,&get_logfile(1)); +push(@touchedfiles, "$VP/inter.b", "$VP/inter.d"); unlink @touchedfiles unless $keep; 1; - -### Local Variables: -### eval: (setq whitespace-action (delq 'auto-cleanup whitespace-action)) -### End: |