mirror of
https://github.com/mirror/make.git
synced 2025-03-03 22:30:59 +08:00
[SV 60435] Ensure intermediate grouped files are removed
If multiple intermediate files are built together be sure all of them are removed after make is finished. Continue to ensure that targets that exist before make starts are not removed even if they appear to be intermediate. Add a number of tests to pattern rules to verify this behavior. * src/filedef.h (struct file): Add a new is_explicit bitfield. * src/file.c (rehash_file): Merge the is_explicit bit. (enter_prereqs): Set is_explicit if the file is explicitly mentioned. * src/implicit.c (pattern_search): Set intermediate on the file if it's not explicit. (record_files): Set is_explicit if a file is mentioned as a target. * src/remake.c (update_file_1): Set secondary on files that already exist so they won't be removed. * tests/scripts/features/double_colon: Add a test for double-colon pattern rules. * tests/scripts/features/patternrules: Update KGO for tests where more files are removed. Add new tests to verify handling removal of intermediate files in the context of grouped pattern targets.
This commit is contained in:
parent
5a96d5a066
commit
9e4b3d3f4c
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user