Re: A 'makedep' feature for m4.

"David M. Warme" <[email protected]> Tue, 20 May 2025 14:31:04 -0400
Newsgroups gmane.comp.gnu.m4.patches
Message-ID <[email protected]>
This is a multi-part message in MIME format.
--===============3538069760711764656==
Content-Type: multipart/alternative;
 boundary="------------CPX3LGelT46DInmb58R6Q6HY"
Content-Language: en-US

This is a multi-part message in MIME format.
--------------CPX3LGelT46DInmb58R6Q6HY
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.4.

David

  ChangeLog-2014    |  16 +++++
  NEWS              |   2 +
  THANKS            |   2 +
  checks/check-them |  36 +++++++++-
  checks/get-them   |  13 +++-
  doc/m4.texi       | 194 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
  src/builtin.c     |  19 ++++--
  src/m4.c          | 151 +++++++++++++++++++++++++++++++++++++++++-
  src/m4.h          |  15 ++++-
  src/path.c        |  78 ++++++++++++++++++++++
  10 files changed, 511 insertions(+), 15 deletions(-)
diff --git a/ChangeLog-2014 b/ChangeLog-2014
index 0783ad62..a16111c5 100644
--- a/ChangeLog-2014
+++ b/ChangeLog-2014
@@ -1,3 +1,19 @@
+2025-05-20  David Warme<[email protected]>
+	    Lorenzo Di Gregorio<[email protected]>
+
+	Add ability to generate make dependency rules.
+	* checks/check-them: Added auxfile, auxresult and TMP/.
+	* checks/get-them: Added auxfile, auxresult.
+	* doc/m4.texi: Document new options and examples.
+	* src/builtin.c: Record dependencies for include() / sinclude().
+	* src/m4.c: Add new options.  Record dependencies for files
+	specified on the command line.  Generate dependencies at end.
+	* src/m4.h: Add defines for tracking how files are referenced, and
+	new functions for recording / generation of dependencies.
+	* src/path.c: Added recording / generation of dependencies.
+	* NEWS: Added a blurb for this new feature.
+	* THANKS: Added us to the list.
+
  2014-05-13  Eric Blake<[email protected]>
  
  	doc: fix line-wrapped macro definitions
diff --git a/NEWS b/NEWS
index 00a81b7f..2b5b6d6a 100644
--- a/NEWS
+++ b/NEWS
@@ -39,6 +39,8 @@ GNU M4 NEWS - User visible changes.
  
  * 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 016dd6e2..f73c59ea 100644
--- a/THANKS
+++ b/THANKS
@@ -37,6 +37,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]
@@ -79,6 +80,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 c0a8d350..2c400e53 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
@@ -101,7 +102,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 M4PATH=$examples "$m4" -d $options - >$out 2>$err
    stat=$?
@@ -123,8 +125,8 @@ 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/|" \
-      "$file" > $xout
+    ${SED} -ne 's/^dnl @result{}//p' "$file" \
+    | ${SED} "s|examples/|$examples/|" > $xout
    else
      cp "$examples/$xoutfile" $xout
    fi
@@ -142,6 +144,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
@@ -172,6 +176,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 b80f70fb..b901cf15 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 7cbad39e..99952f14 
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 
======================================================== @@ -161,6 
+169,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 * Debugging 
options:: Command line options for debugging * Command line files:: 
Specifying input files on the command line @@ -589,6 +598,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 @@ -864,6 +874,190 @@ 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 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: 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 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);
+          fail = 0;
          }
+      if (!silent)
+        M4ERROR ((warning_status, errno, _("cannot open `%s'"), ARG (1)));
+      if (fail)
+          retcode = EXIT_FAILURE;
        return;
      }
  
+  record_dependency (name, ref_from);
    push_file (fp, name, true);
    free (name);
  }
