Re: A 'makedep' feature for m4.
"David M. Warme" <[email protected]> Tue, 20 May 2025 14:31:35 -0400
| Newsgroups | gmane.comp.gnu.m4.patches |
|---|---|
| Message-ID | <[email protected]> |
This is a multi-part message in MIME format.
--===============6877030795792928262==
Content-Type: multipart/alternative;
boundary="------------n8uDVgn7VhLhPTQyNGk5DF1n"
Content-Language: en-US
This is a multi-part message in MIME format.
--------------n8uDVgn7VhLhPTQyNGk5DF1n
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 7bit
Eric,
I have incorporated most of the changes that you have identified. This
patch is from very recent branch-1.6.
David
NEWS | 2 +
THANKS | 2 +
checks/check-them | 37 ++++++++++-
checks/get-them | 13 +++-
doc/m4.texi | 195 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/builtin.c | 16 ++++-
src/eval.c | 1 +
src/m4.c | 151 +++++++++++++++++++++++++++++++++++++++++-
src/m4.h | 10 +++
src/path.c | 80 ++++++++++++++++++++++
10 files changed, 496 insertions(+), 11 deletions(-)
diff --git a/NEWS b/NEWS
index 97c4d9c0..23d5bd5f 100644
--- a/NEWS
+++ b/NEWS
@@ -196,6 +196,8 @@ following beta features that were deemed worth deferring until 1.6:
* Noteworthy changes in release 1.4.19 (2021-05-28) [stable]
+** Add new capability to automatically generate make dependency rules.
+
** A number of portability improvements inherited from gnulib, including
the ability to perform stack overflow detection on more platforms
without linking to GNU libsigsegv.
diff --git a/THANKS b/THANKS
index d441f56a..2e4de505 100644
--- a/THANKS
+++ b/THANKS
@@ -39,6 +39,7 @@ David Apps unlisted
David [email protected]
David J. [email protected]
David [email protected]
+David [email protected]
Elbert [email protected]
Elias [email protected]
Erez [email protected]
@@ -81,6 +82,7 @@ Konrad [email protected]
Kristine [email protected]
Krste [email protected]
Lawson [email protected]
+Lorenzo Di [email protected]
Marijn Schouten unlisted
Marion [email protected]
Mark [email protected]
diff --git a/checks/check-them b/checks/check-them
index 24e68029..09c7c14f 100755
--- a/checks/check-them
+++ b/checks/check-them
@@ -37,6 +37,7 @@ out=$tmp/m4-out
err=$tmp/m4-err
xout=$tmp/m4-xout
xerr=$tmp/m4-xerr
+xaux=$tmp/m4-xaux
failed=
skipped=
strip_needed=false
@@ -104,7 +105,8 @@ do
continue ;;
esac
- options=`${SED} -ne '3s/^dnl @ extra options: //p;3q' "$file"`
+ options=`${SED} -ne '3s/^dnl @ extra options: //p;3q' "$file" \
+ | ${SED} -e "s/TMP\//$tmp\//"`
${SED} -e '/^dnl @/d' -e '/^\^D$/q' "$file" \
| LC_MESSAGES=C LANG=C M4PATH=$examples "$m4" -d $options - >$out 2>$err
stat=$?
@@ -126,8 +128,9 @@ do
xoutfile=`${SED} -n 's/^dnl @ expected output: //p' "$file"`
if test -z "$xoutfile" ; then
- ${SED} -e '/^dnl @result{}/!d' -e 's///' -e "s|examples/|$examples/|" \
- -e "s|@value{VERSION}|$m4version|" "$file" > $xout
+ ${SED} -ne 's/^dnl @result{}//p' "$file" \
+ | ${SED} -e "s|examples/|$examples/|" \
+ -e "s|@value{VERSION}|$m4version|" > $xout
else
cp "$examples/$xoutfile" $xout
fi
@@ -149,6 +152,8 @@ do
"$examples/$xerrfile" > $xerr ;;
esac
+ auxfile=`${SED} -n 's/^dnl @ expected auxfile: //p' "$file"`
+
# For the benefit of mingw, normalize \r\n line endings
if $strip_needed ; then
tr -d '\015' < $out > $out.t
@@ -179,6 +184,32 @@ do
diff $diffopts $xerr $err
fi
+ if test -n "$auxfile"; then
+ tauxfile=`echo "$auxfile" | ${SED} -e "s/TMP\//$tmp\//"`
+ if test -f "$tauxfile"; then
+ ${SED} -ne 's|^dnl @auxresult{[A-Za-z0-9_/]*}||p' < $file >$xaux
+ if $strip_needed ; then
+ tr -d '\015' < $tauxfile > $tauxfile.t
+ mv $tauxfile.t $tauxfile
+ tr -d '\015' < $xaux > $xaux.t
+ mv $xaux.t $xaux
+ fi
+ if cmp -s $tauxfile $xaux; then
+ :
+ else
+ failed="$failed $file:aux"
+ echo `${SED} -e 's/^dnl //' -e 1q $file`
+ echo "$file auxfile mismatch"
+ diff $diffopts $xaux $tauxfile
+ fi
+ rm -f $tauxfile
+ else
+ failed="$failed $file:aux"
+ echo `${SED} -e 's/^dnl //' -e 1q $file`
+ echo "$file aux outfile $auxfile does not exist"
+ fi
+ fi
+
done
rm -f $out $err $xout $xerr
diff --git a/checks/get-them b/checks/get-them
index 9028a6e3..dafdb591 100755
--- a/checks/get-them
+++ b/checks/get-them
@@ -36,6 +36,7 @@ BEGIN {
options = "";
xout = "";
xerr = "";
+ auxfile = "";
}
/^@node / {
@@ -83,6 +84,11 @@ BEGIN {
gsub ("@comment xerr: ", "", xerr);
}
+/^@comment auxfile: / {
+ auxfile = $0;
+ gsub ("@comment auxfile: ", "", auxfile);
+}
+
/^@example$/, /^@end example$/ {
if (seq < 0)
next;
@@ -105,10 +111,13 @@ BEGIN {
printf("dnl @ expected output: %s\n", xout) > file;
if (xerr)
printf("dnl @ expected error: %s\n", xerr) > file;
+ if (auxfile)
+ printf("dnl @ expected auxfile: %s\n", auxfile) > file;
status = 0;
options = "";
xout = "";
xerr = "";
+ auxfile = "";
next;
}
if ($0 ~ /^@end example$/) {
@@ -116,9 +125,9 @@ BEGIN {
}
if ($0 ~ /^\^D$/)
next;
- if ($0 ~ /^\$ @kbd/)
+ if ($0 ~ /^\$ @kbd/ || $0 ~ /^@kbd/)
next;
- if ($0 ~ /^@result\{\}/ || $0 ~ /^@error\{\}/)
+ if ($0 ~ /^@result\{\}/ || $0 ~ /^@error\{\}/ || $0 ~ /^@auxresult\{[A-Za-z0-9_\/]*\}/)
prefix = "dnl ";
else
prefix = ""; diff --git a/doc/m4.texi b/doc/m4.texi index 612ed945..e7a9d5f6
100644 --- a/doc/m4.texi +++ b/doc/m4.texi @@ -36,6 +36,14 @@
@r{[}@var{\varname\} = @samp{\default\}@r{]} @end macro +@c
@auxresult{auxfile} +@c ------------ +@c Used in examples to indicate
output produced within the +@c ``auxilliary output file.'' +@macro
auxresult{auxfile} +\auxfile\ @b{@result{}} +@end macro + @comment
%**end of header @comment
======================================================== @@ -148,6
+156,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 dependency rules * Debugging
options:: Command line options for debugging * Command line files::
Specifying input files on the command line @@ -583,6 +592,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 dependency rules * Debugging options::
Command line options for debugging * Command line files:: Specifying
input files on the command line @end menu @@ -904,6 +914,191 @@ 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. + +@comment options:
--makedep=TMP/depfile --makedep-target=Target foo +@comment auxfile:
TMP/depfile +@example +$ @kbd{m4 -I examples --makedep=TMP/depfile
--makedep-target=Target foo} +@result{}bar +@auxresult{TMP/depfile}#
Automatically generated by GNU m4. +@auxresult{TMP/depfile}Target:
./../examples/foo +@end example + +@comment Separate these two examples.
+@sp 1 + +@comment options: --makedep=TMP/depfile
--makedep-target=Target foo +@comment auxfile: TMP/depfile +@example +$
@kbd{m4 -I examples --makedep=TMP/depfile --makedep-target=Target foo -}
+@result{}bar +include(`incl.m4') +@result{}Include file start
+@result{}foo +@result{}Include file end +@result{} +^D
+@auxresult{TMP/depfile}# Automatically generated by GNU m4.
+@auxresult{TMP/depfile}Target: ./../examples/foo ./../examples/incl.m4
+@end example + +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. + + +@comment status: 1
+@comment options: --makedep=TMP/depfile --makedep-target=Target
--makedep-gen-missing-all foo none +@comment auxfile: TMP/depfile
+@example +$ @kbd{m4 -I examples --makedep=TMP/depfile
--makedep-target=Target \} +@kbd{ --makedep-gen-missing-all foo none -}
+@result{}bar +@error{}m4: cannot open 'none': No such file or directory
+include(`incl.m4') +@result{}Include file start +@result{}foo
+@result{}Include file end +@result{} +include(`none2') +@result{}
+@error{}m4:stdin:2: include: cannot open 'none2': No such file or
directory +sinclude(`none3') +@result{} +^D +@auxresult{TMP/depfile}#
Automatically generated by GNU m4. +@auxresult{TMP/depfile}Target:
./../examples/foo none ./../examples/incl.m4 none2 none3 +@end example +
+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 + +@comment options:
--makedep=TMP/depfile --makedep-target=Target --makedep-phony-all foo
+@comment auxfile: TMP/depfile +@example +$ @kbd{m4 -I examples
--makdep=TMP/depfile --makedep-target=Target \} +@kbd{
--makedep-phony-all foo -} +@result{}bar +include(`incl.m4')
+@result{}Include file start +@result{}foo +@result{}Include file end
+@result{} +^D +@auxresult{TMP/depfile}# Automatically generated by GNU
m4. +@auxresult{TMP/depfile}Target: ./../examples/foo
./../examples/incl.m4 +@auxresult{TMP/depfile}
+@auxresult{TMP/depfile}./../examples/foo: +@auxresult{TMP/depfile}
+@auxresult{TMP/depfile}./../examples/incl.m4: +@end example + @node
Debugging options @section Command line options for debugging diff --git
a/src/builtin.c b/src/builtin.c index bf0d1798..36b9ed00 100644 ---
a/src/builtin.c +++ b/src/builtin.c @@ -1494,13 +1494,14 @@ m4_changecom
(struct obstack *obs MAYBE_UNUSED, int argc, argument, if it exists.
Complain about inaccessible files iff SILENT is false. */ static void
-include (int argc, macro_arguments *argv, bool silent) +include (int
argc, macro_arguments *argv, bool silent, int ref_from) { const
call_info *me = arg_info (argv); FILE *fp; char *name; const char *arg;
size_t len; + int fail; if (bad_argc (me, argc, 1, 1)) return; @@
-1513,12 +1514,21 @@ include (int argc, macro_arguments *argv, bool
silent) fp = m4_path_search (arg, false, &name); if (fp == NULL) { +
fail = !silent; + if ((makedep_gen_missing & ref_from) != 0) + { +
record_dependency (arg, ref_from); + fail = 0; + } if (!silent) m4_error
(0, errno, me, _("cannot open %s"),
quotearg_style (locale_quoting_style, arg));
+ if (fail)
+ retcode = EXIT_FAILURE;
return;
}
+ record_dependency (name, ref_from);
push_file (fp, name, true);
free (name);
}
@@ -1527,7 +1537,7 @@ include (int argc, macro_arguments *argv, bool silent)
static void
m4_include (struct obstack *obs MAYBE_UNUSED, int argc, macro_arguments *argv)
{
- include (argc, argv, false);
+ include (argc, argv, false, REF_INCLUDE);
}
/* Include a file, ignoring errors. */
@@ -1535,7 +1545,7 @@ static void
m4_sinclude (struct obstack *obs MAYBE_UNUSED, int argc,
macro_arguments *argv)
{
- include (argc, argv, true);
+ include (argc, argv, true, REF_SINCLUDE);
}
/* More miscellaneous builtins -- "maketemp", "errprint", "__file__",
diff --git a/src/eval.c b/src/eval.c
index 69cd5e41..d91fa3cd 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -431,6 +431,7 @@ parse_expr (int32_t *v1, eval_error er, unsigned min_prec)
that the implementation-defined overflow when casting
unsigned to signed is a silent twos-complement
wrap-around. */
+ u3 = 1;
if (v2 < 0)
er = NEGATIVE_EXPONENT;
else if (*v1 == 0 && v2 == 0)
diff --git a/src/m4.c b/src/m4.c
index 89a2ec2f..aa2327a5 100644
--- a/src/m4.c
+++ b/src/m4.c
@@ -65,6 +65,21 @@ int warning_status = 0;
/* Artificial limit for expansion_level in macro.c. */
int nesting_limit = 1024;
+/* Pathname of dependency file being made (--makedep=PATH). */
+static const char *makedep_path = NULL;
+
+/* Target for dependency rule being made (--makedep-target=TARGET). */
+static const char *makedep_target = NULL;
+
+/* Bitmask of places that will assume non-existent files are actually
+ generated, and so a dependency should be listed regardless
+ (--makedep-gen-missing-*). */
+int makedep_gen_missing = REF_NONE;
+
+/* Bitmask of which places files are referenced from that will trigger
+ phony rules to be generated (--makedep-phony-*). */
+static int makedep_phony = REF_NONE;
+
/* Global catchall for any errors that should affect final error status, but
where we try to continue execution in the meantime. */
int retcode;
@@ -283,6 +298,37 @@ Frozen state files:\n\
"), stdout);
puts ("");
fputs (_("\
+Make dependency generation:\n\
+ --makedep=FILE write make dependency rule(s) into FILE\n\
+ --makedep-target=TARGET specify target of generated dependency rule\n\
+ The --makedep and --makedep-target options\n\
+ must be used together, either both present,\n\
+ or neither present.\n\
+ --makedep-gen-missing-argfiles\n\
+ --makedep-gen-missing-include\n\
+ --makedep-gen-missing-sinclude\n\
+ files that do not exist (on command line,\n\
+ via include(), or via sinclude(),\n\
+ respectively) are assumed to be generated\n\
+ files and become dependencies regardless.\n\
+ --makedep-gen-missing-all\n\
+ equivalent to --makedep-gen-missing-argfiles\n\
+ --makedep-gen-missing-include\n\
+ --makedep-gen-missing-sinclude\n\
+ --makedep-phony-argfiles\n\
+ --makedep-phony-include\n\
+ --makedep-phony-sinclude\n\
+ generate a \"phony\" target for each file\n\
+ that is specified on the command line, the\n\
+ subject of an include() macro, or the\n\
+ subject of an sinclude() macro,\n\
+ respectively.\n\
+ --makedep-phony-all equivalent to --makedep-phony-argfiles\n\
+ --makedep-phony-include\n\
+ --makedep-phony-sinclude\n\
+"), stdout);
+ puts ("");
+ fputs (_("\
Debugging:\n\
-d, --debug[=[-|+]FLAGS], --debugmode[=[-|+]FLAGS]\n\
set debug level (no FLAGS implies `+adeq')\n\
@@ -333,6 +379,16 @@ enum
{
DEBUGFILE_OPTION = CHAR_MAX + 1, /* no short opt */
WARN_MACRO_SEQUENCE_OPTION, /* no short opt */
+ MAKEDEP_OPTION, /* no short opt */
+ MAKEDEP_TARGET_OPTION, /* no short opt */
+ MAKEDEP_GEN_MISSING_ARGFILES_OPTION, /* no short opt */
+ MAKEDEP_GEN_MISSING_INCLUDE_OPTION, /* no short opt */
+ MAKEDEP_GEN_MISSING_SINCLUDE_OPTION, /* no short opt */
+ MAKEDEP_GEN_MISSING_ALL_OPTION, /* no short opt */
+ MAKEDEP_PHONY_ARGFILES_OPTION, /* no short opt */
+ MAKEDEP_PHONY_INCLUDE_OPTION, /* no short opt */
+ MAKEDEP_PHONY_SINCLUDE_OPTION, /* no short opt */
+ MAKEDEP_PHONY_ALL_OPTION, /* no short opt */
HELP_OPTION, /* no short opt */
VERSION_OPTION /* no short opt */
@@ -365,6 +421,21 @@ static const struct option long_options[] = {
{"warn-macro-sequence", optional_argument, NULL,
WARN_MACRO_SEQUENCE_OPTION},
+ {"makedep", required_argument, NULL, MAKEDEP_OPTION},
+ {"makedep-target", required_argument, NULL, MAKEDEP_TARGET_OPTION},
+ {"makedep-gen-missing-argfiles", no_argument, NULL,
+ MAKEDEP_GEN_MISSING_ARGFILES_OPTION},
+ {"makedep-gen-missing-include", no_argument, NULL,
+ MAKEDEP_GEN_MISSING_INCLUDE_OPTION},
+ {"makedep-gen-missing-sinclude", no_argument, NULL,
+ MAKEDEP_GEN_MISSING_SINCLUDE_OPTION},
+ {"makedep-gen-missing-all", no_argument, NULL,
+ MAKEDEP_GEN_MISSING_ALL_OPTION},
+ {"makedep-phony-argfiles", no_argument, NULL, MAKEDEP_PHONY_ARGFILES_OPTION},
+ {"makedep-phony-include", no_argument, NULL, MAKEDEP_PHONY_INCLUDE_OPTION},
+ {"makedep-phony-sinclude", no_argument, NULL, MAKEDEP_PHONY_SINCLUDE_OPTION},
+ {"makedep-phony-all", no_argument, NULL, MAKEDEP_PHONY_ALL_OPTION},
+
{"help", no_argument, NULL, HELP_OPTION},
{"version", no_argument, NULL, VERSION_OPTION},
@@ -394,11 +465,15 @@ process_file (const char *name)
{
error (0, errno, _("cannot open %s"),
quotearg_style (locale_quoting_style, name));
- /* Set the status to EXIT_FAILURE, even though we
- continue to process files after a missing file. */
- retcode = EXIT_FAILURE;
+ if ((makedep_gen_missing & REF_CMD_LINE) != 0)
+ record_dependency (name, REF_CMD_LINE);
+ else
+ /* Set the status to EXIT_FAILURE, even though we
+ continue to process files after a missing file. */
+ retcode = EXIT_FAILURE;
return;
}
+ record_dependency (full_name, REF_CMD_LINE);
push_file (fp, full_name, true);
free (full_name);
}
@@ -641,6 +716,50 @@ main (int argc, char *const *argv, char *const *envp MAYBE_UNUSED)
(which disables these warnings). */
macro_sequence = optarg;
break;
+
+ case MAKEDEP_OPTION:
+ if (makedep_path != NULL)
+ usage (EXIT_FAILURE);
+ makedep_path = optarg;
+ break;
+
+ case MAKEDEP_TARGET_OPTION:
+ if (makedep_target != NULL)
+ usage (EXIT_FAILURE);
+ makedep_target = optarg;
+ break;
+
+ case MAKEDEP_GEN_MISSING_ARGFILES_OPTION:
+ makedep_gen_missing |= REF_CMD_LINE;
+ break;
+
+ case MAKEDEP_GEN_MISSING_INCLUDE_OPTION:
+ makedep_gen_missing |= REF_INCLUDE;
+ break;
+
+ case MAKEDEP_GEN_MISSING_SINCLUDE_OPTION:
+ makedep_gen_missing |= REF_SINCLUDE;
+ break;
+
+ case MAKEDEP_GEN_MISSING_ALL_OPTION:
+ makedep_gen_missing |= REF_ALL;
+ break;
+
+ case MAKEDEP_PHONY_ARGFILES_OPTION:
+ makedep_phony |= REF_CMD_LINE;
+ break;
+
+ case MAKEDEP_PHONY_INCLUDE_OPTION:
+ makedep_phony |= REF_INCLUDE;
+ break;
+
+ case MAKEDEP_PHONY_SINCLUDE_OPTION:
+ makedep_phony |= REF_SINCLUDE;
+ break;
+
+ case MAKEDEP_PHONY_ALL_OPTION:
+ makedep_phony |= REF_ALL;
+ break;
case VERSION_OPTION:
version_etc (stdout, PACKAGE, PACKAGE_NAME, VERSION, AUTHORS, NULL);
@@ -659,6 +778,30 @@ main (int argc, char *const *argv, char *const *envp MAYBE_UNUSED)
m4_error (0, errno, NULL, _("cannot set debug file %s"),
quotearg_style (locale_quoting_style, debugfile));
+ /* Verify mutual consistency of makedep options. */
+ if ((makedep_path == NULL) && (makedep_target == NULL))
+ {
+ /* Makedep mode is NOT active. */
+ if (makedep_gen_missing != 0)
+ m4_error (0, 0, NULL,
+ _("--makedep-gen-missing-* requires --makedep and --makedep-target"));
+ if (makedep_phony != 0)
+ m4_error (0, 0, NULL,
+ _("--makedep-phony-* requires --makedep and --makedep-target"));
+ if ((makedep_gen_missing | makedep_phony) != 0)
+ exit (EXIT_FAILURE);
+ }
+ else if ((makedep_path != NULL) && (makedep_target != NULL))
+ {
+ /* Makedep mode is active. */
+ }
+ else
+ {
+ m4_error (0, 0, NULL,
+ _("--makedep must be used with --makedep-target"));
+ exit (EXIT_FAILURE);
+ }
+
input_init ();
output_init ();
symtab_init (hash_table_size);
@@ -769,6 +912,8 @@ main (int argc, char *const *argv, char *const *envp MAYBE_UNUSED)
undivert_all ();
}
output_exit ();
+ if (makedep_path != NULL)
+ generate_make_dependencies (makedep_path, makedep_target, makedep_phony);
#ifndef NDEBUG
/* Only spend time freeing memory to help isolate leaks; if
assertions are disabled, save the time and exit now. */
diff --git a/src/m4.h b/src/m4.h
index 79dca438..d2d5c3f6 100644
--- a/src/m4.h
+++ b/src/m4.h
@@ -94,6 +94,14 @@
# undef bindtextdomain
# define bindtextdomain(Domainname, Dirname) /* empty */
#endif
+extern int makedep_gen_missing; /* --makedep-gen-missing-* */
+
+/* Bit masks indicating places a file is referenced from. */
+#define REF_CMD_LINE 0x01 /* File referenced from command line */
+#define REF_INCLUDE 0x02 /* File referenced from m4_include() */
+#define REF_SINCLUDE 0x04 /* File referenced from m4_sinclude() */
+#define REF_ALL 0x07 /* All of the above */
+#define REF_NONE 0x00 /* None of the above */
#define _(msgid) gettext (msgid)
@@ -545,6 +553,8 @@ extern void include_init (void);
extern void include_env_init (void);
extern void add_include_directory (const char *);
extern FILE *m4_path_search (const char *, bool, char **);
+extern void record_dependency (const char *, int);
+extern void generate_make_dependencies (const char *, const char *, int);
/* File: eval.c --- expression evaluation. */
diff --git a/src/path.c b/src/path.c
index 1c9993d6..93bd08d2 100644
--- a/src/path.c
+++ 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; /* pathname of this dependency */
+};
+
+typedef struct dependency dependency;
+
+static dependency *dependency_list; /* the list of dependencies */
+static dependency *dependency_list_end; /* the end of same */
void
@@ -194,6 +206,74 @@ m4_path_search (const char *file, bool binary, char **result)
return fp;
}
+void
+record_dependency (const char *path, int ref_from)
+{
+ dependency *dp;
+ for (dp = dependency_list; dp != NULL; dp = dp->next)
+ if (strcmp (path, dp->path) == 0)
+ {
+ /* Remember all the places this file has been referenced from. */
+ dp->ref_from |= ref_from;
+ return;
+ }
+
+ dp = xmalloc (sizeof (dependency));
+ dp->next = NULL;
+ dp->ref_from = ref_from;
+ dp->path = xstrdup (path);
+
+ if (dependency_list_end == NULL)
+ dependency_list = dp;
+ else
+ dependency_list_end->next = dp;
+ dependency_list_end = dp;
+}
+
+void
+generate_make_dependencies (const char *path, const char *target, int phony)
+{
+ FILE *fp;
+ size_t col, len, maxcol;
+ dependency *dp;
+
+ fp = fopen (path, "w");
+ if (fp == NULL)
+ {
+ m4_error (0, errno, NULL, _("unable to open %s"),
+ quotearg_style_mem (locale_quoting_style,
+ path, strlen (path)));
+ return;
+ }
+
+ fputs (_("# Automatically generated by GNU m4.\n"), fp);
+
+ /* Generate the main dependency rule. */
+ maxcol = 78;
+ fprintf (fp, "%s:", target);
+ col = strlen (target) + 1;
+ for (dp = dependency_list; dp != NULL; dp = dp->next)
+ {
+ len = 1 + strlen (dp->path);
+ if (col + len + 2 > maxcol) /* +2 is for trailing space/backslash */
+ {
+ fprintf (fp," \\\n ");
+ col = 1;
+ }
+ fprintf (fp, " %s", dp->path);
+ col += len;
+ }
+ fprintf (fp, "\n");
+
+ /* Generate phony targets for user-specified subset of dependencies. */
+ if (phony != 0)
+ for (dp = dependency_list; dp != NULL; dp = dp->next)
+ if ((dp->ref_from & phony) != 0)
+ fprintf (fp, "\n%s:\n", dp->path);
+
+ fclose (fp);
+}
+
#ifdef DEBUG_INCL
static void MAYBE_UNUSED
--------------n8uDVgn7VhLhPTQyNGk5DF1n
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<!DOCTYPE html>
<html>
<head>
<meta http-equiv=3D"content-type" content=3D"text/html; charset=3DUTF=
-8">
</head>
<body>
<pre>Eric,
I have incorporated most of the changes that you have identified. This
patch is from very recent branch-1.6.
David
NEWS | 2 +
THANKS | 2 +
checks/check-them | 37 ++++++++++-
checks/get-them | 13 +++-
doc/m4.texi | 195 ++++++++++++++++++++++++++++++++++++++++++++++++=
++++++
src/builtin.c | 16 ++++-
src/eval.c | 1 +
src/m4.c | 151 +++++++++++++++++++++++++++++++++++++++++-
src/m4.h | 10 +++
src/path.c | 80 ++++++++++++++++++++++
10 files changed, 496 insertions(+), 11 deletions(-)
diff --git a/NEWS b/NEWS
index 97c4d9c0..23d5bd5f 100644
--- a/NEWS
+++ b/NEWS
@@ -196,6 +196,8 @@ following beta features that were deemed worth deferr=
ing until 1.6:
=20
* Noteworthy changes in release 1.4.19 (2021-05-28) [stable]
=20
+** Add new capability to automatically generate make dependency rules.
+
** A number of portability improvements inherited from gnulib, including=
the ability to perform stack overflow detection on more platforms
without linking to GNU libsigsegv.
diff --git a/THANKS b/THANKS
index d441f56a..2e4de505 100644
--- a/THANKS
+++ b/THANKS
@@ -39,6 +39,7 @@ David Apps unlisted
David Arnstein <a class=3D"moz-txt-link-abbreviated" href=3D=
"mailto:[email protected]">[email protected]</a>
David J. MacKenzie <a class=3D"moz-txt-link-abbreviated" href=3D=
"mailto:[email protected]">[email protected]</a>
David Perlin <a class=3D"moz-txt-link-abbreviated" href=3D=
"mailto:[email protected]">[email protected]</a>
+David Warme <a class=3D"moz-txt-link-abbreviated" href=3D=
"mailto:[email protected]">[email protected]</a>
Elbert Pol <a class=3D"moz-txt-link-abbreviated" href=3D=
"mailto:[email protected]">[email protected]</a>
Elias Benali <a class=3D"moz-txt-link-abbreviated" href=3D=
"mailto:[email protected]">[email protected]</a>
Erez Zadok <a class=3D"moz-txt-link-abbreviated" href=3D=
"mailto:[email protected]">[email protected]</a>
@@ -81,6 +82,7 @@ Konrad Schwarz <a class=3D"moz-txt-link-a=
bbreviated" href=3D"mailto:[email protected]">konrad.schwarz@sie=
mens.com</a>
Kristine Lund <a class=3D"moz-txt-link-abbreviated" href=3D=
"mailto:[email protected]">[email protected]</a>
Krste Asanovic <a class=3D"moz-txt-link-abbreviated" href=3D=
"mailto:[email protected]">[email protected]</a>
Lawson Chan <a class=3D"moz-txt-link-abbreviated" href=3D=
"mailto:[email protected]">[email protected]</a>
+Lorenzo Di Gregorio <a class=3D"moz-txt-link-abbreviated" href=3D=
"mailto:[email protected]">[email protected]</a>
Marijn Schouten unlisted
Marion Hakanson <a class=3D"moz-txt-link-abbreviated" href=3D=
"mailto:[email protected]">[email protected]</a>
Mark Seiden <a class=3D"moz-txt-link-abbreviated" href=3D=
"mailto:[email protected]">[email protected]</a>
diff --git a/checks/check-them b/checks/check-them
index 24e68029..09c7c14f 100755
--- a/checks/check-them
+++ b/checks/check-them
@@ -37,6 +37,7 @@ out=3D$tmp/m4-out
err=3D$tmp/m4-err
xout=3D$tmp/m4-xout
xerr=3D$tmp/m4-xerr
+xaux=3D$tmp/m4-xaux
failed=3D
skipped=3D
strip_needed=3Dfalse
@@ -104,7 +105,8 @@ do
continue ;;
esac
=20
- options=3D`${SED} -ne '3s/^dnl @ extra options: //p;3q' "$file"`
+ options=3D`${SED} -ne '3s/^dnl @ extra options: //p;3q' "$file" \
+ | ${SED} -e "s/TMP\//$tmp\//"`
${SED} -e '/^dnl @/d' -e '/^\^D$/q' "$file" \
| LC_MESSAGES=3DC LANG=3DC M4PATH=3D$examples "$m4" -d $options - &g=
t;$out 2>$err
stat=3D$?
@@ -126,8 +128,9 @@ do
=20
xoutfile=3D`${SED} -n 's/^dnl @ expected output: //p' "$file"`
if test -z "$xoutfile" ; then
- ${SED} -e '/^dnl @result{}/!d' -e 's///' -e "s|examples/|$examples/|=
" \
- -e "s|@value{VERSION}|$m4version|" "$file" > $xout
+ ${SED} -ne 's/^dnl @result{}//p' "$file" \
+ | ${SED} -e "s|examples/|$examples/|" \
+ -e "s|@value{VERSION}|$m4version|" > $xout
else
cp "$examples/$xoutfile" $xout
fi
@@ -149,6 +152,8 @@ do
"$examples/$xerrfile" > $xerr ;;
esac
=20
+ auxfile=3D`${SED} -n 's/^dnl @ expected auxfile: //p' "$file"`
+
# For the benefit of mingw, normalize \r\n line endings
if $strip_needed ; then
tr -d '\015' < $out > $out.t
@@ -179,6 +184,32 @@ do
diff $diffopts $xerr $err
fi
=20
+ if test -n "$auxfile"; then
+ tauxfile=3D`echo "$auxfile" | ${SED} -e "s/TMP\//$tmp\//"`
+ if test -f "$tauxfile"; then
+ ${SED} -ne 's|^dnl @auxresult{[A-Za-z0-9_/]*}||p' < $file >$=
xaux
+ if $strip_needed ; then
+ tr -d '\015' < $tauxfile > $tauxfile.t
+ mv $tauxfile.t $tauxfile
+ tr -d '\015' < $xaux > $xaux.t
+ mv $xaux.t $xaux
+ fi
+ if cmp -s $tauxfile $xaux; then
+ :
+ else
+ failed=3D"$failed $<a class=3D"moz-txt-link-freetext" href=3D"fi=
le:aux">file:aux</a>"
+ echo `${SED} -e 's/^dnl //' -e 1q $file`
+ echo "$file auxfile mismatch"
+ diff $diffopts $xaux $tauxfile
+ fi
+ rm -f $tauxfile
+ else
+ failed=3D"$failed $<a class=3D"moz-txt-link-freetext" href=3D"file=
:aux">file:aux</a>"
+ echo `${SED} -e 's/^dnl //' -e 1q $file`
+ echo "$file aux outfile $auxfile does not exist"
+ fi
+ fi
+
done
=20
rm -f $out $err $xout $xerr
diff --git a/checks/get-them b/checks/get-them
index 9028a6e3..dafdb591 100755
--- a/checks/get-them
+++ b/checks/get-them
@@ -36,6 +36,7 @@ BEGIN {
options =3D "";
xout =3D "";
xerr =3D "";
+ auxfile =3D "";
}
=20
/^@node / {
@@ -83,6 +84,11 @@ BEGIN {
gsub ("@comment xerr: ", "", xerr);
}
=20
+/^@comment auxfile: / {
+ auxfile =3D $0;
+ gsub ("@comment auxfile: ", "", auxfile);
+}
+
/^@example$/, /^@end example$/ {
if (seq < 0)
next;
@@ -105,10 +111,13 @@ BEGIN {
printf("dnl @ expected output: %s\n", xout) > file;
if (xerr)
printf("dnl @ expected error: %s\n", xerr) > file;
+ if (auxfile)
+ printf("dnl @ expected auxfile: %s\n", auxfile) > file;
status =3D 0;
options =3D "";
xout =3D "";
xerr =3D "";
+ auxfile =3D "";
next;
}
if ($0 ~ /^@end example$/) {
@@ -116,9 +125,9 @@ BEGIN {
}
if ($0 ~ /^\^D$/)
next;
- if ($0 ~ /^\$ @kbd/)
+ if ($0 ~ /^\$ @kbd/ || $0 ~ /^@kbd/)
next;
- if ($0 ~ /^@result\{\}/ || $0 ~ /^@error\{\}/)
+ if ($0 ~ /^@result\{\}/ || $0 ~ /^@error\{\}/ || $0 ~ /^@auxresult\{[A=
-Za-z0-9_\/]*\}/)
prefix =3D "dnl ";
else
prefix =3D "<a class=3D"moz-txt-link-rfc2396E" href=3D"mailto:;diff-=
-gita/doc/m4.texib/doc/m4.texiindex612ed945..e7a9d5f6100644---a/doc/m4.te=
xi+++b/doc/m4.texi@@-36,6+36,14@@@r{[}@var{\varname\}=3D@samp{\default\}@=
r{]}@endmacro+@c@auxresult{auxfile}+@c------------+@cUsedinexamplestoindi=
cateoutputproducedwithinthe+@c``auxilliaryoutputfile.''+@macroauxresult{a=
uxfile}+\auxfile\@b{@result{}}+@endmacro+@comment%**endofheader@comment=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D@@-148,6+156,7@@*Preprocessorfeatures::Commandlineoptionsf=
orpreprocessorfeatures*Limitscontrol::Commandlineoptionsforlimitscontrol*=
Frozenstate::Commandlineoptionsforfrozenstate+*Makedependencygeneration::=
Generatingmakedependencyrules*Debuggingoptions::Commandlineoptionsfordebu=
gging*Commandlinefiles::Specifyinginputfilesonthecommandline@@-583,6+592,=
7@@*Preprocessorfeatures::Commandlineoptionsforpreprocessorfeatures*Limit=
scontrol::Commandlineoptionsforlimitscontrol*Frozenstate::Commandlineopti=
onsforfrozenstate+*Makedependencygeneration::Generatingmakedependencyrule=
s*Debuggingoptions::Commandlineoptionsfordebugging*Commandlinefiles::Spec=
ifyinginputfilesonthecommandline@endmenu@@-904,6+914,191@@filesareread.@e=
ndtable+@nodeMakedependencygeneration+@sectionCommandlineoptionsforgenera=
tingMakefiledependencyrules++Makefiledependencyrulescanbeautomaticallygen=
eratedbyspecifying+boththe@code{--makedep=3D}@var{file}and+@code{--makede=
p-target=3D}@var{target}options.++@table@code+@item--makedep=3D@var{file}=
+Causes@code{m4}togenerateadependencyruleintothespecified+@var{file}.Macr=
oexpansionoutputisstillwrittentostdoutas+normal.Thisoptionisanalogoustoth=
e@code{-MF}optionof+@code{gcc}.++@item--makedep-target=3D@var{target}+Spe=
cifies@var{target}tobethetargetofthegenerateddependency+rule.Thestring@va=
r{target}isusedverbatim,andcancontainseveral+logicaltargetsseparatedbyspa=
ces.Itistheuser'sresponsibilityto+properlyexpresscharactersthat@code{make=
}handlesspecially(suchas+'@code{$}',orspaceswithinfilenames).Since@code{m=
4}sendsits+macroexpansionoutputtostdout,itneverreallyknowsthenameofthe+ta=
rgetfilebeinggenerated,sothetargetmustalwaysbespecified+explicitlybytheus=
erwiththisoption.Thisoptionisanalogousto+the@code{-MT}optionof@code{gcc}(=
exceptthat@code{gcc}allows+@code{-MT}tobespecifiedmultipletimes).+@endtab=
le++Notethatthe@code{--makedep=3D}@var{file}and+@code{makedep-target=3D}@=
var{target}optionsmusteither(a)bothbe+specified,or(b)neitherbespecified.T=
heycannotbeused+independentlyofeachother.++@commentoptions:--makedep=3DTM=
P/depfile--makedep-target=3DTargetfoo+@commentauxfile:TMP/depfile+@exampl=
e+$@kbd{m4-Iexamples--makedep=3DTMP/depfile--makedep-target=3DTargetfoo}+=
@result{}bar+@auxresult{TMP/depfile}#AutomaticallygeneratedbyGNUm4.+@auxr=
esult{TMP/depfile}Target:./../examples/foo+@endexample++@commentSeparatet=
hesetwoexamples.+@sp1++@commentoptions:--makedep=3DTMP/depfile--makedep-t=
arget=3DTargetfoo+@commentauxfile:TMP/depfile+@example+$@kbd{m4-Iexamples=
--makedep=3DTMP/depfile--makedep-target=3DTargetfoo-}+@result{}bar+includ=
e(`incl.m4')+@result{}Includefilestart+@result{}foo+@result{}Includefilee=
nd+@result{}+^D+@auxresult{TMP/depfile}#AutomaticallygeneratedbyGNUm4.+@a=
uxresult{TMP/depfile}Target:./../examples/foo./../examples/incl.m4+@endex=
ample++Thefollowingadditionaloptionscanalsobeusedwhendependencyrules+areb=
einggenerated(theseoptionsareonlyvalidwhenboth+@code{makedep=3D}@var{file=
}and@code{makedep-target=3D}@var{target}have+alsobeenspecified):++@table@=
code+@item--makedep-gen-missing-argfiles+Causes@code{m4}toassumethatanyfi=
lelistedonthecommandlinethat+ismissing(i.e.,doesnotexist)isanautomaticall=
ygeneratedfile.+@code{M4}includessuchmissingfilesasdependenciesinthegener=
ated+ruleregardless.Inthiscasethedependencyappearsexactlyas+specifiedonth=
ecommandlineandisnotmodifiedbyany+@code{-I}@var{searchdir}prefixes.Noteth=
atthemacroexpansionoutput+generatedtostdoutwillbeincorrectwhenthishappens=
becausethe+missingfileisassumedtobeanemptyfile.Awarningisproducedon+stder=
rforeachmissingcommandlinefilehandledinthismanner.++@item--makedep-gen-mi=
ssing-include+Causes@code{m4}toassumethatanyfileincludedviathe+@code{incl=
ude()}macrothatismissing(i.e.,doesnotexist)isan+automaticallygeneratedfil=
e.@code{M4}includessuchmissingfilesas+dependenciesinthegeneratedruleregar=
dless.Inthiscasethe+dependencyappearsexactlyasspecifiedintheargumentto+@c=
ode{include()}andisnotmodifiedbyany@code{-I}@var{searchdir}+prefixes.Note=
thatthemacroexpansionoutputgeneratedtostdoutwill+beincorrectwhenthishappe=
nsbecausethemissingfileisassumedtobe+anemptyfile.Thisoptioncausesthe@code=
{m4}@code{include()}macro+tobehavelike@code{sinclude()},exceptthatawarnin=
gmessageis+producedonstderrtoindicatethattherequestedfilewasmissing.+This=
optionisanalogoustothe@code{-MG}optionof@code{gcc}.++@item--makedep-gen-m=
issing-sinclude+Causes@code{m4}toassumethatanyfileincludedviathe+@code{si=
nclude()}macrothatismissing(i.e.,doesnotexist)isan+automaticallygenerated=
file.@code{M4}includessuchmissingfilesas+dependenciesinthegeneratedrulere=
gardless.Inthiscasethe+dependencyappearsexactlyasspecifiedintheargumentto=
+@code{sinclude()}andisnotmodifiedbyany@code{-I}@var{searchdir}+prefixes.=
Notethatthemacroexpansionoutputgeneratedtostdoutwill+beincorrectwhenthish=
appensbecausethemissingfileisassumedtobe+anemptyfile.Thisoptiondoesnotalt=
er@code{sinclude()}'sbehavior+ofsilentlyignoringrequeststo@code{sinclude(=
)}filesthatdonotexist.++@item--makedep-gen-missing-all+Thisoptionisequiva=
lenttospecifyingallthreeoptions+@code{--makedep-gen-missing-argfiles},+@c=
ode{--makedep-gen-missing-include}and+@code{--makedep-gen-missing-sinclud=
e}.+@endtable++Notethattheabove@code{makedep-gen-missing-*}optionsassumet=
hatthe+missingfileswillultimatelynot@code{include()}or@code{sinclude()}+a=
nyadditionalfiles--iftheydo,thentheseadditionalfileswillbe+missingfromthe=
generateddependencyrules.+++@commentstatus:1+@commentoptions:--makedep=3D=
TMP/depfile--makedep-target=3DTarget--makedep-gen-missing-allfoonone+@com=
mentauxfile:TMP/depfile+@example+$@kbd{m4-Iexamples--makedep=3DTMP/depfil=
e--makedep-target=3DTarget\}+@kbd{--makedep-gen-missing-allfoonone-}+@res=
ult{}bar+@error{}m4:cannotopen'none':Nosuchfileordirectory+include(`incl.=
m4')+@result{}Includefilestart+@result{}foo+@result{}Includefileend+@resu=
lt{}+include(`none2')+@result{}+@error{}m4:stdin:2:include:cannotopen'non=
e2':Nosuchfileordirectory+sinclude(`none3')+@result{}+^D+@auxresult{TMP/d=
epfile}#AutomaticallygeneratedbyGNUm4.+@auxresult{TMP/depfile}Target:./..=
/examples/foonone./../examples/incl.m4none2none3+@endexample++Thefollowin=
goptionscontrolthegenerationof``phony''targetsfor+certainclassesofdepende=
ncies.Thesedummyrulesareusedtowork+arounderrors@code{make}givesifyouremov=
efileswithoutupdatingthe+@code{Makefile}tomatch.Dependenciesthatmatchoneo=
rmoreofthese+classescauseasingledummyruletobegeneratedforthem:++@table@co=
de+@item--makedep-phony-argfiles+Causes@code{m4}togeneratea``phony''targe=
tforeachfilethatis+specifiedonthecommandline.++@item--makedep-phony-inclu=
de+Causes@code{m4}togeneratea``phony''targetforeachfilethatis+thesubjecto=
fan@code{include()}macro.Thisoptionisanalogousto+the@code{-MP}optionof@co=
de{gcc}.++@item--makedep-phony-sinclude+Causes@code{m4}togeneratea``phony=
''targetforeachfilethatis+thesubjectofan@code{sinclude()}macro.++@item--m=
akedep-phony-all+isequivalenttospecifyingallthreeoptions:+@code{--makedep=
-phony-argfiles}+@code{--makedep-phony-include}+@code{--makedep-phony-sin=
clude}.+@endtable++@commentoptions:--makedep=3DTMP/depfile--makedep-targe=
t=3DTarget--makedep-phony-allfoo+@commentauxfile:TMP/depfile+@example+$@k=
bd{m4-Iexamples--makdep=3DTMP/depfile--makedep-target=3DTarget\}+@kbd{--m=
akedep-phony-allfoo-}+@result{}bar+include(`incl.m4')+@result{}Includefil=
estart+@result{}foo+@result{}Includefileend+@result{}+^D+@auxresult{TMP/d=
epfile}#AutomaticallygeneratedbyGNUm4.+@auxresult{TMP/depfile}Target:./..=
/examples/foo./../examples/incl.m4+@auxresult{TMP/depfile}+@auxresult{TMP=
/depfile}./../examples/foo:+@auxresult{TMP/depfile}+@auxresult{TMP/depfil=
e}./../examples/incl.m4:+@endexample+@nodeDebuggingoptions@sectionCommand=
lineoptionsfordebuggingdiff--gita/src/builtin.cb/src/builtin.cindexbf0d17=
98..36b9ed00100644---a/src/builtin.c+++b/src/builtin.c@@-1494,13+1494,14@=
@m4_changecom(structobstack*obsMAYBE_UNUSED,intargc,argument,ifitexists.C=
omplainaboutinaccessiblefilesiffSILENTisfalse.*/staticvoid-include(intarg=
c,macro_arguments*argv,boolsilent)+include(intargc,macro_arguments*argv,b=
oolsilent,intref_from){constcall_info*me=3Darg_info(argv);FILE*fp;char*na=
me;constchar*arg;size_tlen;+intfail;if(bad_argc(me,argc,1,1))return;@@-15=
13,12+1514,21@@include(intargc,macro_arguments*argv,boolsilent)fp=3Dm4_pa=
th_search(arg,false,&name);if(fp=3D=3DNULL){+fail=3D!silent;+if((make=
dep_gen_missing&ref_from)!=3D0)+{+record_dependency(arg,ref_from);+fa=
il=3D0;+}if(!silent)m4_error(0,errno,me,_(">";
diff --git a/doc/m4.texi b/doc/m4.texi
index 612ed945..e7a9d5f6 100644
--- a/doc/m4.texi
+++ b/doc/m4.texi
@@ -36,6 +36,14 @@
@r{[}@var{\varname\} =3D @samp{\default\}@r{]}
@end macro
=20
+@c @auxresult{auxfile}
+@c ------------
+@c Used in examples to indicate output produced within the
+@c ``auxilliary output file.''
+@macro auxresult{auxfile}
+\auxfile\ @b{@result{}}
+@end macro
+
@comment %**end of header
@comment =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
=20
@@ -148,6 +156,7 @@
* Preprocessor features:: Command line options for preprocessor fe=
atures
* Limits control:: Command line options for limits control
* Frozen state:: Command line options for frozen state
+* Make dependency generation:: Generating make dependency rules
* Debugging options:: Command line options for debugging
* Command line files:: Specifying input files on the command li=
ne
=20
@@ -583,6 +592,7 @@
* Preprocessor features:: Command line options for preprocessor fe=
atures
* Limits control:: Command line options for limits control
* Frozen state:: Command line options for frozen state
+* Make dependency generation:: Generating make dependency rules
* Debugging options:: Command line options for debugging
* Command line files:: Specifying input files on the command li=
ne
@end menu
@@ -904,6 +914,191 @@
files are read.
@end table
=20
+@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=3D}@var{file} and
+@code{--makedep-target=3D}@var{target} options.
+
+@table @code
+@item --makedep=3D@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=3D@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=3D}@var{file} and
+@code{makedep-target=3D}@var{target} options must either (a) both be
+specified, or (b) neither be specified. They cannot be used
+independently of each other.
+
+@comment options: --makedep=3DTMP/depfile --makedep-target=3DTarget foo
+@comment auxfile: TMP/depfile
+@example
+$ @kbd{m4 -I examples --makedep=3DTMP/depfile --makedep-target=3DTarget =
foo}
+@result{}bar
+@auxresult{TMP/depfile}# Automatically generated by GNU m4.
+@auxresult{TMP/depfile}Target: ./../examples/foo
+@end example
+
+@comment Separate these two examples.
+@sp 1
+
+@comment options: --makedep=3DTMP/depfile --makedep-target=3DTarget foo
+@comment auxfile: TMP/depfile
+@example
+$ @kbd{m4 -I examples --makedep=3DTMP/depfile --makedep-target=3DTarget =
foo -}
+@result{}bar
+include(`incl.m4')
+@result{}Include file start
+@result{}foo
+@result{}Include file end
+@result{}
+^D
+@auxresult{TMP/depfile}# Automatically generated by GNU m4.
+@auxresult{TMP/depfile}Target: ./../examples/foo ./../examples/incl.m4
+@end example
+
+The following additional options can also be used when dependency rules
+are being generated (these options are only valid when both
+@code{makedep=3D}@var{file} and @code{makedep-target=3D}@var{target} hav=
e
+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 exi=
st.
+
+@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.
+
+
+@comment status: 1
+@comment options: --makedep=3DTMP/depfile --makedep-target=3DTarget --ma=
kedep-gen-missing-all foo none
+@comment auxfile: TMP/depfile
+@example
+$ @kbd{m4 -I examples --makedep=3DTMP/depfile --makedep-target=3DTarget =
\}
+@kbd{ --makedep-gen-missing-all foo none -}
+@result{}bar
+@error{}m4: cannot open 'none': No such file or directory
+include(`incl.m4')
+@result{}Include file start
+@result{}foo
+@result{}Include file end
+@result{}
+include(`none2')
+@result{}
+@error{}m4:stdin:2: include: cannot open 'none2': No such file or direct=
ory
+sinclude(`none3')
+@result{}
+^D
+@auxresult{TMP/depfile}# Automatically generated by GNU m4.
+@auxresult{TMP/depfile}Target: ./../examples/foo none ./../examples/incl=
=2Em4 none2 none3
+@end example
+
+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
+
+@comment options: --makedep=3DTMP/depfile --makedep-target=3DTarget --ma=
kedep-phony-all foo
+@comment auxfile: TMP/depfile
+@example
+$ @kbd{m4 -I examples --makdep=3DTMP/depfile --makedep-target=3DTarget \=
}
+@kbd{ --makedep-phony-all foo -}
+@result{}bar
+include(`incl.m4')
+@result{}Include file start
+@result{}foo
+@result{}Include file end
+@result{}
+^D
+@auxresult{TMP/depfile}# Automatically generated by GNU m4.
+@auxresult{TMP/depfile}Target: ./../examples/foo ./../examples/incl.m4
+@auxresult{TMP/depfile}
+@auxresult{TMP/depfile}./../examples/foo:
+@auxresult{TMP/depfile}
+@auxresult{TMP/depfile}./../examples/incl.m4:
+@end example
+
@node Debugging options
@section Command line options for debugging
=20
diff --git a/src/builtin.c b/src/builtin.c
index bf0d1798..36b9ed00 100644
--- a/src/builtin.c
+++ b/src/builtin.c
@@ -1494,13 +1494,14 @@ m4_changecom (struct obstack *obs MAYBE_UNUSED, i=
nt argc,
argument, if it exists. Complain about inaccessible files iff
SILENT is false. */
static void
-include (int argc, macro_arguments *argv, bool silent)
+include (int argc, macro_arguments *argv, bool silent, int ref_from)
{
const call_info *me =3D arg_info (argv);
FILE *fp;
char *name;
const char *arg;
size_t len;
+ int fail;
=20
if (bad_argc (me, argc, 1, 1))
return;
@@ -1513,12 +1514,21 @@ include (int argc, macro_arguments *argv, bool si=
lent)
fp =3D m4_path_search (arg, false, &name);
if (fp =3D=3D NULL)
{
+ fail =3D !silent;
+ if ((makedep_gen_missing & ref_from) !=3D 0)
+ {
+ record_dependency (arg, ref_from);
+ fail =3D 0;
+ }
if (!silent)
m4_error (0, errno, me, _("</a>cannot open %s"),
quotearg_style (locale_quoting_style, arg));
+ if (fail)
+ retcode =3D EXIT_FAILURE;
return;
}
=20
+ record_dependency (name, ref_from);
push_file (fp, name, true);
free (name);
}
@@ -1527,7 +1537,7 @@ include (int argc, macro_arguments *argv, bool sile=
nt)
static void
m4_include (struct obstack *obs MAYBE_UNUSED, int argc, macro_arguments =
*argv)
{
- include (argc, argv, false);
+ include (argc, argv, false, REF_INCLUDE);
}
=20
/* Include a file, ignoring errors. */
@@ -1535,7 +1545,7 @@ static void
m4_sinclude (struct obstack *obs MAYBE_UNUSED, int argc,
macro_arguments *argv)
{
- include (argc, argv, true);
+ include (argc, argv, true, REF_SINCLUDE);
}
=0C
/* More miscellaneous builtins -- "maketemp", "errprint", "__file__",
diff --git a/src/eval.c b/src/eval.c
index 69cd5e41..d91fa3cd 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -431,6 +431,7 @@ parse_expr (int32_t *v1, eval_error er, unsigned min_=
prec)
that the implementation-defined overflow when casting
unsigned to signed is a silent twos-complement
wrap-around. */
+ u3 =3D 1;
if (v2 < 0)
er =3D NEGATIVE_EXPONENT;
else if (*v1 =3D=3D 0 && v2 =3D=3D 0)
diff --git a/src/m4.c b/src/m4.c
index 89a2ec2f..aa2327a5 100644
--- a/src/m4.c
+++ b/src/m4.c
@@ -65,6 +65,21 @@ int warning_status =3D 0;
/* Artificial limit for expansion_level in macro.c. */
int nesting_limit =3D 1024;
=20
+/* Pathname of dependency file being made (--makedep=3DPATH). */
+static const char *makedep_path =3D NULL;
+
+/* Target for dependency rule being made (--makedep-target=3DTARGET). */=
+static const char *makedep_target =3D NULL;
+
+/* Bitmask of places that will assume non-existent files are actually
+ generated, and so a dependency should be listed regardless
+ (--makedep-gen-missing-*). */
+int makedep_gen_missing =3D REF_NONE;
+
+/* Bitmask of which places files are referenced from that will trigger
+ phony rules to be generated (--makedep-phony-*). */
+static int makedep_phony =3D REF_NONE;
+
/* Global catchall for any errors that should affect final error status,=
but
where we try to continue execution in the meantime. */
int retcode;
@@ -283,6 +298,37 @@ Frozen state files:\n\
"), stdout);
puts ("");
fputs (_("\
+Make dependency generation:\n\
+ --makedep=3DFILE write make dependency rule(s) into FILE=
\n\
+ --makedep-target=3DTARGET specify target of generated dependency =
rule\n\
+ The --makedep and --makedep-target opti=
ons\n\
+ must be used together, either both pres=
ent,\n\
+ or neither present.\n\
+ --makedep-gen-missing-argfiles\n\
+ --makedep-gen-missing-include\n\
+ --makedep-gen-missing-sinclude\n\
+ files that do not exist (on command line,=
\n\
+ via include(), or via sinclude(),\n\
+ respectively) are assumed to be generat=
ed\n\
+ files and become dependencies regardles=
s.\n\
+ --makedep-gen-missing-all\n\
+ equivalent to --makedep-gen-missing-argfi=
les\n\
+ --makedep-gen-missing-include\n\
+ --makedep-gen-missing-sinclude\n\
+ --makedep-phony-argfiles\n\
+ --makedep-phony-include\n\
+ --makedep-phony-sinclude\n\
+ generate a \"phony\" target for each file=
\n\
+ that is specified on the command line, =
the\n\
+ subject of an include() macro, or the\n=
\
+ subject of an sinclude() macro,\n\
+ respectively.\n\
+ --makedep-phony-all equivalent to --makedep-phony-argfiles\n\=
+ --makedep-phony-include\n\
+ --makedep-phony-sinclude\n\
+"), stdout);
+ puts ("");
+ fputs (_("\
Debugging:\n\
-d, --debug[=3D[-|+]FLAGS], --debugmode[=3D[-|+]FLAGS]\n\
set debug level (no FLAGS implies `+adeq'=
)\n\
@@ -333,6 +379,16 @@ enum
{
DEBUGFILE_OPTION =3D CHAR_MAX + 1, /* no short opt */
WARN_MACRO_SEQUENCE_OPTION, /* no short opt */
+ MAKEDEP_OPTION, /* no short opt */
+ MAKEDEP_TARGET_OPTION, /* no short opt */
+ MAKEDEP_GEN_MISSING_ARGFILES_OPTION, /* no short opt */
+ MAKEDEP_GEN_MISSING_INCLUDE_OPTION, /* no short opt */
+ MAKEDEP_GEN_MISSING_SINCLUDE_OPTION, /* no short opt */
+ MAKEDEP_GEN_MISSING_ALL_OPTION, /* no short opt */
+ MAKEDEP_PHONY_ARGFILES_OPTION, /* no short opt */
+ MAKEDEP_PHONY_INCLUDE_OPTION, /* no short opt */
+ MAKEDEP_PHONY_SINCLUDE_OPTION, /* no short opt */
+ MAKEDEP_PHONY_ALL_OPTION, /* no short opt */
=20
HELP_OPTION, /* no short opt */
VERSION_OPTION /* no short opt */
@@ -365,6 +421,21 @@ static const struct option long_options[] =3D {
{"warn-macro-sequence", optional_argument, NULL,
WARN_MACRO_SEQUENCE_OPTION},
=20
+ {"makedep", required_argument, NULL, MAKEDEP_OPTION},
+ {"makedep-target", required_argument, NULL, MAKEDEP_TARGET_OPTION},
+ {"makedep-gen-missing-argfiles", no_argument, NULL,
+ MAKEDEP_GEN_MISSING_ARGFILES_OPTION},
+ {"makedep-gen-missing-include", no_argument, NULL,
+ MAKEDEP_GEN_MISSING_INCLUDE_OPTION},
+ {"makedep-gen-missing-sinclude", no_argument, NULL,
+ MAKEDEP_GEN_MISSING_SINCLUDE_OPTION},
+ {"makedep-gen-missing-all", no_argument, NULL,
+ MAKEDEP_GEN_MISSING_ALL_OPTION},
+ {"makedep-phony-argfiles", no_argument, NULL, MAKEDEP_PHONY_ARGFILES_O=
PTION},
+ {"makedep-phony-include", no_argument, NULL, MAKEDEP_PHONY_INCLUDE_OPT=
ION},
+ {"makedep-phony-sinclude", no_argument, NULL, MAKEDEP_PHONY_SINCLUDE_O=
PTION},
+ {"makedep-phony-all", no_argument, NULL, MAKEDEP_PHONY_ALL_OPTION},
+
{"help", no_argument, NULL, HELP_OPTION},
{"version", no_argument, NULL, VERSION_OPTION},
=20
@@ -394,11 +465,15 @@ process_file (const char *name)
{
error (0, errno, _("cannot open %s"),
quotearg_style (locale_quoting_style, name));
- /* Set the status to EXIT_FAILURE, even though we
- continue to process files after a missing file. */
- retcode =3D EXIT_FAILURE;
+ if ((makedep_gen_missing & REF_CMD_LINE) !=3D 0)
+ record_dependency (name, REF_CMD_LINE);
+ else
+ /* Set the status to EXIT_FAILURE, even though we
+ continue to process files after a missing file. */
+ retcode =3D EXIT_FAILURE;
return;
}
+ record_dependency (full_name, REF_CMD_LINE);
push_file (fp, full_name, true);
free (full_name);
}
@@ -641,6 +716,50 @@ main (int argc, char *const *argv, char *const *envp=
MAYBE_UNUSED)
(which disables these warnings). */
macro_sequence =3D optarg;
break;
+=20
+ case MAKEDEP_OPTION:
+ if (makedep_path !=3D NULL)
+ usage (EXIT_FAILURE);
+ makedep_path =3D optarg;
+ break;
+
+ case MAKEDEP_TARGET_OPTION:
+ if (makedep_target !=3D NULL)
+ usage (EXIT_FAILURE);
+ makedep_target =3D optarg;
+ break;
+
+ case MAKEDEP_GEN_MISSING_ARGFILES_OPTION:
+ makedep_gen_missing |=3D REF_CMD_LINE;
+ break;
+
+ case MAKEDEP_GEN_MISSING_INCLUDE_OPTION:
+ makedep_gen_missing |=3D REF_INCLUDE;
+ break;
+
+ case MAKEDEP_GEN_MISSING_SINCLUDE_OPTION:
+ makedep_gen_missing |=3D REF_SINCLUDE;
+ break;
+
+ case MAKEDEP_GEN_MISSING_ALL_OPTION:
+ makedep_gen_missing |=3D REF_ALL;
+ break;
+
+ case MAKEDEP_PHONY_ARGFILES_OPTION:
+ makedep_phony |=3D REF_CMD_LINE;
+ break;
+
+ case MAKEDEP_PHONY_INCLUDE_OPTION:
+ makedep_phony |=3D REF_INCLUDE;
+ break;
+
+ case MAKEDEP_PHONY_SINCLUDE_OPTION:
+ makedep_phony |=3D REF_SINCLUDE;
+ break;
+
+ case MAKEDEP_PHONY_ALL_OPTION:
+ makedep_phony |=3D REF_ALL;
+ break;
=20
case VERSION_OPTION:
version_etc (stdout, PACKAGE, PACKAGE_NAME, VERSION, AUTHORS, NU=
LL);
@@ -659,6 +778,30 @@ main (int argc, char *const *argv, char *const *envp=
MAYBE_UNUSED)
m4_error (0, errno, NULL, _("cannot set debug file %s"),
quotearg_style (locale_quoting_style, debugfile));
=20
+ /* Verify mutual consistency of makedep options. */
+ if ((makedep_path =3D=3D NULL) && (makedep_target =3D=3D NULL)=
)
+ {
+ /* Makedep mode is NOT active. */
+ if (makedep_gen_missing !=3D 0)
+ m4_error (0, 0, NULL,
+ _("--makedep-gen-missing-* requires --makedep and --ma=
kedep-target"));
+ if (makedep_phony !=3D 0)
+ m4_error (0, 0, NULL,
+ _("--makedep-phony-* requires --makedep and --makedep-=
target"));
+ if ((makedep_gen_missing | makedep_phony) !=3D 0)
+ exit (EXIT_FAILURE);
+ }
+ else if ((makedep_path !=3D NULL) && (makedep_target !=3D NULL=
))
+ {
+ /* Makedep mode is active. */
+ }
+ else
+ {
+ m4_error (0, 0, NULL,
+ _("--makedep must be used with --makedep-target"));
+ exit (EXIT_FAILURE);
+ }
+
input_init ();
output_init ();
symtab_init (hash_table_size);
@@ -769,6 +912,8 @@ main (int argc, char *const *argv, char *const *envp =
MAYBE_UNUSED)
undivert_all ();
}
output_exit ();
+ if (makedep_path !=3D NULL)
+ generate_make_dependencies (makedep_path, makedep_target, makedep_ph=
ony);
#ifndef NDEBUG
/* Only spend time freeing memory to help isolate leaks; if
assertions are disabled, save the time and exit now. */
diff --git a/src/m4.h b/src/m4.h
index 79dca438..d2d5c3f6 100644
--- a/src/m4.h
+++ b/src/m4.h
@@ -94,6 +94,14 @@
# undef bindtextdomain
# define bindtextdomain(Domainname, Dirname) /* empty */
#endif
+extern int makedep_gen_missing; /* --makedep-gen-missing-* */
+
+/* Bit masks indicating places a file is referenced from. */
+#define REF_CMD_LINE 0x01 /* File referenced from command line */
+#define REF_INCLUDE 0x02 /* File referenced from m4_include() */
+#define REF_SINCLUDE 0x04 /* File referenced from m4_sinclude() */=
+#define REF_ALL 0x07 /* All of the above */
+#define REF_NONE 0x00 /* None of the above */
=20
#define _(msgid) gettext (msgid)
=0C
@@ -545,6 +553,8 @@ extern void include_init (void);
extern void include_env_init (void);
extern void add_include_directory (const char *);
extern FILE *m4_path_search (const char *, bool, char **);
+extern void record_dependency (const char *, int);
+extern void generate_make_dependencies (const char *, const char *, int)=
;
=0C
/* File: eval.c --- expression evaluation. */
=20
diff --git a/src/path.c b/src/path.c
index 1c9993d6..93bd08d2 100644
--- a/src/path.c
+++ 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 */
+=20
+struct dependency
+{
+ struct dependency *next; /* next in list of dependencies */
+ int ref_from; /* bit mask: places file referenced from=
*/
+ char *path; /* pathname of this dependency */
+};
+
+typedef struct dependency dependency;
+
+static dependency *dependency_list; /* the list of dependencies */
+static dependency *dependency_list_end; /* the end of same */
=0C
=20
void
@@ -194,6 +206,74 @@ m4_path_search (const char *file, bool binary, char =
**result)
return fp;
}
=20
+void
+record_dependency (const char *path, int ref_from)
+{
+ dependency *dp;
+ for (dp =3D dependency_list; dp !=3D NULL; dp =3D dp->next)
+ if (strcmp (path, dp->path) =3D=3D 0)
+ {
+ /* Remember all the places this file has been referenced from. *=
/
+ dp->ref_from |=3D ref_from;
+ return;
+ }
+
+ dp =3D xmalloc (sizeof (dependency));
+ dp->next =3D NULL;
+ dp->ref_from =3D ref_from;
+ dp->path =3D xstrdup (path);
+
+ if (dependency_list_end =3D=3D NULL)
+ dependency_list =3D dp;
+ else
+ dependency_list_end->next =3D dp;
+ dependency_list_end =3D dp;
+}
+
+void
+generate_make_dependencies (const char *path, const char *target, int ph=
ony)
+{
+ FILE *fp;
+ size_t col, len, maxcol;
+ dependency *dp;
+
+ fp =3D fopen (path, "w");
+ if (fp =3D=3D NULL)
+ {
+ m4_error (0, errno, NULL, _("unable to open %s"),
+ quotearg_style_mem (locale_quoting_style,
+ path, strlen (path)));
+ return;
+ }
+
+ fputs (_("# Automatically generated by GNU m4.\n"), fp);
+
+ /* Generate the main dependency rule. */
+ maxcol =3D 78;
+ fprintf (fp, "%s:", target);
+ col =3D strlen (target) + 1;
+ for (dp =3D dependency_list; dp !=3D NULL; dp =3D dp->next)
+ {
+ len =3D 1 + strlen (dp->path);
+ if (col + len + 2 > maxcol) /* +2 is for trailing space/backsla=
sh */
+ {
+ fprintf (fp," \\\n ");
+ col =3D 1;
+ }
+ fprintf (fp, " %s", dp->path);
+ col +=3D len;
+ }
+ fprintf (fp, "\n");
+
+ /* Generate phony targets for user-specified subset of dependencies. *=
/
+ if (phony !=3D 0)
+ for (dp =3D dependency_list; dp !=3D NULL; dp =3D dp->next)
+ if ((dp->ref_from & phony) !=3D 0)
+ fprintf (fp, "\n%s:\n", dp->path);
+
+ fclose (fp);
+}
+
#ifdef DEBUG_INCL
=20
static void MAYBE_UNUSED
</pre>
</body>
</html>
--------------n8uDVgn7VhLhPTQyNGk5DF1n--
--===============6877030795792928262==
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: base64
Content-Disposition: inline
X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18KTTQtcGF0Y2hl
cyBtYWlsaW5nIGxpc3QKTTQtcGF0Y2hlc0BnbnUub3JnCmh0dHBzOi8vbGlzdHMuZ251Lm9yZy9t
YWlsbWFuL2xpc3RpbmZvL200LXBhdGNoZXMK
--===============6877030795792928262==--