[SV 60188] Explicit prereqs cannot be intermediate files

If a prereq of a pattern is an explicit target, it should not be
considered an intermediate file.

(Minor tweaks by Paul Smith <psmith@gnu.org>)

* src/dep.h (struct nameseq): Add is_explicit flag.
* src/implicit.c (struct patdeps): Ditto.
(pattern_search): Set the is_explicit flag appropriately for each
prerequisite, based on whether it contained a pattern or not.
Update the help output to note implicit vs. explicit prereqs.
* tests/scripts/features/double_colon: Add tests.
* tests/scripts/features/grouped_targets: Ditto.
* tests/scripts/features/patternrules: Ditto.
* tests/scripts/features/se_implicit: Ditto.
* tests/scripts/features/statipattrules: Ditto.
This commit is contained in:
Dmitry Goncharov 2021-03-15 02:10:49 -04:00 committed by Paul Smith
parent 144f436c4b
commit 510e5ce801
7 changed files with 233 additions and 6 deletions

View file

@ -38,7 +38,10 @@ struct nameseq
/* Structure representing one dependency of a file.
Each struct file's 'deps' points to a chain of these, through 'next'.
'stem' is the stem for this dep line of static pattern rule or NULL. */
'stem' is the stem for this dep line of static pattern rule or NULL.
explicit is set when implicit rule search is performed and the prerequisite
does not contain %. When explicit is set the file is not intermediate. */
#define DEP(_t) \
NAMESEQ (_t); \
@ -49,7 +52,8 @@ struct nameseq
unsigned int ignore_mtime : 1; \
unsigned int staticpattern : 1; \
unsigned int need_2nd_expansion : 1; \
unsigned int ignore_automatic_vars : 1
unsigned int ignore_automatic_vars : 1; \
unsigned int is_explicit : 1;
struct dep
{

View file

@ -153,6 +153,7 @@ struct patdeps
struct file *file;
unsigned int ignore_mtime : 1;
unsigned int ignore_automatic_vars : 1;
unsigned int is_explicit : 1;
};
/* This structure stores information about pattern rules that we need
@ -540,6 +541,7 @@ pattern_search (struct file *file, int archive,
/* If we don't need a second expansion, just replace the %. */
if (! dep->need_2nd_expansion)
{
int is_explicit = 1;
p = strchr (nptr, '%');
if (p == 0)
strcpy (depname, nptr);
@ -556,6 +558,7 @@ pattern_search (struct file *file, int archive,
memcpy (o, stem, stemlen);
o += stemlen;
strcpy (o, p + 1);
is_explicit = 0;
}
/* Parse the expanded string. It might have wildcards. */
@ -566,6 +569,7 @@ pattern_search (struct file *file, int archive,
++deps_found;
d->ignore_mtime = dep->ignore_mtime;
d->ignore_automatic_vars = dep->ignore_automatic_vars;
d->is_explicit = is_explicit;
}
/* We've used up this dep, so next time get a new one. */
@ -586,6 +590,7 @@ pattern_search (struct file *file, int archive,
int add_dir = 0;
size_t len;
struct dep **dptr;
int is_explicit;
nptr = get_next_word (nptr, &len);
if (nptr == 0)
@ -615,6 +620,7 @@ pattern_search (struct file *file, int archive,
{
memcpy (depname, nptr, len);
depname[len] = '\0';
is_explicit = 1;
}
else
{
@ -635,6 +641,7 @@ pattern_search (struct file *file, int archive,
}
memcpy (o, p + 1, len - i - 1);
o[len - i - 1] = '\0';
is_explicit = 0;
}
/* Set up for the next word. */
@ -674,6 +681,7 @@ pattern_search (struct file *file, int archive,
++deps_found;
if (order_only)
d->ignore_mtime = 1;
d->is_explicit = is_explicit;
dptr = &d->next;
}
@ -726,6 +734,7 @@ pattern_search (struct file *file, int archive,
memset (pat, '\0', sizeof (struct patdeps));
pat->ignore_mtime = d->ignore_mtime;
pat->ignore_automatic_vars = d->ignore_automatic_vars;
pat->is_explicit = d->is_explicit;
DBS (DB_IMPLICIT,
(is_rule
@ -777,13 +786,14 @@ pattern_search (struct file *file, int archive,
}
/* We could not find the file in any place we should look.
Try to make this dependency as an intermediate file, but
Look for an implicit rule to make this dependency, but
only on the second pass. */
if (intermed_ok)
{
DBS (DB_IMPLICIT,
(_("Looking for a rule with intermediate file '%s'.\n"),
(_("Looking for a rule with %s file '%s'.\n"),
d->is_explicit ? "explicit" : "intermediate",
d->name));
if (int_file == 0)
@ -899,7 +909,7 @@ pattern_search (struct file *file, int archive,
f->pat_searched = imf->pat_searched;
f->also_make = imf->also_make;
f->is_target = 1;
f->intermediate = 1;
f->intermediate = !pat->is_explicit;
f->tried_implicit = 1;
imf = lookup_file (pat->pattern);
@ -916,6 +926,7 @@ pattern_search (struct file *file, int archive,
dep = alloc_dep ();
dep->ignore_mtime = pat->ignore_mtime;
dep->is_explicit = pat->is_explicit;
dep->ignore_automatic_vars = pat->ignore_automatic_vars;
s = strcache_add (pat->name);
if (recursions)

View file

@ -212,6 +212,21 @@ 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');
run_make_test(q!
all: hello.z
%.z:: test.x ; touch $@
%.x: ;
!, '', "#MAKE#: Nothing to be done for 'all'.\n");
unlink('hello.z');
# This tells the test driver that the perl test script executed properly.
1;

View file

@ -129,5 +129,31 @@ 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");
unlink('hello.z');
unlink('hello.q');
# This tells the test driver that the perl test script executed properly.
1;

View file

@ -18,7 +18,7 @@ $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
@ -43,6 +43,13 @@ all: case.1 case.2 case.3
@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
@ -244,6 +251,86 @@ run_make_test(q!
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');
unlink('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");
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');
unlink('test.x');
# This tells the test driver that the perl test script executed properly.
1;

View file

@ -262,5 +262,68 @@ 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");
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');
# This tells the test driver that the perl test script executed properly.
1;

View file

@ -108,4 +108,25 @@ 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: test.x ; @echo $@
%.x: ;
!, '', "hello.z\n");
unlink('hello.z');
1;