@@ -1418,7 +1425,7 @@ include (int argc, token_data **argv, bool silent)
  static void
  m4_include (struct obstack *obs MAYBE_UNUSED, int argc, token_data **argv)
  {
-  include (argc, argv, false);
+  include (argc, argv, false, REF_INCLUDE);
  }
  
  /*----------------------------------.
@@ -1428,7 +1435,7 @@ m4_include (struct obstack *obs MAYBE_UNUSED, int argc, token_data **argv)
  static void
  m4_sinclude (struct obstack *obs MAYBE_UNUSED, int argc, token_data **argv)
  {
-  include (argc, argv, true);
+  include (argc, argv, true, REF_SINCLUDE);
  }
  
  /* More miscellaneous builtins -- "maketemp", "errprint", "__file__",
diff --git a/src/m4.c b/src/m4.c
index 8f9f6d2e..227d8a20 100644
--- a/src/m4.c
+++ b/src/m4.c
@@ -77,6 +77,21 @@ int nesting_limit = 1024;
  const char *user_word_regexp = "";
  #endif
  
+/* 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;
@@ -267,6 +282,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]          set debug level (no FLAGS implies `aeq')\n\
        --debugfile[=FILE]       redirect debug and trace output to FILE\n\
@@ -317,6 +363,16 @@ enum
    DEBUGFILE_OPTION = CHAR_MAX + 1,      /* no short opt */
    DIVERSIONS_OPTION,            /* not quite -N, because of message */
    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 */
@@ -354,6 +410,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},
  
@@ -380,11 +451,15 @@ process_file (const char *name)
        if (fp == NULL)
          {
            error (0, errno, _("cannot open `%s'"), 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);
      }
@@ -615,6 +690,50 @@ main (int argc, char *const *argv)
             (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);
