diff --git a/doc/make.texi b/doc/make.texi index 627d4f14..4470386d 100644 --- a/doc/make.texi +++ b/doc/make.texi @@ -10024,12 +10024,12 @@ either, unless there is some other reason to update that target: for example the target doesn't exist or a different prerequisite is newer than the target. -The second difference is that if @code{make} @emph{does} create @var{b} -in order to update something else, it deletes @var{b} later on after it -is no longer needed. Therefore, an intermediate file which did not -exist before @code{make} also does not exist after @code{make}. -@code{make} reports the deletion to you by printing a @samp{rm -f} -command showing which file it is deleting. +The second difference is that if @code{make} @emph{does} create @var{b} in +order to update something else, it deletes @var{b} later on after it is no +longer needed. Therefore, an intermediate file which did not exist before +@code{make} also does not exist after @code{make}. @code{make} reports the +deletion to you by printing a @samp{rm} command showing which file it is +deleting. Ordinarily, a file cannot be intermediate if it is mentioned in the makefile as a target or prerequisite. However, you can explicitly mark a diff --git a/src/file.c b/src/file.c index 80696b8e..27be8b6c 100644 --- a/src/file.c +++ b/src/file.c @@ -338,6 +338,7 @@ rehash_file (struct file *from_file, const char *to_hname) MERGE (cmd_target); MERGE (phony); /* Don't merge intermediate because this file might be pre-existing */ + MERGE (is_explicit); MERGE (secondary); MERGE (notintermediate); MERGE (ignore_vpath); @@ -556,6 +557,9 @@ enter_prereqs (struct dep *deps, const char *stem) d1->file = enter_file (d1->name); d1->staticpattern = 0; d1->name = 0; + if (!stem) + /* This file is explicitly mentioned as a prereq. */ + d1->file->is_explicit = 1; } return deps; diff --git a/src/filedef.h b/src/filedef.h index 36701b76..0b9f6e17 100644 --- a/src/filedef.h +++ b/src/filedef.h @@ -96,6 +96,7 @@ struct file unsigned int phony:1; /* Nonzero if this is a phony file i.e., a prerequisite of .PHONY. */ unsigned int intermediate:1;/* Nonzero if this is an intermediate file. */ + unsigned int is_explicit:1; /* Nonzero if explicitly mentioned. */ unsigned int secondary:1; /* Nonzero means remove_intermediates should not delete it. */ unsigned int notintermediate:1; /* Nonzero means a file is a prereq to diff --git a/src/implicit.c b/src/implicit.c index dec61428..3c7fba76 100644 --- a/src/implicit.c +++ b/src/implicit.c @@ -713,6 +713,7 @@ pattern_search (struct file *file, int archive, for (d = dl; d != 0; d = d->next) { struct dep *expl_d; + struct file *f; int is_rule = d->name == dep_name (dep); if (file_impossible_p (d->name)) @@ -754,6 +755,13 @@ pattern_search (struct file *file, int archive, continue; } + /* f->is_explicit is set when this file is mentioned + explicitly on some other rule. d->is_explicit is set when + this file is mentioned explicitly on this rule. */ + f = lookup_file (d->name); + if (f && !f->is_explicit && !d->is_explicit) + f->intermediate = 1; + /* The DEP->changed flag says that this dependency resides in a nonexistent directory. So we normally can skip looking for the file. However, if CHECK_LASTSLASH is @@ -762,8 +770,7 @@ pattern_search (struct file *file, int archive, FILENAME's directory), so it might actually exist. */ /* @@ dep->changed check is disabled. */ - if (lookup_file (d->name) != 0 - /*|| ((!dep->changed || check_lastslash) && */ + if (f /* || ((!dep->changed || check_lastslash) */ || file_exists_p (d->name)) { (pat++)->name = d->name; diff --git a/src/read.c b/src/read.c index 1db51cfa..77bbdb5e 100644 --- a/src/read.c +++ b/src/read.c @@ -2164,6 +2164,11 @@ record_files (struct nameseq *filenames, int are_also_makes, free_dep_chain (f->deps); f->deps = 0; } + /* This file is explicitly mentioned as a target. There is no need + to set is_explicit in the case of double colon below, because an + implicit double colon rule only applies when the prerequisite + exists. A prerequisite which exists is not intermediate anyway. */ + f->is_explicit = 1; } else { diff --git a/src/remake.c b/src/remake.c index b20d37c7..9b71ce61 100644 --- a/src/remake.c +++ b/src/remake.c @@ -812,6 +812,10 @@ update_file_1 (struct file *file, unsigned int depth) fflush (stdout); } + /* Since make has not created this file, make should not remove it, + even if the file is intermediate. */ + file->secondary = 1; + notice_finished_file (file); /* Since we don't need to remake the file, convert it to use the diff --git a/tests/scripts/features/double_colon b/tests/scripts/features/double_colon index cd51ea4f..b5b73f70 100644 --- a/tests/scripts/features/double_colon +++ b/tests/scripts/features/double_colon @@ -217,14 +217,27 @@ unlink('joe-is-forced'); # 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"); +!, + '', "#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'); # This tells the test driver that the perl test script executed properly. diff --git a/tests/scripts/features/patternrules b/tests/scripts/features/patternrules index ded8e0db..25a80e78 100644 --- a/tests/scripts/features/patternrules +++ b/tests/scripts/features/patternrules @@ -24,33 +24,26 @@ all: case.1 case.2 case.3 case.4 #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 +%.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). @@ -62,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 @@ -82,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"); @@ -116,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"); @@ -130,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'); @@ -158,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 ', @@ -222,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 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 @@ -241,13 +210,39 @@ 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'); @@ -257,26 +252,25 @@ unlink('some file.xx', 'some file.yy'); # rule is not considered intermediate. touch('hello.z'); -unlink('hello.x'); -unlink('test.x'); +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 $@ +%.z: %.x ; touch $@ %.x: ; -!, '', "#MAKE#: Nothing to be done for 'all'.\n"); +!, + '', "#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 $@ +%.z: %.x test.x ; touch $@ %.x: ; -!, '', "touch hello.z"); +!, + '', "touch hello.z"); unlink('hello.z'); @@ -294,7 +288,8 @@ run_make_test(q! all: hello.tsk %.tsk: %.z ; @echo $@ %.z : %.x ; @echo $@ -!, '', "#MAKE#: Nothing to be done for 'all'.\n"); +!, + '', "#MAKE#: Nothing to be done for 'all'.\n"); # subtest 2 # test.z is explicitly mentioned and thus is not an intermediate file. @@ -304,7 +299,8 @@ run_make_test(q! all: hello.tsk %.tsk: %.z test.z ; @echo $@ %.z : %.x ; @echo $@ -!, '', "test.z\nhello.z\nhello.tsk\n"); +!, + '', "test.z\nhello.z\nhello.tsk\n"); # subtest 3 # hello.o is not explicitly mentioned and thus is an intermediate file. @@ -312,7 +308,8 @@ run_make_test(q! all: hello.tsk dep:=%.o %.tsk: $(dep) ; @echo $@ -!, '', "#MAKE#: Nothing to be done for 'all'.\n"); +!, + '', "#MAKE#: Nothing to be done for 'all'.\n"); # subtest 4 # Even when test.z is constructed from 2 variables it is still explicitly @@ -325,15 +322,127 @@ name:=test suf:=.z %.tsk: %.z $(name)$(suf) ; @echo $@ %.z: %.x ; @echo $@ -!, '', "test.z\nhello.z\nhello.tsk\n"); +!, + '', "test.z\nhello.z\nhello.tsk\n"); -unlink('hello.x'); -unlink('test.x'); +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 %.2 ; cat $^ >$@ +%.1 %.2: ; touch $*.1 $*.2 +!, + '', "touch a.1 a.2\ncat a.1 a.2 >a.4\nrm a.1 a.2"); + +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 %.2 a.3 ; cat $^ >$@ +%.1 %.2: ; touch $*.1 $*.2 +%.3: ; touch $@ +!, + '', "touch a.3\ntouch a.1 a.2\ncat a.1 a.2 a.3 >a.4\nrm a.1 a.2"); + +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 %.2 a.3 ; cat $^ >$@ +%.1 %.2 %.3: ; touch $*.1 $*.2 $*.3 +!, + '', "touch a.1 a.2 a.3\ncat a.1 a.2 a.3 >a.4\nrm a.1 a.2"); + +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 %.2 a.3 ; cat $^ >$@ +%.3 %.1 %.2: ; touch $*.1 $*.2 $*.3 +!, + '', "touch a.1 a.2 a.3\ncat a.1 a.2 a.3 >a.4\nrm a.1 a.2"); + +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 %.2 ; cat $^ >$@ +%.1 %.2 %.3: ; touch $*.1 $*.2 $*.3 +!, + '', "touch a.1 a.2 a.3\ncat a.3 a.1 a.2 >a.4\nrm a.1 a.2"); + +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'); # 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: