Patchwork [fortran] output of Makefile dependencies

login
register
mail settings
Submitter Kirill Smelkov
Date June 14, 2010, 6:20 p.m.
Message ID <20100614182041.GA11547@landau.phys.spbu.ru>
Download mbox | patch
Permalink /patch/55571/
State New
Headers show

Comments

Kirill Smelkov - June 14, 2010, 6:20 p.m.
On Sun, Jun 13, 2010 at 02:36:46PM +0200, Daniel Franke wrote:
> 
> Hi all.
> 
> Attached patch enables the output of Makefile dependencies.
> It handles '#include', 'INCLUDE' and module targets/use dependencies alike.
> 
> Example:
> $ cat a.f90 
> MODULE a
>   include "a.inc"
> END MODULE
> 
> $ cat b.f90
>   USE a
> #include "b.h"
> end
> 
> $ gfortran-svn -cpp -M a.f90 b.f90 
> a.o a.mod: a.f90 a.inc
> b.o: b.f90 b.h a.mod
> 
> 
> 2010-06-13  Daniel Franke  <franke.daniel@gmail.com>
> 
> 	PR fortran/31588
> 	PR fortran/43954
> 	* gfortranspec.c (lang_specific_driver): Removed deprecation
> 	warning for -M.
> 	* lang.opt: Add options -M, -MM, -MD, -MMD, -MF, -MG, -MP, -MT, -MQ.
> 	* lang-specs.h (CPP_FORWARD_OPTIONS): Add -M* options.
> 	* cpp.h (gfc_cpp_makedep): New.
> 	(gfc_cpp_add_dep): New.
> 	(gfc_cpp_add_target): New.
> 	* cpp.c (gfc_cpp_option): Add deps* members.
> 	(gfc_cpp_makedep): New.
> 	(gfc_cpp_add_dep): New.
> 	(gfc_cpp_add_target): New.
> 	(gfc_cpp_init_options): Initialize new options.
> 	(gfc_cpp_handle_option): Handle new options.
> 	(gfc_cpp_post_options): Map new options to libcpp-options.
> 	(gfc_cpp_init): Handle deferred -MQ and -MT options.
> 	(gfc_cpp_done): If requested, write dependencies to file.
> 	* module.c (gfc_dump_module): Add a module filename as target.
> 	(import_iso_c_binding_module): Add dependency on intrinsic module.
> 	(use_iso_fortran_env_module): Likewise.
> 	* scanner.c (gfc_open_included_file): Add the included file as
> 	dependency if dependency tracking is enabled.
> 	(gfc_open_intrinsic_module): Likewise.
> 
> 
> Bootstrapped and regression tested on i686-pc-linux-gnu.
> Ok for trunk?
> 
> 	Daniel

Daniel, thanks for dealing with this.

Because of PR fortran/43954 (4.3 -> 4.4 regression, where -Wp,-M stopped
working) could we please apply your committed version to 4.4 as well?

`make check` tested on top of today's gcc-4_4-branch on
i686-pc-linux-gnu + manually verified that dependency generation works.

Thanks,
Kirill


P.S. If "yes", I'll backport to 4.5 too.


----8<----

From: Kirill Smelkov <kirr@landau.phys.spbu.ru>
Date: Mon, 14 Jun 2010 21:49:47 +0400
Subject: [PATCH] gcc/fortran: output of Makefile dependencies

2010-06-14  Kirill Smelkov  <kirr@landau.phys.spbu.ru>

	Backport from mainline:
	2010-06-13  Daniel Franke  <franke.daniel@gmail.com>

	PR fortran/31588
	PR fortran/43954
	* gfortranspec.c (lang_specific_driver): Removed deprecation
	warning for -M.
	* lang.opt: Add options -M, -MM, -MD, -MMD, -MF, -MG, -MP, -MT, -MQ.
	* lang-specs.h (CPP_FORWARD_OPTIONS): Add -M* options.
	* cpp.h (gfc_cpp_makedep): New.
	(gfc_cpp_add_dep): New.
	(gfc_cpp_add_target): New.
	* cpp.c (gfc_cpp_option): Add deps* members.
	(gfc_cpp_makedep): New.
	(gfc_cpp_add_dep): New.
	(gfc_cpp_add_target): New.
	(gfc_cpp_init_options): Initialize new options.
	(gfc_cpp_handle_option): Handle new options.
	(gfc_cpp_post_options): Map new options to libcpp-options.
	(gfc_cpp_init): Handle deferred -MQ and -MT options.
	(gfc_cpp_done): If requested, write dependencies to file.
	* module.c (gfc_dump_module): Add a module filename as target.
	* scanner.c (open_included_file): New parameter system; add the
	included file as dependency.
	(gfc_open_included_file): Add the included file as dependency.
	(gfc_open_intrinsic_module): Likewise.
	* invoke.texi: Removed deprecation warning for -M.
	* gfortran.texi: Removed Makefile-dependencies project.
