diff mbox

[fortran] output of Makefile dependencies

Message ID 201006131436.46910.franke@embl-hamburg.de
State New
Headers show

Commit Message

Daniel Franke June 13, 2010, 12:36 p.m. UTC
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

Comments

Tobias Burnus June 13, 2010, 1:47 p.m. UTC | #1
Hi Daniel,

Daniel Franke wrote:
> Attached patch enables the output of Makefile dependencies.
> It handles '#include', 'INCLUDE' and module targets/use dependencies alike.
>   

Awesome!

I glanced at the patch - and I like it. However:

a) You need to change invoke.texi, it still lists -M as (deprecated)
synonym for -J.


b) gfortran.texi lists:
  @item
  Flag to generate @code{Makefile} info.
You should remove it.
(By the way, the "Proposed Extensions" and "Fortran 2003 and 2008
status" sections need to be updated badly.)


c) The patch does not work properly.

Assume: The file "iso_c_env.mod" exists, omp_lib.mod and 
omp_lib_kinds.mod do not

-------- x/other.f90 ------------
module m
  integer :: a
end module m

integer :: b
common /com/ b

-------- inc.f90 ------------
 include "other.f90"
end

subroutine test
  use, intrinsic :: iso_c_binding
  use, non_intrinsic :: iso_c_env
  use OMP_LIB
  use OMP_LIB_KINDS
end subroutine test
---------------------------------

$ gfortran -cpp -I./x -M inc.f90
inc.o m.mod: inc.f90 other.f90 iso_c_binding.mod iso_c_env.mod \
 omp_lib.mod omp_lib_kinds.mod


Expected:

- other.f90 misses the path "./x" in the name (it works for #include
"other.f90").

- The intrinsic modules "iso_c_binding.mod", "omp_lib.mod", and
"omp_lib_kinds.mod" shall not be listed - only the non_intrinsic module
"iso_c_env.mod".

- If possible: If - for instance - the "omp_lib.mod" file exists, add it
to the list as the standard has
"A use-stmt without a module-nature provides access either to an
intrinsic or to a nonintrinsic module. If the module-name is the name of
both an intrinsic and a nonintrinsic module, the nonintrinsic module is
accessed."
If the check can not easily be done, I think one can simply assume that
the intrinsic module is meant - which is the most likely case.

- Related to that: "use mod". If the module does not exist, "mod.mod"
would be OK, but if the file "x/mod.mod" exists, it probably should be
used. Again, as written above: If the check is difficult, simply output
"mod.mod".

Tobias
Daniel Franke June 13, 2010, 2:03 p.m. UTC | #2
On Sunday 13 June 2010 15:47:52 Tobias Burnus wrote:
> a) You need to change invoke.texi, it still lists -M as (deprecated)
> synonym for -J.
>
> b) gfortran.texi lists:
>   @item
>   Flag to generate @code{Makefile} info.
> You should remove it.
> (By the way, the "Proposed Extensions" and "Fortran 2003 and 2008
> status" sections need to be updated badly.)

Shall have a look.


> c) The patch does not work properly.
[...]
> $ gfortran -cpp -I./x -M inc.f90
> inc.o m.mod: inc.f90 other.f90 iso_c_binding.mod iso_c_env.mod \
>  omp_lib.mod omp_lib_kinds.mod
> 
> Expected:
> 
> - other.f90 misses the path "./x" in the name (it works for #include
> "other.f90").
> 
> - The intrinsic modules "iso_c_binding.mod", "omp_lib.mod", and
> "omp_lib_kinds.mod" shall not be listed - only the non_intrinsic module
> "iso_c_env.mod".

Try -MM.
"Like -M but do not mention header files that are found in system header 
directories, nor header files that are included, directly or indirectly, from 
such a header."

Renaming "MODULE m" to MODULE iso_c_env", I get:

$ gfortran-svn -cpp -I./x -MM other.f90
other.o iso_c_env.mod: other.f90 other.inc iso_c_env.mod

