[SV 64571] Add --print-targets option

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.
This commit is contained in:
Paul Smith 2024-01-08 23:14:57 -05:00
parent 1ff728bff4
commit 31036e648f
9 changed files with 181 additions and 48 deletions

9
NEWS
View File

@ -37,6 +37,10 @@ https://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=111&se
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
@ -56,6 +60,11 @@ https://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=111&se
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

View File

@ -270,10 +270,15 @@ reading the makefiles; then execute as usual or as otherwise
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

View File

@ -9677,15 +9677,28 @@ performed. @xref{Parallel Output, ,Output During Parallel Execution}.
@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}
@ -11237,26 +11250,26 @@ You can use a last-resort rule to override part of another makefile.
@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

View File

@ -26,6 +26,7 @@ this program. If not, see <https://www.gnu.org/licenses/>. */
#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
@ -334,6 +335,7 @@ rehash_file (struct file *from_file, const char *to_hname)
MERGE (notintermediate);
MERGE (ignore_vpath);
MERGE (snapped);
MERGE (suffix);
#undef MERGE
to_file->builtin = 0;
@ -1050,7 +1052,7 @@ file_timestamp_sprintf (char *p, FILE_TIMESTAMP ts)
/* Print the data base of files. */
void
static void
print_prereqs (const struct dep *deps)
{
const struct dep *ood = 0;
@ -1201,6 +1203,34 @@ print_file_data_base (void)
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);
}
/* Verify the integrity of the data base of files. */

View File

@ -113,6 +113,7 @@ struct file
--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. */
};
@ -134,8 +135,8 @@ void notice_finished_file (struct file *file);
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);

View File

@ -167,11 +167,16 @@ int env_overrides = 0;
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). */
@ -509,6 +514,7 @@ static struct command_switch switches[] =
{ 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 }
};
@ -2289,6 +2295,14 @@ main (int argc, char **argv, char **envp)
}
}
/* 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;

View File

@ -56,10 +56,6 @@ size_t max_pattern_dep_length;
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
@ -304,7 +300,7 @@ convert_to_pattern (void)
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));
@ -317,6 +313,7 @@ convert_to_pattern (void)
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.
@ -327,14 +324,26 @@ convert_to_pattern (void)
/* Record a pattern for this suffix's null-suffix rule. */
convert_suffix_rule ("", dep_name (d), d->file->cmds);
slen = strlen (dep_name (d));
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. */
slen = strlen (dep_name (d));
memcpy (rulename, dep_name (d), slen);
for (d2 = suffix_file->deps; d2 != 0; d2 = d2->next)
{
struct file *f;
size_t s2len;
s2len = strlen (dep_name (d2));
@ -359,10 +368,12 @@ convert_to_pattern (void)
{
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. */

View File

@ -51,12 +51,30 @@ run_make_test(q!
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
@ -67,25 +85,25 @@ $X.POSIX:
!,
'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');

View File

@ -0,0 +1,32 @@
# -*-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;