---
 gcc/fortran/ChangeLog      |   31 +++++++++++
 gcc/fortran/cpp.c          |  124 +++++++++++++++++++++++++++++++++++++++-----
 gcc/fortran/cpp.h          |    6 ++
 gcc/fortran/gfortran.texi  |    3 -
 gcc/fortran/gfortranspec.c |   30 -----------
 gcc/fortran/invoke.texi    |    6 +--
 gcc/fortran/lang-specs.h   |    2 +-
 gcc/fortran/lang.opt       |   36 +++++++++++++
 gcc/fortran/module.c       |    4 ++
 gcc/fortran/scanner.c      |   39 ++++++++++----
 10 files changed, 217 insertions(+), 64 deletions(-)
Kirill Smelkov - June 28, 2010, 6:07 p.m.
On Mon, Jun 14, 2010 at 10:20:41PM +0400, Kirill Smelkov wrote:
> On Sun, Jun 13, 2010 at 02:36:46PM +0200, Daniel Franke wrote:
> > 
> > Hi all.
> > 
> > Attached patch enables the output of Makefile dependencies.
> > It handles '#include', 'INCLUDE' and module targets/use dependencies alike.
> > 
> > Example:
> > $ cat a.f90 
> > MODULE a
> >   include "a.inc"
> > END MODULE
> > 
> > $ cat b.f90
> >   USE a
> > #include "b.h"
> > end
> > 
> > $ gfortran-svn -cpp -M a.f90 b.f90 
> > a.o a.mod: a.f90 a.inc
> > b.o: b.f90 b.h a.mod
> > 
> > 
> > 2010-06-13  Daniel Franke  <franke.daniel@gmail.com>
> > 
> > 	PR fortran/31588
> > 	PR fortran/43954
> > 	* gfortranspec.c (lang_specific_driver): Removed deprecation
> > 	warning for -M.
> > 	* lang.opt: Add options -M, -MM, -MD, -MMD, -MF, -MG, -MP, -MT, -MQ.
> > 	* lang-specs.h (CPP_FORWARD_OPTIONS): Add -M* options.
> > 	* cpp.h (gfc_cpp_makedep): New.
> > 	(gfc_cpp_add_dep): New.
> > 	(gfc_cpp_add_target): New.
> > 	* cpp.c (gfc_cpp_option): Add deps* members.
> > 	(gfc_cpp_makedep): New.
> > 	(gfc_cpp_add_dep): New.
> > 	(gfc_cpp_add_target): New.
> > 	(gfc_cpp_init_options): Initialize new options.
> > 	(gfc_cpp_handle_option): Handle new options.
> > 	(gfc_cpp_post_options): Map new options to libcpp-options.
> > 	(gfc_cpp_init): Handle deferred -MQ and -MT options.
> > 	(gfc_cpp_done): If requested, write dependencies to file.
> > 	* module.c (gfc_dump_module): Add a module filename as target.
> > 	(import_iso_c_binding_module): Add dependency on intrinsic module.
> > 	(use_iso_fortran_env_module): Likewise.
> > 	* scanner.c (gfc_open_included_file): Add the included file as
> > 	dependency if dependency tracking is enabled.
> > 	(gfc_open_intrinsic_module): Likewise.
> > 
> > 
> > Bootstrapped and regression tested on i686-pc-linux-gnu.
> > Ok for trunk?
> > 
> > 	Daniel
> 
> Daniel, thanks for dealing with this.
> 
> Because of PR fortran/43954 (4.3 -> 4.4 regression, where -Wp,-M stopped
> working) could we please apply your committed version to 4.4 as well?
> 
> `make check` tested on top of today's gcc-4_4-branch on
> i686-pc-linux-gnu + manually verified that dependency generation works.
> 
> Thanks,
> Kirill
> 
> 
> P.S. If "yes", I'll backport to 4.5 too.
> 
> 
> ----8<----
> 
> From: Kirill Smelkov <kirr@landau.phys.spbu.ru>
> Date: Mon, 14 Jun 2010 21:49:47 +0400
> Subject: [PATCH] gcc/fortran: output of Makefile dependencies


Silence = ?


Anyway, I've posted two updated patches for 4.4 & 4.5 here

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43954#c9


Thanks,
Kirill
Ralf Wildenhues - Oct. 2, 2010, 6:57 a.m.
Hello GNU Fortran people,

apologies for following up a fairly old thread:

