[m-rev.] for review: Add foreign include files to makefile dependencies files.

Peter Wang novalazy at gmail.com
Fri Mar 14 17:05:32 AEDT 2014


List files included by pragma foreign_decl and pragma foreign_code
declarations in the makefile dependencies file (`.d') generated for
a module.

The written dependencies are more conservative than necessary
(e.g. C target files should not depend on Java include files),
but I don't think any more effort is warranted.

compiler/module_imports.m:
	Add get_foreign_include_files to return a list of include files
	from a list of items.

compiler/modules.m:
	Add foreign include files when initialising the module_imports
	structure in grab_imported_modules. Otherwise it will be empty
	when the `.d' file is automatically generated as a side-effect
	of generating target code.

compiler/write_deps_file.m:
	Write include files from the module_imports structure into the
	`.d' file.

doc/reference_manual.texi:
	Update manual.

tests/invalid/Mmakefile:
	Make `missing_file' a phony target.  This change makes `make'
	aware of the dependency and report the error, instead of
	running the test case that checks the compiler's reaction
	to the missing file.
---

diff --git a/compiler/module_imports.m b/compiler/module_imports.m
index ed292c1..7e83fb7 100644
--- a/compiler/module_imports.m
+++ b/compiler/module_imports.m
@@ -250,6 +250,12 @@
     %
 :- pred get_fact_table_dependencies(list(item)::in, list(string)::out) is det.
 
+    % Get foreign include_file dependencies for a module.
+    % This replicates part of get_item_list_foreign_code.
+    %
+:- pred get_foreign_include_files(list(item)::in,
+    foreign_include_file_info_list::out) is det.
+
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
 
@@ -804,5 +810,37 @@ get_fact_table_dependencies_2([Item | Items], !Deps) :-
     get_fact_table_dependencies_2(Items, !Deps).
 
 %-----------------------------------------------------------------------------%
+
+get_foreign_include_files(Items, IncludeFiles) :-
+    list.foldl(get_foreign_include_file, Items, [], IncludeFiles).
+
+:- pred get_foreign_include_file(item::in,
+    foreign_include_file_info_list::in, foreign_include_file_info_list::out)
+    is det.
+
+get_foreign_include_file(Item, !IncludeFiles) :-
+    (
+        Item = item_pragma(ItemPragma),
+        ItemPragma = item_pragma_info(_, Pragma, _, _),
+        (
+            Pragma = pragma_foreign_decl(FDInfo),
+            FDInfo = pragma_info_foreign_decl(Lang, _IsLocal, LiteralOrInclude)
+        ;
+            Pragma = pragma_foreign_code(FCInfo),
+            FCInfo = pragma_info_foreign_code(Lang, LiteralOrInclude)
+        )
+    ->
+        (
+            LiteralOrInclude = literal(_)
+        ;
+            LiteralOrInclude = include_file(FileName),
+            IncludeFile = foreign_include_file_info(Lang, FileName),
+            !:IncludeFiles = [IncludeFile | !.IncludeFiles]
+        )
+    ;
+        true
+    ).
+
+%-----------------------------------------------------------------------------%
 :- end_module parse_tree.module_imports.
 %-----------------------------------------------------------------------------%
diff --git a/compiler/modules.m b/compiler/modules.m
index e2f6560..7bcf077 100644
--- a/compiler/modules.m
+++ b/compiler/modules.m
@@ -161,8 +161,8 @@
     % Similar to grab_imported_modules, but only reads in the unqualified
     % short interfaces (.int3s), and the .int0 files for parent modules,
     % instead of reading the long interfaces and qualified short interfaces
-    % (.int and int2s). Does not set the `PublicChildren' or `FactDeps'
-    % fields of the module_and_imports structure.
+    % (.int and int2s). Does not set the `PublicChildren', `FactDeps'
+    % `ForeignIncludeFiles' fields of the module_and_imports structure.
     %
 :- pred grab_unqual_imported_modules(globals::in, file_name::in,
     module_name::in, module_name::in, list(item)::in, module_and_imports::out,
@@ -1876,10 +1876,11 @@ grab_imported_modules(Globals, SourceFileName, SourceFileModuleName,
             ImpImportedModules0, ImpImportedModules,
             ImpUsedModules0, ImpUsedModules, !Specs),
 
-        get_fact_table_dependencies(Items0, FactDeps),
         get_interface_and_implementation(ModuleName, no, Items0,
             InterfaceItems, ImplItems),
         get_children(InterfaceItems, PublicChildren),
+        get_fact_table_dependencies(Items0, FactDeps),
+        get_foreign_include_files(Items0, ForeignIncludeFiles),
         (
             MaybeTimestamp = yes(Timestamp),
             MaybeTimestamps = yes(map.singleton(ModuleName,
@@ -1887,11 +1888,10 @@ grab_imported_modules(Globals, SourceFileName, SourceFileModuleName,
         ;
             MaybeTimestamp = no,
             MaybeTimestamps = no
-
         ),
         init_module_and_imports(SourceFileName, SourceFileModuleName,
             ModuleName, Items0, !.Specs, PublicChildren, NestedChildren,
-            FactDeps, MaybeTimestamps, !:Module),
+            FactDeps, ForeignIncludeFiles, MaybeTimestamps, !:Module),
 
         % If this module has any separately-compiled sub-modules, then
         % we need to make everything in the implementation of this module
@@ -2021,7 +2021,7 @@ grab_unqual_imported_modules(Globals, SourceFileName, SourceFileModuleName,
 
     % Construct the initial module import structure.
     init_module_and_imports(SourceFileName, SourceFileModuleName, ModuleName,
-        Items0, [], [], [], [], no, !:Module),
+        Items0, [], [], [], [], [], no, !:Module),
 
     % Add `builtin' and `private_builtin' to the imported modules.
     add_implicit_imports(Items0, Globals,
@@ -3602,11 +3602,12 @@ get_interface_and_implementation(ModuleName, IncludeImplTypes,
 :- pred init_module_and_imports(file_name::in,
     module_name::in, module_name::in, list(item)::in, list(error_spec)::in,
     list(module_name)::in, list(module_name)::in, list(string)::in,
+    foreign_include_file_info_list::in,
     maybe(module_timestamps)::in, module_and_imports::out) is det.
 
 init_module_and_imports(SourceFileName, SourceFileModuleName, ModuleName,
         Items0, Specs, PublicChildren, NestedChildren, FactDeps,
-        MaybeTimestamps, Module) :-
+        ForeignIncludeFiles, MaybeTimestamps, Module) :-
     % XXX The reason why init_module_and_imports is here and not in
     % module_imports.m is this call. This should be fixed, preferably
     % by changing the module_and_imports structure.
@@ -3614,9 +3615,9 @@ init_module_and_imports(SourceFileName, SourceFileModuleName, ModuleName,
     ItemsCord = cord.from_list(Items),
     Module = module_and_imports(SourceFileName, SourceFileModuleName,
         ModuleName, [], [], [], [], [], PublicChildren,
-        NestedChildren, FactDeps, contains_foreign_code_unknown, [], [],
-        contains_no_foreign_export, ItemsCord, Specs, no_module_errors,
-        MaybeTimestamps, no_main, dir.this_directory).
+        NestedChildren, FactDeps, contains_foreign_code_unknown, [],
+        ForeignIncludeFiles, contains_no_foreign_export, ItemsCord, Specs,
+        no_module_errors, MaybeTimestamps, no_main, dir.this_directory).
 
 :- pred maybe_add_foreign_import_module(module_name::in,
     list(item)::in, list(item)::out) is det.
diff --git a/compiler/write_deps_file.m b/compiler/write_deps_file.m
index 33b6e77..85d5cd9 100644
--- a/compiler/write_deps_file.m
+++ b/compiler/write_deps_file.m
@@ -36,9 +36,6 @@
     % `.trans_opt' file may depend on.  This is set to `no' if the
     % dependency list is not available.
     %
-    % XXX we do not yet write dependencies on files referenced by pragma
-    % foreign_decl or pragma foreign_code
-    %
 :- pred write_dependency_file(globals::in, module_and_imports::in,
     set(module_name)::in, maybe(list(module_name))::in, io::di, io::uo) is det.
 
@@ -109,7 +106,7 @@ write_dependency_file(Globals, Module, AllDepsSet, MaybeTransOptDeps, !IO) :-
     Module = module_and_imports(SourceFileName, SourceFileModuleName,
         ModuleName, ParentDeps, IntDeps, ImplDeps, IndirectDeps,
         _Children, InclDeps, NestedDeps, FactDeps0,
-        ContainsForeignCode, ForeignImports0, _ForeignIncludeFiles,
+        ContainsForeignCode, ForeignImports0, ForeignIncludeFiles,
         _ContainsForeignExport,
         Items, _Specs, _Error, _Timestamps, _HasMain, _Dir),
 
@@ -275,6 +272,12 @@ write_dependency_file(Globals, Module, AllDepsSet, MaybeTransOptDeps, !IO) :-
             ),
             list.foldl(Write, NestedExts, !IO)
         ),
