[SV 62706] Only second-expand targets that might be built

Second-expand only the prerequisites of the targets being built.
Defer second-expanding the prerequisites of targets until we need
to decide if they should be built.

* NEWS: Mention the change in behavior.
* doc/make.texi (Secondary Expansion): Document the new behavior.
* src/filedef.h (struct file): Add flag snapped.
(expand_deps): Declare a function to second expand the
prerequisites of a target.
* src/file.c (rehash_file): Merge flag snapped.
(expand_deps): Remove qualifier static. Check flag snapped.
(snap_deps): Remove the loop which performed second expansion for all
targets.
* src/remake.c (update_file_1): Second expand the prerequisites of
the considered target.
* tests/scripts/features/se_explicit: Add tests.
* tests/scripts/features/se_implicit: Ditto.
* tests/scripts/features/se_statpat: Ditto.
This commit is contained in:
Dmitry Goncharov 2022-07-24 18:16:50 -04:00 committed by Paul Smith
parent 16e14b4114
commit 07eea3aa49
8 changed files with 430 additions and 57 deletions

5
NEWS
View file

@ -83,6 +83,11 @@ https://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=109&se
mentioned in other targets as "ought to exist".
Implementation provided by Dmitry Goncharov <dgoncharov@users.sf.net>
* GNU make was performing secondary expansion of all targets, even targets
which didn't need to be considered during the build. In this release
only targets which are considered will be secondarily expanded.
Implementation provided by Dmitry Goncharov <dgoncharov@users.sf.net>
* If the MAKEFLAGS variable is modified in a makefile, it will be re-parsed
immediately rather than after all makefiles have been read. Note that
although all options are parsed immediately, some special effects won't

View file

@ -1703,18 +1703,16 @@ this second expansion to occur, the special target
@code{.SECONDEXPANSION} must be defined before the first prerequisite
list that makes use of this feature.
If that special target is defined then in between the two phases
mentioned above, right at the end of the read-in phase, all the
prerequisites of the targets defined after the special target are
expanded a @emph{second time}. In most circumstances this secondary
expansion will have no effect, since all variable and function
references will have been expanded during the initial parsing of the
makefiles. In order to take advantage of the secondary expansion
phase of the parser, then, it's necessary to @emph{escape} the
variable or function reference in the makefile. In this case the
first expansion merely un-escapes the reference but doesn't expand it,
and expansion is left to the secondary expansion phase. For example,
consider this makefile:
If @code{.SECONDEXPANSION} is defined then when GNU @code{make} needs to check
the prerequisites of a target, the prerequisites are expanded a @emph{second
time}. In most circumstances this secondary expansion will have no effect,
since all variable and function references will have been expanded during the
initial parsing of the makefiles. In order to take advantage of the secondary
expansion phase of the parser, then, it's necessary to @emph{escape} the
variable or function reference in the makefile. In this case the first
expansion merely un-escapes the reference but doesn't expand it, and expansion
is left to the secondary expansion phase. For example, consider this
makefile:
@example
.SECONDEXPANSION:

View file

