On Wed, Apr 09, 2025 at 10:03:06PM -0400, David M. Warme wrote:
> Re-submitting this patch for an m4 'makedep' feature.
>
> This patch is based on branch-1.4 as of today.
Thank you for providing that update. I'm leaning towards applying it
to 1.6 rather than 1.4, but we'll see how things go. I'm trying to
get beta 1.4.19b out the door this weekend to make sure I didn't break
builds on any platforms, then follow that shortly by stable 1.4.20;
and in parallel put out beta 1.5.90 with your patch included as a
preview of what I hope will be 1.6 soon (I spent evenings this week
getting over 100 patches from 1.4.x forward ported on top of the last
1.5.89a release on branch-1.6). But a lot of that depends on how much
additional free time I can make on the next few weekends...
Additional review comments below...
>
> David
>
>
> ChangeLog-2014 | 14 ++++++
> NEWS | 2 +
> THANKS | 2 +
> doc/m4.texi | 116 +++++++++++++++++++++++++++++++++++++++++++
> src/builtin.c | 19 ++++---
> src/m4.c | 153
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
> src/m4.h | 15 +++++-
> src/path.c | 79 +++++++++++++++++++++++++++++
> 8 files changed, 390 insertions(+), 10 deletions(-)
...
> +++ b/doc/m4.texi
> @@ -161,6 +161,7 @@
> * Preprocessor features:: Command line options for preprocessor
> features
> * Limits control:: Command line options for limits control
> * Frozen state:: Command line options for frozen state
> +* Make dependency generation:: Generating make depencency rules
This feels like it might belong closer to the Preprocessor features
section of the manual (since it is like synclines, __line__, and
__file).
> @@ -864,6 +866,120 @@
> files are read.
> @end table
> +@node Make dependency generation
> +@section Command line options for generating Makefile dependency rules
> +
> +Makefile dependency rules can be automatically generated by specifying
> +both the @code{--makedep=}@var{file} and
> +@code{--makedep-target=}@var{target} options.
> +
> +@table @code
> +@item --makedep=@var{file}
> +Causes @code{m4} to generate a dependency rule into the specified
> +@var{file}. Macro expansion output is still written to stdout as
> +normal. This option is analogous to the @code{-MF} option of
> +@code{gcc}.
> +
> +@item --makedep-target=@var{target}
> +Specifies @var{target} to be the target of the generated dependency
> +rule. The string @var{target} is used verbatim, and can contain several
> +logical targets separated by spaces. It is the user's responsibility to
> +properly express characters that @code{make} handles specially (such as
> +'@code{$}', or spaces within file names). Since @code{m4} sends its
> +macro expansion output to stdout, it never really knows the name of the
> +target file being generated, so the target must always be specified
> +explicitly by the user with this option. This option is analogous to
> +the @code{-MT} option of @code{gcc} (except that @code{gcc} allows
> +@code{-MT} to be specified multiple times).
> +@end table
> +
> +Note that the @code{--makedep=}@var{file} and
> +@code{makedep-target=}@var{target} options must either (a) both be
> +specified, or (b) neither be specified. They cannot be used
> +independently of each other.
> +
> +The following additional options can also be used when dependency rules
> +are being generated (these options are only valid when both
> +@code{makedep=}@var{file} and @code{makedep-target=}@var{target} have
> +also been specified):
> +
> +@table @code
> +@item --makedep-gen-missing-argfiles
> +Causes @code{m4} to assume that any file listed on the command line that
> +is missing (i.e., does not exist) is an automatically generated file.
> +@code{M4} includes such missing files as dependencies in the generated
> +rule regardless. In this case the dependency appears exactly as
> +specified on the command line and is not modified by any
> +@code{-I}@var{searchdir} prefixes. Note that the macro expansion output
> +generated to stdout will be incorrect when this happens because the
> +missing file is assumed to be an empty file. A warning is produced on
> +stderr for each missing command line file handled in this manner.
> +
> +@item --makedep-gen-missing-include
> +Causes @code{m4} to assume that any file included via the
> +@code{include()} macro that is missing (i.e., does not exist) is an
> +automatically generated file. @code{M4} includes such missing files as
> +dependencies in the generated rule regardless. In this case the
> +dependency appears exactly as specified in the argument to
> +@code{include()} and is not modified by any @code{-I}@var{searchdir}
> +prefixes. Note that the macro expansion output generated to stdout will
> +be incorrect when this happens because the missing file is assumed to be
> +an empty file. This option causes the @code{m4} @code{include()} macro
> +to behave like @code{sinclude()}, except that a warning message is
> +produced on stderr to indicate that the requested file was missing.
> +This option is analogous to the @code{-MG} option of @code{gcc}.
> +
> +@item --makedep-gen-missing-sinclude
> +Causes @code{m4} to assume that any file included via the
> +@code{sinclude()} macro that is missing (i.e., does not exist) is an
> +automatically generated file. @code{M4} includes such missing files as
> +dependencies in the generated rule regardless. In this case the
> +dependency appears exactly as specified in the argument to
> +@code{sinclude()} and is not modified by any @code{-I}@var{searchdir}
> +prefixes. Note that the macro expansion output generated to stdout will
> +be incorrect when this happens because the missing file is assumed to be
> +an empty file. This option does not alter @code{sinclude()}'s behavior
> +of silently ignoring requests to @code{sinclude()} files that do not exist.
> +
> +@item --makedep-gen-missing-all
> +This option is equivalent to specifying all three options
> +@code{--makedep-gen-missing-argfiles},
> +@code{--makedep-gen-missing-include} and
> +@code{--makedep-gen-missing-sinclude}.
> +@end table
> +
> +Note that the above @code{makedep-gen-missing-*} options assume that the
> +missing files will ultimately not @code{include()} or @code{sinclude()}
> +any additional files -- if they do, then these additional files will be
> +missing from the generated dependency rules.
> +
> +The following options control the generation of ``phony'' targets for
> +certain classes of dependencies. These dummy rules are used to work
> +around errors @code{make} gives if you remove files without updating the
> +@code{Makefile} to match. Dependencies that match one or more of these
> +classes cause a single dummy rule to be generated for them:
> +
> +@table @code
> +@item --makedep-phony-argfiles
> +Causes @code{m4} to generate a ``phony'' target for each file that is
> +specified on the command line.
> +
> +@item --makedep-phony-include
> +Causes @code{m4} to generate a ``phony'' target for each file that is
> +the subject of an @code{include()} macro. This option is analogous to
> +the @code{-MP} option of @code{gcc}.
> +
> +@item --makedep-phony-sinclude
> +Causes @code{m4} to generate a ``phony'' target for each file that is
> +the subject of an @code{sinclude()} macro.
> +
> +@item --makedep-phony-all
> +is equivalent to specifying all three options:
> +@code{--makedep-phony-argfiles}
> +@code{--makedep-phony-include}
> +@code{--makedep-phony-sinclude}.
> +@end table
> +
In addition to all the command line options to enable this feature,
would it be worth an example demonstration of the feature in
operation?
One of the nicer things about the current state of the tree is that
examples that appear in the m4 manual are also executed during 'make
check' to ensure we don't regress; even if it is a silly example that
uses mkstemp() or hard-codes a dependency name, and then runs a second
m4 instance to see what the first one produced as its dependency
output, that would add some confidence that future refactoring won't
break this. And even if we can't get it running automatically from
the manual, having a shell script or other means of testing expected
behavior in the checks/ directory will be worthwhile.
> @node Debugging options
> @section Command line options for debugging
> diff --git a/src/builtin.c b/src/builtin.c
> index 2819ba49..0f237c5b 100644
> --- a/src/builtin.c
> +++ b/src/builtin.c
> @@ -1388,10 +1388,11 @@ m4_changeword (struct obstack *obs MAYBE_UNUSED, int
> argc, token_data **argv)
> `---------------------------------------------------------------*/
> static void
> -include (int argc, token_data **argv, bool silent)
> +include (int argc, token_data **argv, bool silent, int ref_from)
> {
> FILE *fp;
> char *name;
> + int fail;
> if (bad_argc (argv[0], argc, 2, 2))
> return;
> @@ -1399,14 +1400,20 @@ include (int argc, token_data **argv, bool silent)
> fp = m4_path_search (ARG (1), false, &name);
> if (fp == NULL)
> {
> - if (!silent)
> + fail = !silent;
> + if ((makedep_gen_missing & ref_from) != 0)
> {
> - M4ERROR ((warning_status, errno, _("cannot open `%s'"), ARG (1)));
> - retcode = EXIT_FAILURE;
> + record_dependency (ARG (1), ref_from);
Not this patch's fault, but repeated references to ARG(1) are slightly
less efficient than storing ARG(1) into a temporary variable up
front. I can clean that up.
> +++ b/src/m4.c
> @@ -632,6 +751,32 @@ main (int argc, char *const *argv)
> if (debugfile && !debug_set_output (debugfile))
> M4ERROR ((warning_status, errno, _("cannot set debug file `%s'"),
> debugfile));
> +
> + /* Verify mutual consistency of makedep options. */
> +#define MKDEP_OPTS "--makedep and --makedep-target"
This #define is not marked for translation; I'm not sure how to best
phrase things for when we do add i18n translations of error messages.
> + if ((makedep_path == NULL) && (makedep_target == NULL))
> + {
> + /* Makedep mode is NOT active. */
> + if (makedep_gen_missing != 0)
> + M4ERROR ((EXIT_FAILURE, 0,
> + "--makedep-gen-missing-* requires " MKDEP_OPTS));
> + if (makedep_phony != 0)
> + M4ERROR ((EXIT_FAILURE, 0,
> + "--makedep-phony-* requires " MKDEP_OPTS));
More strings missing _() marking.
> + if ((makedep_gen_missing | makedep_phony) != 0)
> + exit (EXIT_FAILURE);
> + }
> + else if ((makedep_path != NULL) && (makedep_target != NULL))
> + {
> + /* Makedep mode is active. */
> + }
> + else
> + {
> + M4ERROR ((EXIT_FAILURE, 0,
> + MKDEP_OPTS " cannot be used independently."));
Error messages should not end in '.'
> + exit (EXIT_FAILURE);
> + }
> +#undef MKDEP_OPTS
> input_init ();
> output_init ();
> @@ -738,6 +883,8 @@ main (int argc, char *const *argv)
> undivert_all ();
> }
> output_exit ();
> + if (makedep_path != NULL)
> + generate_make_dependencies (makedep_path, makedep_target, makedep_phony);
> free_macro_sequence ();
> exit (retcode);
> }
> diff --git a/src/m4.h b/src/m4.h
> index 8d0d96dd..f8735abc 100644
> --- a/src/m4.h
> @@ -412,7 +420,10 @@ extern void hack_all_symbols (hack_symbol *, void *);
> extern int expansion_level;
> extern void expand_input (void);
> -extern void call_macro (symbol *, int, token_data **, struct obstack *);
> +extern void call_macro (symbol *, int, token_data **, struct obstack *)
> + /* This doesn't seem right, but gcc-8.5.0 is suggesting that this */
> + /* function might be a candidate for attribute 'cold', stopping the build.
> */
> + ATTRIBUTE_COLD;
Unrelated to your patch, but something that should be fixed
independently if it is still a problem.
> +++ b/src/path.c
> @@ -36,6 +36,18 @@ typedef struct includes includes;
> static includes *dir_list; /* the list of path directories */
> static includes *dir_list_end; /* the end of same */
> static int dir_max_length; /* length of longest directory name */
> +
> +struct dependency
> +{
> + struct dependency *next; /* next in list of dependencies */
> + int ref_from; /* bit mask: places file referenced from */
> + char path [1]; /* pathname of this dependency */
Hmm - abusing this trailing struct member to be an overlay with an
overallocated actual storage. I'm trying to figure out if there is a
preferred GNU style for this sort of C overuse (I know that VLA types
are not what we want, but am not sure this spelling is ideal either).
--
Eric Blake, Principal Software Engineer
Red Hat, Inc.
Virtualization: qemu.org | libguestfs.org
_______________________________________________
M4-patches mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/m4-patches