+
+        % This is conservative: a target file for foreign language A does not
+        % does not truly depend on a file included for foreign language B.
+        write_foreign_include_file_dependencies_list(DepStream,
+            SourceFileName, ForeignIncludeFiles, !IO),
+
         (
             FactDeps = [_ | _],
             io.write_strings(DepStream, [
@@ -860,6 +863,25 @@ write_dll_dependency(Globals, Module, Prefix, DepStream, !IO) :-
     io.write_string(DepStream, Prefix, !IO),
     io.write_string(DepStream, FileName, !IO).
 
+:- pred write_foreign_include_file_dependencies_list(io.output_stream::in,
+    file_name::in, foreign_include_file_info_list::in, io::di, io::uo) is det.
+
+write_foreign_include_file_dependencies_list(DepStream, SourceFileName,
+        IncludeFiles, !IO) :-
+    list.foldl(
+        write_foreign_include_file_dependency(DepStream, SourceFileName),
+        IncludeFiles, !IO).
+
+:- pred write_foreign_include_file_dependency(io.output_stream::in,
+    file_name::in, foreign_include_file_info::in, io::di, io::uo) is det.
+
+write_foreign_include_file_dependency(DepStream, SourceFileName,
+        IncludeFile, !IO) :-
+    IncludeFile = foreign_include_file_info(_Lang, IncludeFileName),
+    make_include_file_path(SourceFileName, IncludeFileName, IncludePath),
+    io.write_string(DepStream, " \\\n\t", !IO),
+    io.write_string(DepStream, IncludePath, !IO).
+
 :- pred write_fact_table_dependencies_list(globals::in, module_name::in,
     list(file_name)::in, string::in, io.output_stream::in,
     io::di, io::uo) is det.
diff --git a/doc/reference_manual.texi b/doc/reference_manual.texi
index 525aa26..382e64fa 100644
--- a/doc/reference_manual.texi
+++ b/doc/reference_manual.texi
@@ -9566,8 +9566,8 @@ the string literal in the last argument, without further interpretation.
 directory that contains the source file of the module containing the
 declaration. The interpretation of the path is platform-dependent.
 
-The @samp{mmc --make} tool takes @samp{include_file} references into
-account when computing dependencies.
+ at samp{mmc --make} and @samp{mmake} treat included files as dependencies
+of the module.
 
 @node Fact tables
 @section Fact tables
diff --git a/tests/invalid/Mmakefile b/tests/invalid/Mmakefile
index b27ca64..c81d474 100644
--- a/tests/invalid/Mmakefile
+++ b/tests/invalid/Mmakefile
@@ -455,6 +455,7 @@ illtyped_compare.err: illtyped_compare.m
 
 # For foreign_include_file_missing, the error is only caught when generating
 # target code.
+.PHONY: missing_file
 foreign_include_file_missing.err: foreign_include_file_missing.m
 	if $(MC) --target-code-only $(ALL_GRADEFLAGS) $(ALL_MCFLAGS) \
 			$* > $*.err 2>&1; \



More information about the reviews mailing list