Add an option to print a list of targets defined in the makefiles.
Don't print targets of implicit rules, or special targets. To
support this remember which files are deemed suffix rule targets.
Add a missing warning for single-suffix targets with prerequisites.
Suggested by many. Sample implementation by Tim <tdhutt@gmail.com>.
* NEWS: Announce the new option and single-suffix warning.
* doc/make.1: Add --print-targets to the man page.
* doc/make.texi: Add --print-targets to the documentation. Clean up
the text around the definition of suffix rules.
* src/main.c (print_targets_flag): New variable for --print-targets.
(switches): Add a new long option --print-targets.
(main): If the option was provided call print_targets() and exit.
* src/filedef.h (struct file): Add a "suffix" boolean value. Remove
print_prereqs() since it's static. Add new print_targets().
* src/file.c (rehash_file): Merge the new suffix value.
(print_prereqs): Used only locally: change to static.
(print_target): Print targets which are not suffix rule targets and
are not special targets.
(print_targets): Call print_target() on each file.
* src/rule.c (convert_to_pattern): Make maxsuffix local; it doesn't
need to be static. Emit ignoring prerequisites for single-suffix
rules as well as double-suffix rules. Remember which files are
actually suffix rules.
* tests/scripts/features/suffixrules: Test single-suffix behavior.
* tests/scripts/options/print-targets: Add tests for --print-targets.
things like "ifeq ((foo,bar),)" are now syntax errors. Use a variable to
hide the comma if needed: "COMMA = ," / "ifeq ((foo$(COMMA)bar),)".
+* NOTE: Deprecated behavior.
+ The check in GNU Make 4.3 for suffix rules with prerequisites didn't check
+ single-suffix rules, only double-suffix rules. Add the missing check.
+
* New feature: Unload function for loaded objects
When a loaded object needs to be unloaded by GNU Make, it will invoke an
unload function (if one is defined) beforehand that allows the object to
invoked recursively, warnings can be controlled only for the current
instance of make using the .WARNINGS variable.
+* New feature: Printing targets defined by the makefile
+ A new option "--print-targets" will print all explicit, non-special targets
+ defined in the makefiles, one per line, then exit with success. No recipes
+ are invoked and no makefiles are re-built.
+
* 'make --print-data-base' (or 'make -p') now outputs time of day
using the same form as for file timestamps, e.g., "2023-05-10
10:43:57.570558743". Previously it used the form "Wed May 10
specified.
This also prints the version information given by the
.B \-v
-switch (see below).
-To print the data base without trying to remake any files, use
+switch (see below). To print the built-in data base only, use
.IR "make \-p \-f/dev/null" .
.TP 0.5i
+\fB\-\-print\-targets\fR
+Print each target defined as a result of reading the makefiles, one target per
+line, then exit with success. Implicit rule targets are not printed, nor are
+special targets (target names that consist of "." followed by all upper-case
+letters). No recipe commands are invoked and no makefiles are rebuilt.
+.TP 0.5i
\fB\-q\fR, \fB\-\-question\fR
``Question mode''.
Do not run any commands, or print anything; just return an exit status
@cindex @code{--print-data-base}
@cindex data base of @code{make} rules
@cindex predefined rules and variables, printing
-Print the data base (rules and variable values) that results from
-reading the makefiles; then execute as usual or as otherwise
-specified. This also prints the version information given by the
-@samp{-v} switch (see below). To print the data base without trying
-to remake any files, use @w{@samp{make -qp}}. To print the data base
-of predefined rules and variables, use @w{@samp{make -p -f /dev/null}}.
-The data base output contains file name and line number information for
-recipe and variable definitions, so it can be a useful debugging tool
-in complex environments.
+Print the data base (rules and variable values) that results from reading the
+makefiles; then execute as usual or as otherwise specified. This also prints
+the version information given by the @samp{-v} switch (see below). To print
+the data base without trying to remake any files, use @w{@samp{make -qp}}. To
+print the data base of predefined rules and variables, use @w{@samp{make -p -f
+/dev/null}}. The data base output contains file name and line number
+information for recipe and variable definitions, so it can be a useful
+debugging tool in complex environments.
+
+@item --print-targets
+@cindex @code{--print-targets}
+@cindex print @file{makefile} targets
+@cindex targets, printing
+Print all the targets defined by reading the makefiles, one target per line,
+then exit immediately with success. No implicit targets are printed. No
+special targets (target names consisting of ``.'' followed by all upper-case
+letters) are printed.
+
+No commands are run, including commands that would rebuild makefiles
+(@pxref{Remaking Makefiles, ,How Makefiles Are Remade}); if makefiles need to
+be rebuilt then the targets listed might be outdated. Also, @code{make} will
+not generate any errors or warnings for missing @code{include} files.
@item -q
@cindex @code{-q}
@section Old-Fashioned Suffix Rules
@cindex old-fashioned suffix rules
@cindex suffix rule
+@cindex inference rule
-@dfn{Suffix rules} are the old-fashioned way of defining implicit rules for
-@code{make}. Suffix rules are obsolete because pattern rules are more
-general and clearer. They are supported in GNU @code{make} for
-compatibility with old makefiles. They come in two kinds:
-@dfn{double-suffix} and @dfn{single-suffix}.
-
-A double-suffix rule is defined by a pair of suffixes: the target
-suffix and the source suffix. It matches any file whose name ends
-with the target suffix. The corresponding implicit prerequisite is
-made by replacing the target suffix with the source suffix in the file
-name. A two-suffix rule @samp{.c.o} (whose target and source suffixes
-are @samp{.o} and @samp{.c}) is equivalent to the pattern rule
-@samp{%.o : %.c}.
+@dfn{Suffix rules} (called @dfn{inference rules} in POSIX) are an
+old-fashioned way of defining implicit rules for @code{make}. Suffix rules
+are less powerful and harder to use than pattern rules (@pxref{Pattern Rules,
+,Defining and Redefining Pattern Rules}); they are supported by GNU Make
+primarily for POSIX compatibility. They come in two flavors:
+@dfn{single-suffix} and @dfn{double-suffix}.
A single-suffix rule is defined by a single suffix, which is the source
-suffix. It matches any file name, and the corresponding implicit
-prerequisite name is made by appending the source suffix. A single-suffix
-rule whose source suffix is @samp{.c} is equivalent to the pattern rule
-@samp{% : %.c}.
+suffix. It matches any file name, and the corresponding implicit prerequisite
+name is made by appending the source suffix. A single-suffix rule whose
+source suffix is @samp{.c} is equivalent to the pattern rule @samp{% : %.c}.
+
+A double-suffix rule is defined by a pair of suffixes: the source suffix and
+the target suffix. It matches any file whose name ends with the target
+suffix. The corresponding implicit prerequisite is made by replacing the
+target suffix with the source suffix in the file name. A two-suffix rule
+@samp{.c.o} has a source suffix @samp{.c} and a target suffix @samp{.o}, and
+is equivalent to the pattern rule @samp{%.o : %.c}.
Suffix rule definitions are recognized by comparing each rule's target
against a defined list of known suffixes. When @code{make} sees a rule
#include "debug.h"
#include "hash.h"
#include "shuffle.h"
+#include "rule.h"
/* Remember whether snap_deps has been invoked: we need this to be sure we
MERGE (notintermediate);
MERGE (ignore_vpath);
MERGE (snapped);
+ MERGE (suffix);
#undef MERGE
to_file->builtin = 0;
\f
/* Print the data base of files. */
-void
+static void
print_prereqs (const struct dep *deps)
{
const struct dep *ood = 0;
fputs (_("\n# files hash-table stats:\n# "), stdout);
hash_print_stats (&files, stdout);
}
+
+static void
+print_target (const void *item)
+{
+ const struct file *f = item;
+
+ if (!f->is_target || f->suffix)
+ return;
+
+ /* Ignore any special targets, as defined by POSIX. */
+ if (f->name[0] == '.' && isupper ((unsigned char)f->name[1]))
+ {
+ const char *cp = f->name + 1;
+ while (*(++cp) != '\0')
+ if (!isupper ((unsigned char)*cp))
+ break;
+ if (*cp == '\0')
+ return;
+ }
+
+ puts (f->name);
+}
+
+void
+print_targets (void)
+{
+ hash_map (&files, print_target);
+}
\f
/* Verify the integrity of the data base of files. */
--shuffle passes through the graph. */
unsigned int snapped:1; /* True if the deps of this file have been
secondary expanded. */
+ unsigned int suffix:1; /* True if this is a suffix rule. */
};
void init_hash_files (void);
void verify_file_data_base (void);
char *build_target_list (char *old_list);
-void print_prereqs (const struct dep *deps);
void print_file_data_base (void);
+void print_targets (void);
int try_implicit_rule (struct file *file, unsigned int depth);
int stemlen_compare (const void *v1, const void *v2);
int ignore_errors_flag = 0;
-/* Nonzero means don't remake anything, just print the data base
- that results from reading the makefile (-p). */
+/* Nonzero means print the data base that results from reading the makefile.
+ (-p or --print-data-base). */
int print_data_base_flag = 0;
+/* Nonzero means don't remake anything, just print a list of targets defined
+ by reading the makefile (--print-targets). */
+
+int print_targets_flag = 0;
+
/* Nonzero means don't remake anything; just return a nonzero status
if the specified targets are not up to date (-q). */
{ CHAR_MAX+11, string, &shuffle_mode, 1, 1, 0, 0, "random", 0, "shuffle", 0 },
{ CHAR_MAX+12, string, &jobserver_style, 1, 0, 0, 0, 0, 0, "jobserver-style", 0 },
{ WARN_OPT, strlist, &warn_flags, 1, 1, 0, 0, "warn", NULL, "warn", NULL },
+ { CHAR_MAX+14, flag, &print_targets_flag, 1, 1, 0, 0, 0, 0, "print-targets", 0 },
{ 0, 0, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL }
};
}
}
+ /* If the user wants to see a list of targets show it now then quit.
+ We do this before rebuilding makefiles to avoid extraneous output. */
+ if (print_targets_flag)
+ {
+ print_targets ();
+ die (EXIT_SUCCESS);
+ }
+
if (!restarts && new_files != 0)
{
const char **p;
struct file *suffix_file;
-/* Maximum length of a suffix. */
-
-static size_t maxsuffix;
-
/* Return the rule definition: space separated rule targets, followed by
either a colon or two colons in the case of a terminal rule, followed by
space separated rule prerequisites, followed by a pipe, followed by
suffixes in the .SUFFIXES target's dependencies and see if it exists.
First find the longest of the suffixes. */
- maxsuffix = 0;
+ size_t maxsuffix = 0;
for (d = suffix_file->deps; d != 0; d = d->next)
{
size_t l = strlen (dep_name (d));
for (d = suffix_file->deps; d != 0; d = d->next)
{
+ struct file *f;
size_t slen;
/* Make a rule that is just the suffix, with no deps or commands.
/* Record a pattern for this suffix's null-suffix rule. */
convert_suffix_rule ("", dep_name (d), d->file->cmds);
- /* Add every other suffix to this one and see if it exists as a
- two-suffix rule. */
slen = strlen (dep_name (d));
- memcpy (rulename, dep_name (d), slen);
+ memcpy (rulename, dep_name (d), slen + 1);
+
+ f = lookup_file (rulename);
+ if (f && f->cmds)
+ {
+ if (!f->deps)
+ f->suffix = 1;
+ else if (!posix_pedantic)
+ {
+ O (error, &f->cmds->fileinfo,
+ _("warning: ignoring prerequisites on suffix rule definition"));
+ f->suffix = 1;
+ }
+ }
+ /* Add every other suffix to this one and see if it exists as a
+ two-suffix rule. */
for (d2 = suffix_file->deps; d2 != 0; d2 = d2->next)
{
- struct file *f;
size_t s2len;
s2len = strlen (dep_name (d2));
{
if (posix_pedantic)
continue;
- error (&f->cmds->fileinfo, 0,
- _("warning: ignoring prerequisites on suffix rule definition"));
+ O (error, &f->cmds->fileinfo,
+ _("warning: ignoring prerequisites on suffix rule definition"));
}
+ f->suffix = 1;
+
if (s2len == 2 && rulename[slen] == '.' && rulename[slen + 1] == 'a')
/* A suffix rule '.X.a:' generates the pattern rule '(%.o): %.X'.
It also generates a normal '%.a: %.X' rule below. */
unlink('foo.baz');
-# SV 40657: Test #4: "Suffix rules" with deps are normal rules
+# SV 40657: "Suffix rules" with deps are normal rules
my $prewarn = 'warning: ignoring prerequisites on suffix rule definition';
touch('foo.bar');
+# Verify warnings for single-suffix rules
+
+run_make_test(q!
+.SUFFIXES:
+.SUFFIXES: .baz
+
+.baz: foo.bar ; @echo make $@ from $<
+
+$X.POSIX:
+!,
+ 'X=1 .baz', "#MAKEFILE#:5: $prewarn\nmake .baz from foo.bar\n");
+
+# In POSIX mode we don't get a warning
+
+run_make_test(undef, 'X= .baz', "make .baz from foo.bar\n");
+
+# Test double-suffix rules
+
run_make_test(q!
.SUFFIXES:
.SUFFIXES: .biz .baz
!,
'X=1 .baz.biz', "#MAKEFILE#:7: $prewarn\nmake .baz.biz from foo.bar\n");
-# SV 40657: Test #5: In POSIX mode we don't get a warning
+# SV 40657: In POSIX mode we don't get a warning
run_make_test(undef, 'X= .baz.biz', "make .baz.biz from foo.bar\n");
unlink('foo.bar');
-# SV 40657: Test #6: In POSIX mode, no pattern rules should be created
+# SV 40657: In POSIX mode, no pattern rules should be created
utouch(-20, 'foo.baz');
run_make_test(undef,
'X= foo.biz', "#MAKE#: *** No rule to make target 'foo.biz'. Stop.\n", 512);
-# SV 40657: Test #7: In Non-POSIX mode, a pattern rule is created
+# SV 40657: In Non-POSIX mode, a pattern rule is created
run_make_test(undef,
'X=1 foo.biz', "#MAKEFILE#:7: $prewarn\nmake foo.biz from foo.baz\n");
-# SV 40657: Test #8: ... but any prerequisites are ignored
+# SV 40657: ... but any prerequisites are ignored
utouch(-10, 'foo.biz');
touch('foo.bar');
--- /dev/null
+# -*-perl-*-
+
+$description = "Test the --print-targets option to GNU Make.";
+
+# Define various things and verify the output
+run_make_test(q!
+.PHONY: all
+all: ;@:
+
+# "special" target
+.BOGUS: ;@:
+
+# Check various forms of suffix rule
+.SUFFIXES: .q
+.q: ;@:
+.c.o: ;@:
+
+# Not a suffix rule
+.x.z: ;@:
+
+# Verify included files aren't built / don't fail
+
+include badfile
+include goodfile
+
+submake: ; $(MAKE) all
+always: ; +echo always
+goodfile: ; touch goodfile
+!,
+ "--print-targets", "submake\n.x.z\nalways\nall\ngoodfile\n");
+
+1;