> > On Sun, Jun 13, 2010 at 02:36:46PM +0200, Daniel Franke wrote:
> > > Attached patch enables the output of Makefile dependencies.
> > > It handles '#include', 'INCLUDE' and module targets/use dependencies alike.
> > > 
> > > Example:
> > > $ cat a.f90 
> > > MODULE a
> > >   include "a.inc"
> > > END MODULE
> > > 
> > > $ cat b.f90
> > >   USE a
> > > #include "b.h"
> > > end
> > > 
> > > $ gfortran-svn -cpp -M a.f90 b.f90 
> > > a.o a.mod: a.f90 a.inc
> > > b.o: b.f90 b.h a.mod

Very nice, thank you for adding this feature!

But say, how can I use it without implicitly knowing beforehand the
order in which files depend upon each other, thereby defeating one
purpose of dependency tracking?

$ rm -f *.mod
$ gfortran -cpp -M b.f90 a.f90
b.f90:1.7:

  USE a
       1
Fatal Error: Can't open module file 'a.mod' for reading at (1): No such file or directory
a.o a.mod: a.f90 a.inc
$ echo $?
1

A pure dependency generation step should not require .mod files to be
present, and it should not create any .mod files either (see below):
$ ls *.mod
a.mod


We are considering adding Fortran automatic dependency tracking to
Automake[1], to be used with Posix make.   I would like to share a
couple more observations, and make a couple of requests.

The dependency output as implemented deserves a comment or two, because
it is quite nontrivial to use correctly, due to multiple outputs being a
feature foreign to Posix make; see [2] for some discussion:  The
dependency line

  a.o a.mod: a.f90 a.inc

tells make that both a.o and a.mod depend on the prerequisites, but a
rule
  a.o a.mod: a.f90 a.inc
        $(FC) ... -c a.f90

will let make think that for either a.o or a.mod, it should invoke the
recipe below.  That of course means trouble with parallel make, because
make may invoke two compiles of a.f90 in order to update both a.o and
a.mod.

In order to prevent this race, one can try to resort to GNU make-specific
pattern rules, or better static pattern rules (so the rules don't match
any files they are not supposed to match), written separately for each
different pair of object and associated modules files.  (For the sake of
the discussion, I'm *not* assuming that there is a specific naming
strategy between modules and source/object files.)

Alternatively, one can serialize in one of several ways, see [2] for
lots of details.  Now, one big simplification for Automake, as well as
for other users of gfortran, would be if the time stamps of .o and .mod
files were strictly ordered: the .mod files generated from a.f90 should
not be older than a.o.  That way, when we, in addition to the gfortran
output, generate rules like

  a.o: a.f90
          $(FC) ...

  a.mod a2.mod ...: a.o
          @if test -f $@; then \
            touch $@; \
          else \
  ## Recover from the removal of $@
            rm -f a.o; \
            $(MAKE) $(AM_MAKEFLAGS) a.o; \
          fi

