https://www.gnu.org/software/gnulib/manual/html_node/C99-features-assumed.html
The configure script should verify the compiler has these features.
+* New feature: The .NOTINTERMEDIATE special target
+ .NOTINTERMEDIATE Disables intermediate behavior for specific files, for all
+ files built using a pattern, or for the entire makefile.
+ Implementation provided by Dmitry Goncharov <dgoncharov@users.sf.net>
+
* New feature: The $(let ...) function
This function allows user-defined functions to define a set of local
variables: values can be assigned to these variables from within the
intermediate files. @xref{Chained Rules, ,Chains of Implicit Rules}.
@code{.INTERMEDIATE} with no prerequisites has no effect.
+@findex .NOTINTERMEDIATE
+@item .NOTINTERMEDIATE
+@cindex notintermediate targets, explicit
+
+Prerequisites of the special target @code{.NOTINTERMEDIATE} are never
+considered intermediate files. @xref{Chained Rules, ,Chains of Implicit Rules}.
+@code{.NOTINTERMEDIATE} with no prerequisites causes all targets to be treated
+as notintermediate.
+
+If the prerequisite is a target pattern then targets that are built using that
+pattern rule are not considered intermediate.
+
@findex .SECONDARY
@item .SECONDARY
@cindex secondary targets
@code{.INTERMEDIATE}. This takes effect even if the file is mentioned
explicitly in some other way.
+Listing a file as a prerequisite of the special target
+@code{.NOTINTERMEDIATE} forces it to not be considered intermediate
+(just as any other mention of the file will do). Also, listing the
+target pattern of a pattern rule as a prerequisite of
+@code{.NOTINTERMEDIATE} ensures that no targets generated using that
+pattern rule are considered intermediate.
+
+You can disable intermediate files completely in your makefile by
+providing @code{.NOTINTERMEDIATE} as a target with no prerequisites:
+in that case it applies to every file in the makefile.
+
@cindex intermediate files, preserving
@cindex preserving intermediate files
@cindex secondary files
-You can prevent automatic deletion of an intermediate file by marking it
-as a @dfn{secondary} file. To do this, list it as a prerequisite of the
-special target @code{.SECONDARY}. When a file is secondary, @code{make}
-will not create the file merely because it does not already exist, but
-@code{make} does not automatically delete the file. Marking a file as
-secondary also marks it as intermediate.
-
-You can list the target pattern of an implicit rule (such as @samp{%.o})
-as a prerequisite of the special target @code{.PRECIOUS} to preserve
-intermediate files made by implicit rules whose target patterns match
-that file's name; see @ref{Interrupts}.@refill
-@cindex preserving with @code{.PRECIOUS}
-@cindex @code{.PRECIOUS} intermediate files
+If you do not want @code{make} to create a file merely because it does
+not already exist, but you also do not want @code{make} to
+automatically delete the file, you can mark it as a @dfn{secondary}
+file. To do this, list it as a prerequisite of the special target
+@code{.SECONDARY}. Marking a file as secondary also marks it as
+intermediate.
A chain can involve more than two implicit rules. For example, it is
possible to make a file @file{foo} from @file{RCS/foo.y,v} by running RCS,
/* Whether or not .SECONDARY with no prerequisites was given. */
static int all_secondary = 0;
+/* Whether or not .NOTINTERMEDIATE with no prerequisites was given. */
+static int no_intermediates = 0;
+
/* Access the hash table of all file records.
lookup_file given a name, return the struct file * for that name,
or nil if there is none.
#define MERGE(field) to_file->field |= from_file->field
MERGE (precious);
+ MERGE (loaded);
MERGE (tried_implicit);
MERGE (updating);
MERGE (updated);
MERGE (is_target);
MERGE (cmd_target);
MERGE (phony);
- MERGE (loaded);
+ /* Don't merge intermediate because this file might be pre-existing */
+ MERGE (secondary);
+ MERGE (notintermediate);
MERGE (ignore_vpath);
#undef MERGE
given on the command line, and it's either a -include makefile or
it's not precious. */
if (f->intermediate && (f->dontcare || !f->precious)
- && !f->secondary && !f->cmd_target)
+ && !f->secondary && !f->notintermediate && !f->cmd_target)
{
int status;
if (f->update_status == us_none)
if (!second_expansion)
f->updating = 0;
- /* If .SECONDARY is set with no deps, mark all targets as intermediate. */
- if (all_secondary)
+ /* More specific setting has priority. */
+
+ /* If .SECONDARY is set with no deps, mark all targets as intermediate,
+ unless the target is a prereq of .NOTINTERMEDIATE. */
+ if (all_secondary && !f->notintermediate)
f->intermediate = 1;
+ /* If .NOTINTERMEDIATE is set with no deps, mark all targets as
+ notintermediate, unless the target is a prereq of .INTERMEDIATE. */
+ if (no_intermediates && !f->intermediate && !f->secondary)
+ f->notintermediate = 1;
+
/* If .EXTRA_PREREQS is set, add them as ignored by automatic variables. */
if (f->variables)
prereqs = expand_extra_prereqs (lookup_variable_in_set (STRING_SIZE_TUPLE(".EXTRA_PREREQS"), f->variables->set));
f2->mtime_before_update = NONEXISTENT_MTIME;
}
+ for (f = lookup_file (".NOTINTERMEDIATE"); f != 0; f = f->prev)
+ /* Mark .NOTINTERMEDIATE deps as notintermediate files. */
+ if (f->deps)
+ for (d = f->deps; d != 0; d = d->next)
+ for (f2 = d->file; f2 != 0; f2 = f2->prev)
+ f2->notintermediate = 1;
+ /* .NOTINTERMEDIATE with no deps marks all files as notintermediate. */
+ else
+ no_intermediates = 1;
+
+ /* The same file connot be both .INTERMEDIATE and .NOTINTERMEDIATE.
+ However, it is possible for a file to be .INTERMEDIATE and also match a
+ .NOTINTERMEDIATE pattern. In that case, the intermediate file has
+ priority over the notintermediate pattern. This priority is enforced by
+ pattern_search. */
+
for (f = lookup_file (".INTERMEDIATE"); f != 0; f = f->prev)
/* Mark .INTERMEDIATE deps as intermediate files. */
for (d = f->deps; d != 0; d = d->next)
for (f2 = d->file; f2 != 0; f2 = f2->prev)
- f2->intermediate = 1;
+ if (f2->notintermediate)
+ OS (fatal, NILF,
+ _("%s cannot be both .NOTINTERMEDIATE and .INTERMEDIATE."),
+ f2->name);
+ else
+ f2->intermediate = 1;
/* .INTERMEDIATE with no deps does nothing.
Marking all files as intermediates is useless since the goal targets
would be deleted after they are built. */
if (f->deps)
for (d = f->deps; d != 0; d = d->next)
for (f2 = d->file; f2 != 0; f2 = f2->prev)
+ if (f2->notintermediate)
+ OS (fatal, NILF,
+ _("%s cannot be both .NOTINTERMEDIATE and .SECONDARY."),
+ f2->name);
+ else
f2->intermediate = f2->secondary = 1;
/* .SECONDARY with no deps listed marks *all* files that way. */
else
all_secondary = 1;
+ if (no_intermediates && all_secondary)
+ O (fatal, NILF,
+ _(".NOTINTERMEDIATE and .SECONDARY are mutually exclusive"));
+
f = lookup_file (".EXPORT_ALL_VARIABLES");
if (f != 0 && f->is_target)
export_all_variables = 1;
printf (_("# Implicit/static pattern stem: '%s'\n"), f->stem);
if (f->intermediate)
puts (_("# File is an intermediate prerequisite."));
+ if (f->notintermediate)
+ puts (_("# File is a prerequisite of .NOTINTERMEDIATE."));
+ if (f->secondary)
+ puts (_("# File is secondary (prerequisite of .SECONDARY)."));
if (f->also_make != 0)
{
const struct dep *d;
unsigned int intermediate:1;/* Nonzero if this is an intermediate file. */
unsigned int secondary:1; /* Nonzero means remove_intermediates should
not delete it. */
+ unsigned int notintermediate:1; /* Nonzero means a file is a prereq to
+ .NOTINTERMEDIATE. */
unsigned int dontcare:1; /* Nonzero if no complaint is to be made if
this target cannot be remade. */
unsigned int ignore_vpath:1;/* Nonzero if we threw out VPATH name. */
f->pat_searched = imf->pat_searched;
f->also_make = imf->also_make;
f->is_target = 1;
- f->intermediate = !pat->is_explicit;
+ f->notintermediate = imf->notintermediate;
+ f->intermediate = !(pat->is_explicit || f->notintermediate);
f->tried_implicit = 1;
imf = lookup_file (pat->pattern);
file->cmds = rule->cmds;
file->is_target = 1;
- /* Set precious flag. */
+ /* Set precious and notintermediate flags. */
{
struct file *f = lookup_file (rule->targets[tryrules[foundrule].matches]);
- if (f && f->precious)
- file->precious = 1;
+ if (f)
+ {
+ if (f->precious)
+ file->precious = 1;
+ if (f->notintermediate)
+ file->notintermediate = 1;
+ }
}
/* If this rule builds other targets, too, put the others into FILE's
/* Set precious flag. */
f = lookup_file (rule->targets[ri]);
- if (f && f->precious)
- new->file->precious = 1;
+ if (f)
+ {
+ if (f->precious)
+ new->file->precious = 1;
+ if (f->notintermediate)
+ new->file->notintermediate = 1;
+ }
/* Set the is_target flag so that this file is not treated as
intermediate by the pattern rule search algorithm and
{
const char *features = "target-specific order-only second-expansion"
" else-if shortest-stem undefine oneshell nocomment"
- " grouped-target extra-prereqs"
+ " grouped-target extra-prereqs notintermediate"
#ifndef NO_ARCHIVES
" archives"
#endif
--- /dev/null
+# -*-perl-*-
+
+$description = "Test the behaviour of the .NOTINTERMEDIATE target.";
+
+$details = "\
+Test the behavior of the .NOTINTERMEDIATE special target.\n";
+
+touch('hello.z');
+unlink('hello.x');
+
+
+# Test 1. A file which matches a .NOTINTERMEDIATE pattern is not intermediate.
+run_make_test(q!
+hello.z:
+%.z: %.x; touch $@
+%.x: ;
+.NOTINTERMEDIATE: %.q %.x
+!, '', "touch hello.z\n");
+
+# Test 2. .NOTINTERMEDIATE: %.q pattern has no effect on hello.x.
+touch('hello.z');
+run_make_test(q!
+hello.z:
+%.z: %.x; touch $@
+%.x: ;
+.NOTINTERMEDIATE: %.q
+!, '', "#MAKE#: 'hello.z' is up to date.\n");
+
+# Test 3. A file which is a prereq of .NOTINTERMEDIATE is not intermediate.
+run_make_test(q!
+hello.z:
+%.z: %.x; touch $@
+%.x: ;
+.NOTINTERMEDIATE: %.q hello.x
+!, '', "touch hello.z\n");
+
+# Test 4. .NOTINTERMEDIATE without prerequisites makes everything
+# notintermediate.
+unlink('hello.z');
+run_make_test(q!
+hello.z:
+%.z: %.x; touch $@
+%.x: ;
+.NOTINTERMEDIATE:
+!, '', "touch hello.z\n");
+
+# Test 5. Same file cannot be intermediate and notintermediate.
+run_make_test(q!
+.INTERMEDIATE: hello.x
+.NOTINTERMEDIATE: hello.x
+!, '', "#MAKE#: *** hello.x cannot be both .NOTINTERMEDIATE and .INTERMEDIATE.. Stop.\n", 512);
+
+# Test 6. Same file cannot be secondary and notintermediate.
+run_make_test(q!
+.SECONDARY: hello.x
+.NOTINTERMEDIATE: hello.x
+!, '', "#MAKE#: *** hello.x cannot be both .NOTINTERMEDIATE and .SECONDARY.. Stop.\n", 512);
+
+# Test 7. All .SECONDARY and all .NOTINTERMEDIATE are mutually exclusive.
+run_make_test(q!
+.SECONDARY:
+.NOTINTERMEDIATE:
+!, '', "#MAKE#: *** .NOTINTERMEDIATE and .SECONDARY are mutually exclusive. Stop.\n", 512);
+
+# Test 8. .INTERMEDIATE file takes priority over a .NOTINTERMEDIATE pattern.
+unlink('hello.x');
+run_make_test(q!
+hello.z:
+%.z: %.x; touch $@
+%.x: ;
+.INTERMEDIATE: hello.x
+.NOTINTERMEDIATE: %.q %.x
+!, '', "#MAKE#: 'hello.z' is up to date.\n");
+
+# Test 9. Everything is notintermediate, except hello.x.
+unlink('hello.x');
+run_make_test(q!
+hello.z:
+%.z: %.x; touch $@
+%.x: ;
+.INTERMEDIATE: hello.x
+.NOTINTERMEDIATE:
+!, '', "#MAKE#: 'hello.z' is up to date.\n");
+
+# Test 10. Everything is notintermediate, except hello.x.
+unlink('hello.x');
+run_make_test(q!
+hello.z:
+%.z: %.x; touch $@
+%.x: ;
+.SECONDARY: hello.x
+.NOTINTERMEDIATE:
+!, '', "#MAKE#: 'hello.z' is up to date.\n");
+
+# Test 11. Everything is secondary, except %.q, hello.x.
+unlink('hello.x');
+run_make_test(q!
+hello.z:
+%.z: %.x; touch $@
+%.x: ;
+.NOTINTERMEDIATE: %.q hello.x
+.SECONDARY:
+!, '', "touch hello.z\n");
+
+# Test 12. Everything is secondary, except %.q %.x.
+unlink('hello.x');
+run_make_test(q!
+hello.z:
+%.z: %.x; touch $@
+%.x: ;
+.NOTINTERMEDIATE: %.q %.x
+.SECONDARY:
+!, '', "touch hello.z\n");
+
+
+
+unlink('hello.z');
+# This tells the test driver that the perl test script executed properly.
+1;