@@ -632,6 +751,30 @@ 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. */
+  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 --makedep and --makedep-target")));
+      if (makedep_phony != 0)
+        M4ERROR ((EXIT_FAILURE, 0,
+                  _("--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
+    {
+      M4ERROR ((EXIT_FAILURE, 0,
+                _("--makedep must be used with --makedep-target")));
+      exit (EXIT_FAILURE);
+    }
  
    input_init ();
    output_init ();
@@ -738,6 +881,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
+++ b/src/m4.h
@@ -135,6 +135,14 @@ extern int nesting_limit;       /* -L */
  #ifdef ENABLE_CHANGEWORD
  extern const char *user_word_regexp;    /* -W */
  #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 */
  
  /* Error handling.  */
  extern int retcode;
@@ -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;
  
  /* File: builtin.c  --- builtins.  */
  
@@ -470,6 +481,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 af5e7cf0..f34ef8a3 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
@@ -189,6 +201,72 @@ 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)
+    {
+      M4ERROR ((0, errno, "unable to open `%s'.\n", 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

--------------CPX3LGelT46DInmb58R6Q6HY
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.4.

David

 ChangeLog-2014    |  16 +++++
 NEWS              |   2 +
 THANKS            |   2 +
 checks/check-them |  36 +++++++++-
 checks/get-them   |  13 +++-
 doc/m4.texi       | 194 ++++++++++++++++++++++++++++++++++++++++++++++++=
++++++
 src/builtin.c     |  19 ++++--
 src/m4.c          | 151 +++++++++++++++++++++++++++++++++++++++++-
 src/m4.h          |  15 ++++-
 src/path.c        |  78 ++++++++++++++++++++++
 10 files changed, 511 insertions(+), 15 deletions(-)
diff --git a/ChangeLog-2014 b/ChangeLog-2014
index 0783ad62..a16111c5 100644
--- a/ChangeLog-2014
+++ b/ChangeLog-2014
@@ -1,3 +1,19 @@
+2025-05-20  David Warme  <a class=3D"moz-txt-link-rfc2396E" href=3D"mail=
to:[email protected]">&lt;[email protected]&gt;</a>
+	    Lorenzo Di Gregorio  <a class=3D"moz-txt-link-rfc2396E" href=3D"mai=
lto:[email protected]">&lt;[email protected]&gt;</a=
>
+
+	Add ability to generate make dependency rules.
+	* checks/check-them: Added auxfile, auxresult and TMP/.
+	* checks/get-them: Added auxfile, auxresult.
+	* doc/m4.texi: Document new options and examples.
+	* src/builtin.c: Record dependencies for include() / sinclude().
+	* src/m4.c: Add new options.  Record dependencies for files
+	specified on the command line.  Generate dependencies at end.
+	* src/m4.h: Add defines for tracking how files are referenced, and
+	new functions for recording / generation of dependencies.
+	* src/path.c: Added recording / generation of dependencies.
+	* NEWS: Added a blurb for this new feature.
+	* THANKS: Added us to the list.
+
 2014-05-13  Eric Blake  <a class=3D"moz-txt-link-rfc2396E" href=3D"mailt=
o:[email protected]">&lt;[email protected]&gt;</a>
=20
 	doc: fix line-wrapped macro definitions
diff --git a/NEWS b/NEWS
index 00a81b7f..2b5b6d6a 100644
--- a/NEWS
+++ b/NEWS
@@ -39,6 +39,8 @@ GNU M4 NEWS - User visible changes.
=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 016dd6e2..f73c59ea 100644
--- a/THANKS
+++ b/THANKS
@@ -37,6 +37,7 @@ David Apps              unlisted
 David Arnstein          <a class=3D"moz-txt-link-abbreviated" href=3D"ma=
ilto:[email protected]">[email protected]</a>
 David J. MacKenzie      <a class=3D"moz-txt-link-abbreviated" href=3D"ma=
ilto:[email protected]">[email protected]</a>
 David Perlin            <a class=3D"moz-txt-link-abbreviated" href=3D"ma=
ilto:[email protected]">[email protected]</a>
+David Warme             <a class=3D"moz-txt-link-abbreviated" href=3D"ma=
ilto:[email protected]">[email protected]</a>
 Elbert Pol              <a class=3D"moz-txt-link-abbreviated" href=3D"ma=
ilto:[email protected]">[email protected]</a>
 Elias Benali            <a class=3D"moz-txt-link-abbreviated" href=3D"ma=
ilto:[email protected]">[email protected]</a>
 Erez Zadok              <a class=3D"moz-txt-link-abbreviated" href=3D"ma=
ilto:[email protected]">[email protected]</a>
@@ -79,6 +80,7 @@ Konrad Schwarz          <a class=3D"moz-txt-link-abbrev=
iated" href=3D"mailto:[email protected]">konrad.schwarz@siemens.=
com</a>
 Kristine Lund           <a class=3D"moz-txt-link-abbreviated" href=3D"ma=
ilto:[email protected]">[email protected]</a>
 Krste Asanovic          <a class=3D"moz-txt-link-abbreviated" href=3D"ma=
ilto:[email protected]">[email protected]</a>
 Lawson Chan             <a class=3D"moz-txt-link-abbreviated" href=3D"ma=
ilto:[email protected]">[email protected]</a>
+Lorenzo Di Gregorio     <a class=3D"moz-txt-link-abbreviated" href=3D"ma=
ilto:[email protected]">[email protected]</a>
 Marijn Schouten         unlisted
 Marion Hakanson         <a class=3D"moz-txt-link-abbreviated" href=3D"ma=
ilto:[email protected]">[email protected]</a>
 Mark Seiden             <a class=3D"moz-txt-link-abbreviated" href=3D"ma=
ilto:[email protected]">[email protected]</a>
diff --git a/checks/check-them b/checks/check-them
index c0a8d350..2c400e53 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
@@ -101,7 +102,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 M4PATH=3D$examples "$m4" -d $options - &gt;$out 2&=
gt;$err
   stat=3D$?
@@ -123,8 +125,8 @@ 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/|=
" \
-      "$file" &gt; $xout
+    ${SED} -ne 's/^dnl @result{}//p' "$file" \
+    | ${SED} "s|examples/|$examples/|" &gt; $xout
   else
     cp "$examples/$xoutfile" $xout
   fi
@@ -142,6 +144,8 @@ do
         "$examples/$xerrfile" &gt; $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' &lt; $out &gt; $out.t
@@ -172,6 +176,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' &lt; $file &gt;$=
xaux
+      if $strip_needed ; then
+        tr -d '\015' &lt; $tauxfile &gt; $tauxfile.t
+        mv $tauxfile.t $tauxfile
+        tr -d '\015' &lt; $xaux &gt; $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 b80f70fb..b901cf15 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 &lt; 0)
     next;
@@ -105,10 +111,13 @@ BEGIN {
         printf("dnl @ expected output: %s\n", xout) &gt; file;
     if (xerr)
         printf("dnl @ expected error: %s\n", xerr) &gt; file;
+    if (auxfile)
+        printf("dnl @ expected auxfile: %s\n", auxfile) &gt; 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.texiindex7cbad39e..99952f14100644---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@@-161,6+169,7@@*Preprocessorfeatures::Commandlineoptionsf=
orpreprocessorfeatures*Limitscontrol::Commandlineoptionsforlimitscontrol*=
Frozenstate::Commandlineoptionsforfrozenstate+*Makedependencygeneration::=
Generatingmakedepencencyrules*Debuggingoptions::Commandlineoptionsfordebu=
gging*Commandlinefiles::Specifyinginputfilesonthecommandline@@-589,6+598,=
7@@*Preprocessorfeatures::Commandlineoptionsforpreprocessorfeatures*Limit=
scontrol::Commandlineoptionsforlimitscontrol*Frozenstate::Commandlineopti=
onsforfrozenstate+*Makedependencygeneration::Generatingmakedependencyrule=
s*Debuggingoptions::Commandlineoptionsfordebugging*Commandlinefiles::Spec=
ifyinginputfilesonthecommandline@endmenu@@-864,6+874,190@@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.+++@commentoptions:--makedep=3DTMP/depfile--make=
dep-target=3DTarget--makedep-gen-missing-allfoonone+@commentauxfile:TMP/d=
epfile+@example+$@kbd{m4-Iexamples--makedep=3DTMP/depfile--makedep-target=
=3DTarget\}+@kbd{--makedep-gen-missing-allfoonone-}+@result{}bar+@error{}=
m4:cannotopen`none':Nosuchfileordirectory+include(`incl.m4')+@result{}Inc=
ludefilestart+@result{}foo+@result{}Includefileend+@result{}+include(`non=
e2')+@result{}+@error{}m4:stdin:2:cannotopen`none2':Nosuchfileordirectory=
+sinclude(`none3')+@result{}+^D+@auxresult{TMP/depfile}#Automaticallygene=
ratedbyGNUm4.+@auxresult{TMP/depfile}Target:./../examples/foonone./../exa=
mples/incl.m4none2none3+@endexample++Thefollowingoptionscontrolthegenerat=
ionof``phony''targetsfor+certainclassesofdependencies.Thesedummyrulesareu=
sedtowork+arounderrors@code{make}givesifyouremovefileswithoutupdatingthe+=
@code{Makefile}tomatch.Dependenciesthatmatchoneormoreofthese+classescause=
asingledummyruletobegeneratedforthem:++@table@code+@item--makedep-phony-a=
rgfiles+Causes@code{m4}togeneratea``phony''targetforeachfilethatis+specif=
iedonthecommandline.++@item--makedep-phony-include+Causes@code{m4}togener=
atea``phony''targetforeachfilethatis+thesubjectofan@code{include()}macro.=
Thisoptionisanalogousto+the@code{-MP}optionof@code{gcc}.++@item--makedep-=
phony-sinclude+Causes@code{m4}togeneratea``phony''targetforeachfilethatis=
+thesubjectofan@code{sinclude()}macro.++@item--makedep-phony-all+isequiva=
lenttospecifyingallthreeoptions:+@code{--makedep-phony-argfiles}+@code{--=
makedep-phony-include}+@code{--makedep-phony-sinclude}.+@endtable++@comme=
ntoptions:--makedep=3DTMP/depfile--makedep-target=3DTarget--makedep-phony=
-allfoo+@commentauxfile:TMP/depfile+@example+$@kbd{m4-Iexamples--makdep=3D=
TMP/depfile--makedep-target=3DTarget\}+@kbd{--makedep-phony-allfoo-}+@res=
ult{}bar+include(`incl.m4')+@result{}Includefilestart+@result{}foo+@resul=
t{}Includefileend+@result{}+^D+@auxresult{TMP/depfile}#Automaticallygener=
atedbyGNUm4.+@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:+@=
endexample+@nodeDebuggingoptions@sectionCommandlineoptionsfordebuggingdif=
f--gita/src/builtin.cb/src/builtin.cindex2819ba49..0f237c5b100644---a/src=
/builtin.c+++b/src/builtin.c@@-1388,10+1388,11@@m4_changeword(structobsta=
ck*obsMAYBE_UNUSED,intargc,token_data**argv)`----------------------------=
-----------------------------------*/staticvoid-include(intargc,token_dat=
a**argv,boolsilent)+include(intargc,token_data**argv,boolsilent,intref_fr=
om){FILE*fp;char*name;+intfail;if(bad_argc(argv[0],argc,2,2))return;@@-13=
99,14+1400,20@@include(intargc,token_data**argv,boolsilent)fp=3Dm4_path_s=
earch(ARG(1),false,&amp;name);if(fp=3D=3DNULL){-if(!silent)+fail=3D!silen=
t;+if((makedep_gen_missing&amp;ref_from)!=3D0){-M4ERROR((warning_status,e=
rrno,_(">";
diff --git a/doc/m4.texi b/doc/m4.texi
index 7cbad39e..99952f14 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
@@ -161,6 +169,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 depencency rules
 * Debugging options::           Command line options for debugging
 * Command line files::          Specifying input files on the command li=
ne
=20
@@ -589,6 +598,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
@@ -864,6 +874,190 @@
 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 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: 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=
=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 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)
 `---------------------------------------------------------------*/
=20
 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;
=20
   if (bad_argc (argv[0], argc, 2, 2))
     return;
@@ -1399,14 +1400,20 @@ include (int argc, token_data **argv, bool silent=
)
   fp =3D m4_path_search (ARG (1), false, &amp;name);
   if (fp =3D=3D NULL)
     {
-      if (!silent)
+      fail =3D !silent;
+      if ((makedep_gen_missing &amp; ref_from) !=3D 0)
         {
-          M4ERROR ((warning_status, errno, _("</a>cannot open `%s'"), AR=
G (1)));
-          retcode =3D EXIT_FAILURE;
+          record_dependency (ARG (1), ref_from);
+          fail =3D 0;
         }
+      if (!silent)
+        M4ERROR ((warning_status, errno, _("cannot open `%s'"), ARG (1))=
);
+      if (fail)
+          retcode =3D EXIT_FAILURE;
       return;
     }
=20
+  record_dependency (name, ref_from);
   push_file (fp, name, true);
   free (name);
 }
@@ -1418,7 +1425,7 @@ include (int argc, token_data **argv, bool silent)
 static void
 m4_include (struct obstack *obs MAYBE_UNUSED, int argc, token_data **arg=
v)
 {
-  include (argc, argv, false);
+  include (argc, argv, false, REF_INCLUDE);
 }
=20
 /*----------------------------------.
@@ -1428,7 +1435,7 @@ m4_include (struct obstack *obs MAYBE_UNUSED, int a=
rgc, token_data **argv)
 static void
 m4_sinclude (struct obstack *obs MAYBE_UNUSED, int argc, token_data **ar=
gv)
 {
-  include (argc, argv, true);
+  include (argc, argv, true, REF_SINCLUDE);
 }
 =0C
 /* More miscellaneous builtins -- "maketemp", "errprint", "__file__",
diff --git a/src/m4.c b/src/m4.c
index 8f9f6d2e..227d8a20 100644
--- a/src/m4.c
+++ b/src/m4.c
@@ -77,6 +77,21 @@ int nesting_limit =3D 1024;
 const char *user_word_regexp =3D "";
 #endif
=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;
@@ -267,6 +282,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[=3DFLAGS]          set debug level (no FLAGS implies `aeq'=
)\n\
       --debugfile[=3DFILE]       redirect debug and trace output to FILE=
\n\
@@ -317,6 +363,16 @@ enum
   DEBUGFILE_OPTION =3D CHAR_MAX + 1,      /* no short opt */
   DIVERSIONS_OPTION,            /* not quite -N, because of message */
   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 */
@@ -354,6 +410,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
@@ -380,11 +451,15 @@ process_file (const char *name)
       if (fp =3D=3D NULL)
         {
           error (0, errno, _("cannot open `%s'"), 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 &amp; 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);
     }
@@ -615,6 +690,50 @@ main (int argc, char *const *argv)
            (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);
@@ -632,6 +751,30 @@ main (int argc, char *const *argv)
   if (debugfile &amp;&amp; !debug_set_output (debugfile))
     M4ERROR ((warning_status, errno, _("cannot set debug file `%s'"),
               debugfile));
+=20
+  /* Verify mutual consistency of makedep options. */
+  if ((makedep_path =3D=3D NULL) &amp;&amp; (makedep_target =3D=3D NULL)=
)
+    {
+      /* Makedep mode is NOT active. */
+      if (makedep_gen_missing !=3D 0)
+        M4ERROR ((EXIT_FAILURE, 0,
+                  _("--makedep-gen-missing-* requires --makedep and --ma=
kedep-target")));
+      if (makedep_phony !=3D 0)
+        M4ERROR ((EXIT_FAILURE, 0,
+                  _("--makedep-phony-* requires --makedep and --makedep-=
target")));
+      if ((makedep_gen_missing | makedep_phony) !=3D 0)
+        exit (EXIT_FAILURE);
+    }
+  else if ((makedep_path !=3D NULL) &amp;&amp; (makedep_target !=3D NULL=
))
+    {
+      /* Makedep mode is active. */
+    }
+  else
+    {
+      M4ERROR ((EXIT_FAILURE, 0,
+                _("--makedep must be used with --makedep-target")));
+      exit (EXIT_FAILURE);
+    }
=20
   input_init ();
   output_init ();
@@ -738,6 +881,8 @@ main (int argc, char *const *argv)
       undivert_all ();
     }
   output_exit ();
+  if (makedep_path !=3D NULL)
+    generate_make_dependencies (makedep_path, makedep_target, makedep_ph=
ony);
   free_macro_sequence ();
   exit (retcode);
 }
diff --git a/src/m4.h b/src/m4.h
index 8d0d96dd..f8735abc 100644
--- a/src/m4.h
+++ b/src/m4.h
@@ -135,6 +135,14 @@ extern int nesting_limit;       /* -L */
 #ifdef ENABLE_CHANGEWORD
 extern const char *user_word_regexp;    /* -W */
 #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
 /* Error handling.  */
 extern int retcode;
@@ -412,7 +420,10 @@ extern void hack_all_symbols (hack_symbol *, void *)=
;
 extern int expansion_level;
=20
 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 bu=
ild. */
+  ATTRIBUTE_COLD;
 =0C
 /* File: builtin.c  --- builtins.  */
=20
@@ -470,6 +481,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 af5e7cf0..f34ef8a3 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
@@ -189,6 +201,72 @@ 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-&gt;next)
+    if (strcmp (path, dp-&gt;path) =3D=3D 0)
+      {
+        /* Remember all the places this file has been referenced from. *=
/
+        dp-&gt;ref_from |=3D ref_from;
+        return;
+      }
+
+  dp =3D xmalloc (sizeof (dependency));
+  dp-&gt;next =3D NULL;
+  dp-&gt;ref_from =3D ref_from;
+  dp-&gt;path =3D xstrdup (path);
+
+  if (dependency_list_end =3D=3D NULL)
+    dependency_list =3D dp;
+  else
+    dependency_list_end-&gt;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)
+    {
+      M4ERROR ((0, errno, "unable to open `%s'.\n", 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-&gt;next)
+    {
+      len =3D 1 + strlen (dp-&gt;path);
+      if (col + len + 2 &gt; maxcol) /* +2 is for trailing space/backsla=
sh */
+        {
+          fprintf (fp," \\\n ");
+          col =3D 1;
+        }
+      fprintf (fp, " %s", dp-&gt;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-&gt;next)
+      if ((dp-&gt;ref_from &amp; phony) !=3D 0)
+        fprintf (fp, "\n%s:\n", dp-&gt;path);
+
+  fclose (fp);
+}
+
 #ifdef DEBUG_INCL
=20
 static void MAYBE_UNUSED

</pre>
  </body>
</html>

--------------CPX3LGelT46DInmb58R6Q6HY--


--===============3538069760711764656==
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: base64
Content-Disposition: inline

X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18KTTQtcGF0Y2hl
cyBtYWlsaW5nIGxpc3QKTTQtcGF0Y2hlc0BnbnUub3JnCmh0dHBzOi8vbGlzdHMuZ251Lm9yZy9t
YWlsbWFuL2xpc3RpbmZvL200LXBhdGNoZXMK

--===============3538069760711764656==--