However, the path component on other.inc is missing.
Also strange, the iso_c_env.mod depends on itself. Not ideal, I assume.

 
> - If possible: If - for instance - the "omp_lib.mod" file exists, add it
> to the list as the standard has
> "A use-stmt without a module-nature provides access either to an
> intrinsic or to a nonintrinsic module. If the module-name is the name of
> both an intrinsic and a nonintrinsic module, the nonintrinsic module is
> accessed."
> If the check can not easily be done, I think one can simply assume that
> the intrinsic module is meant - which is the most likely case.

Probably already handled by -MM as well. If the file is found in a user 
include directory the 'system' parameter of gfc_cpp_add_dep() is set to false.

Cheers

	Daniel
diff mbox

Patch

Index: gfortranspec.c
===================================================================
--- gfortranspec.c	(revision 160677)
+++ gfortranspec.c	(working copy)
@@ -424,35 +424,6 @@  For more information about these matters
 	  continue;
 	}
 
-      if ((argv[i][0] == '-') && (argv[i][1] == 'M'))
-	{
-	  char *p;
-
-	  warning (0, "using -M <directory> is deprecated, use -J instead");
-	  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_error ("argument to %qs 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.  */
Index: lang-specs.h
===================================================================
--- lang-specs.h	(revision 160677)
+++ lang-specs.h	(working copy)
@@ -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 \
Index: lang.opt
===================================================================
--- lang.opt	(revision 160677)
+++ lang.opt	(working copy)
@@ -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
Index: cpp.h
===================================================================
--- cpp.h	(revision 160677)
+++ cpp.h	(working copy)
@@ -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);
 
 
Index: cpp.c
===================================================================
--- cpp.c	(revision 160677)
+++ cpp.c	(working copy)
@@ -35,6 +35,7 @@  along with GCC; see the file COPYING3.  
 #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 gfc_cpp_option_data
   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>  */
@@ -270,6 +277,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)
 {
@@ -299,6 +326,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;
@@ -414,6 +447,43 @@  gfc_cpp_handle_option (size_t scode, con
       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;
@@ -430,16 +500,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);
@@ -462,6 +533,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);
 
@@ -572,6 +654,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
@@ -615,14 +700,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);
 }
Index: module.c
===================================================================
--- module.c	(revision 160677)
+++ module.c	(working copy)
@@ -74,6 +74,7 @@  along with GCC; see the file COPYING3.  
 #include "parse.h" /* FIXME */
 #include "md5.h"
 #include "constructor.h"
+#include "cpp.h"
 
 #define MODULE_EXTENSION ".mod"
 
@@ -5120,6 +5121,9 @@  gfc_dump_module (const char *name, int d
       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)
@@ -5321,6 +5325,9 @@  import_iso_c_binding_module (void)
 		     "module ISO_C_BINDING", u->use_name, &u->where);
 	}
     }
+
+  if (gfc_cpp_makedep ())
+    gfc_cpp_add_dep ("iso_c_binding" MODULE_EXTENSION, true);
 }
 
 
@@ -5476,6 +5483,9 @@  use_iso_fortran_env_module (void)
 		     "module ISO_FORTRAN_ENV", u->use_name, &u->where);
 	}
     }
+
+  if (gfc_cpp_makedep ())
+    gfc_cpp_add_dep ("iso_fortran_env" MODULE_EXTENSION, true);
 }
 
 
Index: scanner.c
===================================================================
--- scanner.c	(revision 160677)
+++ scanner.c	(working copy)
@@ -421,28 +421,38 @@  open_included_file (const char *name, gf
 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);
+    f = gfc_open_file (name);
 
-  if (include_cwd)
-    {
-      f = gfc_open_file (name);
-      if (f != NULL)
-	return f;
-    }
+  if (!f && include_cwd)
+    f = gfc_open_file (name);
+
+  if (!f)
+    f = open_included_file (name, include_dirs, module);
 
-  return open_included_file (name, include_dirs, module);
+  if (f && gfc_cpp_makedep ())
+    gfc_cpp_add_dep (name, 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)
+    f = open_included_file (name, intrinsic_modules_dirs, true);
 
-  return open_included_file (name, intrinsic_modules_dirs, true);
+  if (f && gfc_cpp_makedep ())
+    gfc_cpp_add_dep (name, true);
+
+  return f;
 }