@ -342,6 +342,7 @@ rehash_file (struct file *from_file, const char *to_hname)
MERGE (secondary);
MERGE (notintermediate);
MERGE (ignore_vpath);
MERGE (snapped);
#undef MERGE
to_file->builtin = 0;
@ -565,8 +566,10 @@ enter_prereqs (struct dep *deps, const char *stem)
return deps;
}
/* Expand and parse each dependency line. */
static void
/* Expand and parse each dependency line.
For each dependency of the file, make the 'struct dep' point
at the appropriate 'struct file' (which may have to be created). */
void
expand_deps (struct file *f)
{
struct dep *d;
@ -574,7 +577,9 @@ expand_deps (struct file *f)
const char *fstem;
int initialized = 0;
f->updating = 0;
if (f->snapped)
return;
f->snapped = 1;
/* Walk through the dependencies. For any dependency that needs 2nd
expansion, expand it then insert the result into the list. */
@ -646,6 +651,7 @@ expand_deps (struct file *f)
set_file_variables (f, d->stem ? d->stem : f->stem);
/* Perform second expansion. */
p = variable_expand_for_file (d->name, f);
/* Free the un-expanded name. */
@ -758,10 +764,7 @@ snap_file (const void *item, void *arg)
}
}
/* For each dependency of each file, make the 'struct dep' point
at the appropriate 'struct file' (which may have to be created).
Also mark the files depended on by .PRECIOUS, .PHONY, .SILENT,
/* Mark the files depended on by .PRECIOUS, .PHONY, .SILENT,
and various other special targets. */
void
@ -775,37 +778,6 @@ snap_deps (void)
longer define new targets. */
snapped_deps = 1;
/* Perform second expansion and enter each dependency name as a file. We
must use hash_dump() here because within these loops we likely add new
files to the table, possibly causing an in-situ table expansion.
We only need to do this if second_expansion has been defined; if it
hasn't then all deps were expanded as the makefile was read in. If we
ever change make to be able to unset .SECONDARY_EXPANSION this will have
to change. */
if (second_expansion)
{
struct file **file_slot_0 = (struct file **) hash_dump (&files, 0, 0);
struct file **file_end = file_slot_0 + files.ht_fill;
struct file **file_slot;
const char *suffixes;
/* Expand .SUFFIXES: its prerequisites are used for $$* calc. */
f = lookup_file (".SUFFIXES");
suffixes = f ? f->name : 0;
for (; f != 0; f = f->prev)
expand_deps (f);
/* For every target that's not .SUFFIXES, expand its prerequisites. */
for (file_slot = file_slot_0; file_slot < file_end; file_slot++)
for (f = *file_slot; f != 0; f = f->prev)
if (f->name != suffixes)
expand_deps (f);
free (file_slot_0);
}
/* Now manage all the special targets. */
for (f = lookup_file (".PRECIOUS"); f != 0; f = f->prev)

View file

@ -110,6 +110,8 @@ struct file
diagnostics has been issued (dontcare). */
unsigned int was_shuffled:1; /* Did we already shuffle 'deps'? used when
--shuffle passes through the graph. */
unsigned int snapped:1; /* True if the deps of this file have been
secondary expanded. */
};
@ -120,6 +122,7 @@ struct file *lookup_file (const char *name);
struct file *enter_file (const char *name);
struct dep *split_prereqs (char *prereqstr);
struct dep *enter_prereqs (struct dep *prereqs, const char *stem);
void expand_deps (struct file *f);
struct dep *expand_extra_prereqs (const struct variable *extra);
void remove_intermediates (int sig);
void snap_deps (void);

View file

@ -532,6 +532,12 @@ update_file_1 (struct file *file, unsigned int depth)
{
struct dep *lastd = 0;
/* Perform second expansion and enter each dependency name as a file.
We only need to do this if second_expansion has been defined; if it
hasn't then all deps were expanded as the makefile was read in. */
if (second_expansion)
expand_deps (ad->file);
/* Find the deps we're scanning */
du = ad->file->deps;
ad = ad->next;
@ -1089,6 +1095,12 @@ check_dep (struct file *file, unsigned int depth,
}
ld = 0;
/* Perform second expansion and enter each dependency name as a file.
We only need to do this if second_expansion has been defined; if it
hasn't then all deps were expanded as the makefile was read in. */
if (second_expansion)
expand_deps (file);
d = file->deps;
while (d != 0)
{

View file

@ -299,4 +299,207 @@ 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:; cp hello.1 $@
unrelated: $$(shell touch hello.1);
!, '',
"cp hello.1 hello.tsk
cp: cannot stat 'hello.1': $ERR_no_such_file
#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;

View file

@ -292,8 +292,11 @@ all: hello.z
!, '', "hello.z\n");
# subtest 3.
# hello.x is explicitly mentioned on an unrelated rule and thus is not an
# intermediate file.
# 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
@ -301,7 +304,19 @@ all: hello.z
%.z: %.x; @echo $@
%.x: ;
unrelated: $$(dep)
!, '', "hello.z\n");
!, '', "#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');
@ -442,5 +457,51 @@ 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; cp hello.1 $@
hello.o:;
%.q: $$(shell touch hello.1);
!, '',
"cp hello.1 hello.tsk
cp: cannot stat 'hello.1': $ERR_no_such_file
#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;

View file

@ -91,11 +91,9 @@ 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
@ -110,5 +108,126 @@ 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; cp hello.1 $@
hello.o:;
bye.tsk: %.tsk: $$(shell touch hello.1);
!, '',
"cp hello.1 hello.tsk
cp: cannot stat 'hello.1': $ERR_no_such_file
#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;