the expensive recursive make invocation rarely if ever happens in practice.
(This solution still has a rarely encountered race if someone removes
a.mod and a2.mod but not a.o; that can be dealt with if it is relevant
in practice, see again [2], but requires more expensive locking which
we'd like to avoid).


Thus my first request: please ensure, and document, that the .o file
will never be newer than the .mod files generated from the same gfortran
invocation.


Secondly, error recovery should not leave us in a dirty state: that is,
if compilation fails, please confirm or ensure that at least the object
file is removed, or, even better, created atomically by renaming from a
temporary name inside the same directory.  Otherwise, an interrupted
build (yes, ugly, but users are that way) may leave the tree in an
undesirable state.


If the first released gfortran with above dependency support does not
get these things right, then it will be difficult to use configure
feature tests to determine when it works (relying on version numbers is
not desirable).

Thanks for reading this far.  Should I open one or more PR's for this?

Cheers,
Ralf

[1] http://thread.gmane.org/gmane.comp.sysutils.automake.general/11706/focus=11841
    BTW, if you have a real, sizable application for deptracking that we
    could test our implementation on, that would be great!
[2] http://www.gnu.org/software/automake/manual/html_node/Multiple-Outputs.html
Tobias Burnus - Oct. 2, 2010, 8 a.m.
Hi Ralf,

Ralf Wildenhues wrote:
>>> On Sun, Jun 13, 2010 at 02:36:46PM +0200, Daniel Franke wrote:
>>>> Attached patch enables the output of Makefile dependencies.
>>>> It handles '#include', 'INCLUDE' and module targets/use dependencies alike.
> [Issue about order due to the required reading of the .mod files]

(I think that's going to be a difficult issue. One probably needs to 
write a separate parser for this, which ignores all the rest and only 
parses USE statements and INCLUDE lines - and handles the CPP 
preprocessor's #include - including dependencies of those 
INCLUDEd/#included files.)

> Thus my first request: please ensure, and document, that the .o file
> will never be newer than the .mod files generated from the same gfortran
> invocation.

That's impossible! The .mod file is generated early by the compiler 
(front end part) whereas the .o file is generated by the assembler after 
the backed part of the compiler has finished writing the assembler file!

Additionally, due to a feature request for writing .mod files, gfortran 
(and some but by far not all other Fortran compilers) do not rewrite the 
.mod file if the output has not changed.  -- The reason is to avoid 
compilation cascades if only the internal implementation but not the 
public interface has changed. In that case,  one needs to only relink 
(.o dependency) but not to recompile files depending on the module (.mod 
dependency).

> Secondly, error recovery should not leave us in a dirty state: that is,
> if compilation fails, please confirm or ensure that at least the object
> file is removed, or, even better, created atomically by renaming from a
> temporary name inside the same directory.  Otherwise, an interrupted
> build (yes, ugly, but users are that way) may leave the tree in an
> undesirable state.

I thought the compiler driver ("gcc", "gfortran") is handling this? The 
compiler itself ("cc1", "f951") cannot do this as it only generates 
assembler files. The .mod files are generated atomically to allow for 
not updating the .mod if the interface has not changed.

Tobias
Tobias Burnus - Oct. 2, 2010, 8:35 a.m.
Ralf Wildenhues wrote:
> [1] 
> http://thread.gmane.org/gmane.comp.sysutils.automake.general/11706/focus=11841

Ralf wrote in aforementioned thread:
> Conditional Compilation[2] is standardized but not widely used; the
> coco tool[3] may be used for this.

I would ignore COCO. I think the number of users is very low - that low 
that the Fortran committee is about to drop the support. The conditional 
compilation using the C preprocessor (CPP) is widely used and 
implemented in essentially all Fortran compilers.

> Fortran modules are another matter.  From what I have understood so far:
>
> Fortran files may define modules and use other modules.  In the most
> general case, one Fortran source file can define an arbitrary set of
> modules, and use an arbitrary set of modules, there is no required
> naming strategy.
Correct.

> If you draw arrows between .f90 files from 'use'
> statements to 'module' statements, this graph (which is not the one
> 'make' is interested in!) can have circles.  Is this true?  If yes,
> then I hope this is frowned upon in the Fortran community.

Well, circular use of modules is not allowed. It is allowed to have 
circular dependencies between files (module m1 in file A, module m2 in 
file B; m2 uses m1; and file A uses - e.g. in module m3 - the module 
m2), but as this won't compile with most (all?) compilers, one does not 
find it in practice. Thus, in practice there should not be any loops 
between files either.

> Fortran compilers typically encode module information in some manner.
> It may be in extra module files, which may have one of several possible
> extensions (I only know .mod) and may be named after the module name
> (also the object name possibly?  I don't know).

In principle, all kind of storage could be possible. But I think the 
usage of .mod is quite universal. Saving the .mod by the name of the 
module allows to easily read it. If you had saved it using the object 
name, a compiler encountering a "use mod_name" had to read all .mod 
files to find out which is the correct one. Thus, the assumption that a 
.mod file per MODULE statement is generated and has a naming derived 
from the module name should be rather universal - though I would not be 
surprised if there exist compilers which handle it differently.

> Fortran module files typically have to be cleaned.  Since they are
> compiler-dependent, and effectively binary like object files, they are
> typically not distributed.

They are in a kind of hybrid state: While they are compiler and compiler 
version specific, they are not transferable - but on the other hand, 
Linux distributions often ship them for the system compiler for included 
libraries such as for MPI or HDF5. (See also below.)

> I have no idea how modules mesh with static or shared libraries.  I have
> seen module files installed, typically below $(includedir), but that
> seems not very well thought-through, because I've had trouble avoiding
> them when using a different compiler from the one used to generate the
> modules.  Oh well, that may be a limitation users have to live with
> anyway.

Jakub suggested to use, e.g., 
/usr/include/finclude/gcc/x86_64-unknown-linux-gnu for Fortran .mod 
files and include this automatically in the search path. I think such a 
patch will be added for gfortran and probably then adopted by the Linux 
distributions.

>      BTW, if you have a real, sizable application for deptracking that we
>      could test our implementation on, that would be great

One application I like to use for testing is Elk (http://elk.sf.net) as 
it is a rather large package, but it is simple to setup and does not 
need external libraries.* However, it does only make light use of 
modules. (There are others I use which come into my mind, but they are 
either rather complex, e.g. octopus [http://www.tddft.org].)

Tobias

PS: A stubborn way to get the dependencies even with aborts is to use 
"gfortran -M *.F* *.f*" until no module-not-found error occur any more. 
That works OK but is not a solution for automake.
Steve Kargl - Oct. 2, 2010, 3:34 p.m.
On Sat, Oct 02, 2010 at 10:00:06AM +0200, Tobias Burnus wrote:
>  Hi Ralf,
> 
> Ralf Wildenhues wrote:
> >>>On Sun, Jun 13, 2010 at 02:36:46PM +0200, Daniel Franke wrote:
> >>>>Attached patch enables the output of Makefile dependencies.
> >>>>It handles '#include', 'INCLUDE' and module targets/use dependencies 
> >>>>alike.
> >[Issue about order due to the required reading of the .mod files]
> 
> (I think that's going to be a difficult issue. One probably needs to 
> write a separate parser for this, which ignores all the rest and only 
> parses USE statements and INCLUDE lines - and handles the CPP 
> preprocessor's #include - including dependencies of those 
> INCLUDEd/#included files.)
> 

It will also have to deal with virtual modules.  For
example, iso_binding_c is never written to disk, so the
automatic tool needs to pass over 'use iso_binding_c'.

Patch

diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog
index 283f113..adc63af 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -1,3 +1,34 @@ 
+2010-06-14  Kirill Smelkov  <kirr@landau.phys.spbu.ru>
+
+	Backport from mainline:
+	2010-06-13  Daniel Franke  <franke.daniel@gmail.com>
+
+	PR fortran/31588
+	PR fortran/43954
+	* gfortranspec.c (lang_specific_driver): Removed deprecation
+	warning for -M.
+	* lang.opt: Add options -M, -MM, -MD, -MMD, -MF, -MG, -MP, -MT, -MQ.
+	* lang-specs.h (CPP_FORWARD_OPTIONS): Add -M* options.
+	* cpp.h (gfc_cpp_makedep): New.
+	(gfc_cpp_add_dep): New.
+	(gfc_cpp_add_target): New.
+	* cpp.c (gfc_cpp_option): Add deps* members.
+	(gfc_cpp_makedep): New.
+	(gfc_cpp_add_dep): New.
+	(gfc_cpp_add_target): New.
+	(gfc_cpp_init_options): Initialize new options.
+	(gfc_cpp_handle_option): Handle new options.
+	(gfc_cpp_post_options): Map new options to libcpp-options.
+	(gfc_cpp_init): Handle deferred -MQ and -MT options.
+	(gfc_cpp_done): If requested, write dependencies to file.
+	* module.c (gfc_dump_module): Add a module filename as target.
+	* scanner.c (open_included_file): New parameter system; add the
+	included file as dependency.
+	(gfc_open_included_file): Add the included file as dependency.
+	(gfc_open_intrinsic_module): Likewise.
+	* invoke.texi: Removed deprecation warning for -M.
+	* gfortran.texi: Removed Makefile-dependencies project.
+
 2010-06-09  Steven G. Kargl  <kargl@gcc.gnu.org>
 
 	* fortran/intrinsic.c (add_functions): Change gfc_check_btest,
diff --git a/gcc/fortran/cpp.c b/gcc/fortran/cpp.c
index d45d0c1..d8cdc33 100644
--- a/gcc/fortran/cpp.c
+++ b/gcc/fortran/cpp.c
@@ -35,6 +35,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "../../libcpp/internal.h"
 #include "cpp.h"
 #include "incpath.h"
+#include "mkdeps.h"
 
 #ifndef TARGET_OS_CPP_BUILTINS
 # define TARGET_OS_CPP_BUILTINS()
@@ -84,6 +85,12 @@  struct
   int no_predefined;                    /* -undef */
   int standard_include_paths;           /* -nostdinc */
   int verbose;                          /* -v */
+  int deps;                             /* -M */
+  int deps_skip_system;                 /* -MM */
+  const char *deps_filename;            /* -M[M]D */
+  const char *deps_filename_user;       /* -MF <arg> */
+  int deps_missing_are_generated;       /* -MG */
+  int deps_phony;                       /* -MP */
 
   const char *multilib;                 /* -imultilib <dir>  */
   const char *prefix;                   /* -iprefix <dir>  */
@@ -267,6 +274,26 @@  gfc_cpp_preprocess_only (void)
   return gfc_cpp_option.preprocess_only;
 }
 
+bool
+gfc_cpp_makedep (void)
+{
+  return gfc_cpp_option.deps;
+}
+
+void
+gfc_cpp_add_dep (const char *name, bool system)
+{
+  if (!gfc_cpp_option.deps_skip_system || !system)
+    deps_add_dep (cpp_get_deps (cpp_in), name);
+}
+
+void
+gfc_cpp_add_target (const char *name)
+{
+  deps_add_target (cpp_get_deps (cpp_in), name, 0);
+}
+
+
 const char *
 gfc_cpp_temporary_file (void)
 {
@@ -296,6 +323,12 @@  gfc_cpp_init_options (unsigned int argc,
   gfc_cpp_option.no_predefined = 0;
   gfc_cpp_option.standard_include_paths = 1;
   gfc_cpp_option.verbose = 0;
+  gfc_cpp_option.deps = 0;
+  gfc_cpp_option.deps_skip_system = 0;
+  gfc_cpp_option.deps_phony = 0;
+  gfc_cpp_option.deps_missing_are_generated = 0;
+  gfc_cpp_option.deps_filename = NULL;
+  gfc_cpp_option.deps_filename_user = NULL;
 
   gfc_cpp_option.multilib = NULL;
   gfc_cpp_option.prefix = NULL;
@@ -411,6 +444,43 @@  gfc_cpp_handle_option (size_t scode, const char *arg, int value ATTRIBUTE_UNUSED
       gfc_cpp_option.print_include_names = 1;
       break;
 
+    case OPT_MM:
+      gfc_cpp_option.deps_skip_system = 1;
+      /* fall through */
+
+    case OPT_M:
+      gfc_cpp_option.deps = 1;
+      break;
+
+    case OPT_MMD:
+      gfc_cpp_option.deps_skip_system = 1;
+      /* fall through */
+
+    case OPT_MD:
+      gfc_cpp_option.deps = 1;
+      gfc_cpp_option.deps_filename = arg;
+      break;
+
+    case OPT_MF:
+      /* If specified multiple times, last one wins.  */
+      gfc_cpp_option.deps_filename_user = arg;
+      break;
+
+    case OPT_MG:
+      gfc_cpp_option.deps_missing_are_generated = 1;
+      break;
+
+    case OPT_MP:
+      gfc_cpp_option.deps_phony = 1;
+      break;
+
+    case OPT_MQ:
+    case OPT_MT:
+      gfc_cpp_option.deferred_opt[gfc_cpp_option.deferred_opt_count].code = code;
+      gfc_cpp_option.deferred_opt[gfc_cpp_option.deferred_opt_count].arg = arg;
+      gfc_cpp_option.deferred_opt_count++;
+      break;
+
     case OPT_P:
       gfc_cpp_option.no_line_commands = 1;
       break;
@@ -427,16 +497,17 @@  gfc_cpp_post_options (void)
      an error.  */
   if (!gfc_cpp_enabled ()
       && (gfc_cpp_preprocess_only ()
-          || !gfc_cpp_option.discard_comments
-          || !gfc_cpp_option.discard_comments_in_macro_exp
-          || gfc_cpp_option.print_include_names
-          || gfc_cpp_option.no_line_commands
-          || gfc_cpp_option.dump_macros
-          || gfc_cpp_option.dump_includes))
+	  || gfc_cpp_makedep ()
+	  || !gfc_cpp_option.discard_comments
+	  || !gfc_cpp_option.discard_comments_in_macro_exp
+	  || gfc_cpp_option.print_include_names
+	  || gfc_cpp_option.no_line_commands
+	  || gfc_cpp_option.dump_macros
+	  || gfc_cpp_option.dump_includes))
     gfc_fatal_error("To enable preprocessing, use -cpp");
 
   cpp_in = cpp_create_reader (CLK_GNUC89, NULL, line_table);
-  if (!gfc_cpp_enabled())
+  if (!gfc_cpp_enabled ())
     return;
 
   gcc_assert (cpp_in);
@@ -460,6 +531,17 @@  gfc_cpp_post_options (void)
   cpp_option->print_include_names = gfc_cpp_option.print_include_names;
   cpp_option->preprocessed = gfc_option.flag_preprocessed;
 
+  if (gfc_cpp_makedep ())
+    {
+      cpp_option->deps.style = DEPS_USER;
+      cpp_option->deps.phony_targets = gfc_cpp_option.deps_phony;
+      cpp_option->deps.missing_files = gfc_cpp_option.deps_missing_are_generated;
+
+      /* -MF <arg> overrides -M[M]D.  */
+      if (gfc_cpp_option.deps_filename_user)
+	gfc_cpp_option.deps_filename = gfc_cpp_option.deps_filename_user;
+  }
+
   if (gfc_cpp_option.working_directory == -1)
     gfc_cpp_option.working_directory = (debug_info_level != DINFO_LEVEL_NONE);
 
@@ -571,6 +653,9 @@  gfc_cpp_init (void)
 	  else
 	    cpp_assert (cpp_in, opt->arg);
 	}
+      else if (opt->code == OPT_MT || opt->code == OPT_MQ)
+	deps_add_target (cpp_get_deps (cpp_in),
+			 opt->arg, opt->code == OPT_MQ);
     }
 
   if (gfc_cpp_option.working_directory
@@ -614,14 +699,27 @@  gfc_cpp_done (void)
   if (!gfc_cpp_enabled ())
     return;
 
-  /* TODO: if dependency tracking was enabled, call
-     cpp_finish() here to write dependencies.
+  gcc_assert (cpp_in);
 
-     Use cpp_get_deps() to access the current source's
-     dependencies during parsing. Add dependencies using
-     the mkdeps-interface (defined in libcpp).  */
+  if (gfc_cpp_makedep ())
+    {
+      if (gfc_cpp_option.deps_filename)
+	{
+	  FILE *f = fopen (gfc_cpp_option.deps_filename, "w");
+	  if (f)
+	    {
+	      cpp_finish (cpp_in, f);
+	      fclose (f);
+	    }
+	  else
+	    gfc_fatal_error ("opening output file %s: %s",
+			     gfc_cpp_option.deps_filename,
+			     xstrerror (errno));
+	}
+      else
+	cpp_finish (cpp_in, stdout);
+    }
 
-  gcc_assert (cpp_in);
   cpp_undef_all (cpp_in);
   cpp_clear_file_cache (cpp_in);
 }
diff --git a/gcc/fortran/cpp.h b/gcc/fortran/cpp.h
index 54a899f..556eecb 100644
--- a/gcc/fortran/cpp.h
+++ b/gcc/fortran/cpp.h
@@ -24,6 +24,12 @@  bool gfc_cpp_enabled (void);
 
 bool gfc_cpp_preprocess_only (void);
 
+bool gfc_cpp_makedep (void);
+
+void gfc_cpp_add_dep (const char *name, bool system);
+
+void gfc_cpp_add_target (const char *name);
+
 const char *gfc_cpp_temporary_file (void);
 
 
diff --git a/gcc/fortran/gfortran.texi b/gcc/fortran/gfortran.texi
index 0512cb9..de6e18d 100644
--- a/gcc/fortran/gfortran.texi
+++ b/gcc/fortran/gfortran.texi
@@ -1951,9 +1951,6 @@  J3 Fortran 95 standard.
 User-specified alignment rules for structures.
 
 @item
-Flag to generate @code{Makefile} info.
-
-@item
 Automatically extend single precision constants to double.
 
 @item
diff --git a/gcc/fortran/gfortranspec.c b/gcc/fortran/gfortranspec.c
index 77324c8..7cb6db6 100644
--- a/gcc/fortran/gfortranspec.c
+++ b/gcc/fortran/gfortranspec.c
@@ -425,36 +425,6 @@  For more information about these matters, see the file named COPYING\n\n"));
 	  continue;
 	}
 
-      if ((argv[i][0] == '-') && (argv[i][1] == 'M'))
-	{
-	  char *p;
-
-	  fprintf (stderr, _("Warning: Using -M <directory> is deprecated, "
-	           "use -J instead\n"));
-	  if (argv[i][2] == '\0')
-	    {
-	      if (i+1 < argc)
-		{
-		  p = XNEWVEC (char, strlen (argv[i + 1]) + 3);
-		  p[0] = '-';
-		  p[1] = 'J';
-		  strcpy (&p[2], argv[i + 1]);
-		  i++;
-		}
-	      else
-		fatal ("argument to '%s' missing", argv[i]);
-	    }
-	  else
-	    {
-	      p = XNEWVEC (char, strlen (argv[i]) + 1);
-	      p[0] = '-';
-	      p[1] = 'J';
-	      strcpy (&p[2], argv[i] + 2);
-	    }
-	  append_arg (p);
-	  continue;
-	}
-
       if ((argv[i][0] == '-') && (argv[i][1] != 'l'))
 	{
 	  /* Not a filename or library.  */
diff --git a/gcc/fortran/invoke.texi b/gcc/fortran/invoke.texi
index 8e18dd2..738f6f7 100644
--- a/gcc/fortran/invoke.texi
+++ b/gcc/fortran/invoke.texi
@@ -148,8 +148,7 @@  and warnings}.
 
 @item Directory Options
 @xref{Directory Options,,Options for directory search}.
-@gccoptlist{-I@var{dir}  -J@var{dir}  -M@var{dir}  @gol
--fintrinsic-modules-path @var{dir}}
+@gccoptlist{-I@var{dir}  -J@var{dir} -fintrinsic-modules-path @var{dir}}
 
 @item Link Options
 @xref{Link Options,,Options for influencing the linking step}.
@@ -935,7 +934,6 @@  gcc,Using the GNU Compiler Collection (GCC)}, for information on the
 @option{-I} option.
 
 @item -J@var{dir}
-@item -M@var{dir}
 @opindex @code{J}@var{dir}
 @opindex @code{M}@var{dir}
 @cindex paths, search
@@ -946,8 +944,6 @@  statement.
 
 The default is the current directory.
 
-@option{-M} is deprecated to avoid conflicts with existing GCC options.
-
 @item -fintrinsic-modules-path @var{dir}
 @opindex @code{fintrinsic-modules-path} @var{dir}
 @cindex paths, search
diff --git a/gcc/fortran/lang-specs.h b/gcc/fortran/lang-specs.h
index a622dcb..4fe24de 100644
--- a/gcc/fortran/lang-specs.h
+++ b/gcc/fortran/lang-specs.h
@@ -28,7 +28,7 @@ 
 			     %{O*} %{undef}"
 
 /* Options that f951 should know about, even if not preprocessing.  */
-#define CPP_FORWARD_OPTIONS "%{i*} %{I*}"
+#define CPP_FORWARD_OPTIONS "%{i*} %{I*} %{M*}"
 
 #define F951_CPP_OPTIONS    "%{!nocpp: -cpp %g.f90 %{E} %(cpp_unique_options) \
 			     %{E|M|MM:%(cpp_debug_options) " CPP_ONLY_OPTIONS \
diff --git a/gcc/fortran/lang.opt b/gcc/fortran/lang.opt
index 64fd486..b7aef20 100644
--- a/gcc/fortran/lang.opt
+++ b/gcc/fortran/lang.opt
@@ -56,6 +56,42 @@  J
 Fortran Joined Separate
 -J<directory>	Put MODULE files in 'directory'
 
+M
+Fortran
+; Documented in C
+
+MD
+Fortran Separate
+; Documented in C
+
+MF
+Fortran Joined Separate
+; Documented in C
+
+MG
+Fortran
+; Documented in C
+
+MM
+Fortran
+; Documented in C
+
+MMD
+Fortran Separate
+; Documented in C
+
+MP
+Fortran
+; Documented in C
+
+MT
+Fortran Joined Separate
+; Documented in C
+
+MQ
+Fortran Joined Separate
+; Documented in C
+
 P
 Fortran
 ; Documented in C
diff --git a/gcc/fortran/module.c b/gcc/fortran/module.c
index 16f4ffd..8582e38 100644
--- a/gcc/fortran/module.c
+++ b/gcc/fortran/module.c
@@ -72,6 +72,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "match.h"
 #include "parse.h" /* FIXME */
 #include "md5.h"
+#include "cpp.h"
 
 #define MODULE_EXTENSION ".mod"
 
@@ -4839,6 +4840,9 @@  gfc_dump_module (const char *name, int dump_flag)
       return;
     }
 
+  if (gfc_cpp_makedep ())
+    gfc_cpp_add_target (filename);
+
   /* Write the module to the temporary file.  */
   module_fp = fopen (filename_tmp, "w");
   if (module_fp == NULL)
diff --git a/gcc/fortran/scanner.c b/gcc/fortran/scanner.c
index 1e7ec96..dc1fc82 100644
--- a/gcc/fortran/scanner.c
+++ b/gcc/fortran/scanner.c
@@ -389,7 +389,8 @@  gfc_release_include_path (void)
 
 
 static FILE *
-open_included_file (const char *name, gfc_directorylist *list, bool module)
+open_included_file (const char *name, gfc_directorylist *list,
+		    bool module, bool system)
 {
   char *fullname;
   gfc_directorylist *p;
@@ -406,7 +407,12 @@  open_included_file (const char *name, gfc_directorylist *list, bool module)
 
       f = gfc_open_file (fullname);
       if (f != NULL)
-	return f;
+	{
+	  if (gfc_cpp_makedep ())
+	    gfc_cpp_add_dep (fullname, system);
+
+	  return f;
+	}
     }
 
   return NULL;
@@ -420,28 +426,37 @@  open_included_file (const char *name, gfc_directorylist *list, bool module)
 FILE *
 gfc_open_included_file (const char *name, bool include_cwd, bool module)
 {
-  FILE *f;
+  FILE *f = NULL;
 
-  if (IS_ABSOLUTE_PATH (name))
-    return gfc_open_file (name);
-
-  if (include_cwd)
+  if (IS_ABSOLUTE_PATH (name) || include_cwd)
     {
       f = gfc_open_file (name);
-      if (f != NULL)
-	return f;
+      if (f && gfc_cpp_makedep ())
+	gfc_cpp_add_dep (name, false);
     }
 
-  return open_included_file (name, include_dirs, module);
+  if (!f)
+    f = open_included_file (name, include_dirs, module, false);
+
+  return f;
 }
 
 FILE *
 gfc_open_intrinsic_module (const char *name)
 {
+  FILE *f = NULL;
+
   if (IS_ABSOLUTE_PATH (name))
-    return gfc_open_file (name);
+    {
+      f = gfc_open_file (name);
+      if (f && gfc_cpp_makedep ())
+	gfc_cpp_add_dep (name, true);
+    }
+
+  if (!f)
+    f = open_included_file (name, intrinsic_modules_dirs, true, true);
 
-  return open_included_file (name, intrinsic_modules_dirs, true);
+  return f;
 }