mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-15 01:13:30 +00:00
compiler/file_names.m:
Replace several groups of extensions that stood for semantically
different groups of extensions by one group, the "always in the
current directory" group. The enum type of the new type representing
the now larger group consists of the enum values from the types
representing the old, smaller groups. The old boundaries are thus
no longer expressed in types, but still remain in the naming schemes
of the enum values.
Once we have done the same for the six other groups of extensions,
with each group having its own pattern of where its extensions are put
under which circumstances, we can replace code that does multiple
modulename+extension to filename translations with code that does
one modulename+extension to DIRECTORY PATH translation, and then
constructs multiple filenames from that, repeating just the
"extension enum to extension string" part of the old translation
for each operand. We can do this because unlike the old extension
categories, the new ones will make clear which groups of extensions
are guarantee to map to the same directory path, and which have
no such guarantee.
compiler/compile_target_code.m:
compiler/export.m:
compiler/generate_dep_d_files.m:
compiler/make.build.m:
compiler/make.file_names.m:
compiler/make.module_dep_file.m:
compiler/make.program_target.m:
compiler/mercury_compile_llds_back_end.m:
compiler/mercury_compile_main.m:
compiler/mercury_compile_make_hlds.m:
compiler/mercury_compile_mlds_back_end.m:
compiler/mlds_to_c_file.m:
compiler/write_deps_file.m:
Conform to the changes above.
1087 lines
45 KiB
Mathematica
1087 lines
45 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 expandtab
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 2002-2009, 2011 The University of Melbourne.
|
|
% Copyright (C) 2014-2017, 2019-2020 The Mercury team.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% File: make.module_dep_file.m.
|
|
% Author: stayl.
|
|
%
|
|
% Code to read and write the `<module>.module_dep' files, which contain
|
|
% information about inter-module dependencies.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module make.module_dep_file.
|
|
:- interface.
|
|
|
|
:- import_module libs.
|
|
:- import_module libs.globals.
|
|
:- import_module make.make_info.
|
|
:- import_module mdbcomp.
|
|
:- import_module mdbcomp.sym_name.
|
|
:- import_module parse_tree.
|
|
:- import_module parse_tree.module_baggage.
|
|
|
|
:- import_module io.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Get the dependencies for a given module.
|
|
% Dependencies are generated on demand, not by a `mmc --make depend'
|
|
% command, so this predicate may need to read the source for the module.
|
|
%
|
|
:- pred get_module_dependencies(globals::in, module_name::in,
|
|
maybe_module_dep_info::out, make_info::in, make_info::out,
|
|
io::di, io::uo) is det.
|
|
|
|
:- pred write_module_dep_file(globals::in, burdened_module::in,
|
|
io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module libs.file_util.
|
|
:- import_module libs.maybe_util.
|
|
:- import_module libs.options.
|
|
:- import_module libs.process_util.
|
|
:- import_module libs.timestamp.
|
|
:- import_module make.build.
|
|
:- import_module make.file_names.
|
|
:- import_module make.module_target.
|
|
:- import_module make.timestamp.
|
|
:- import_module make.util.
|
|
:- import_module parse_tree.file_names.
|
|
:- import_module parse_tree.find_module.
|
|
:- import_module parse_tree.get_dependencies.
|
|
:- import_module parse_tree.item_util.
|
|
:- import_module parse_tree.module_dep_info.
|
|
:- import_module parse_tree.parse_error.
|
|
:- import_module parse_tree.parse_sym_name.
|
|
:- import_module parse_tree.parse_tree_out_misc.
|
|
:- import_module parse_tree.parse_tree_out_sym_name.
|
|
:- import_module parse_tree.prog_data_foreign.
|
|
:- import_module parse_tree.prog_item.
|
|
:- import_module parse_tree.read_modules.
|
|
:- import_module parse_tree.write_error_spec.
|
|
:- import_module parse_tree.write_module_interface_files.
|
|
|
|
:- import_module bool.
|
|
:- import_module dir.
|
|
:- import_module getopt.
|
|
:- import_module io.file.
|
|
:- import_module list.
|
|
:- import_module map.
|
|
:- import_module maybe.
|
|
:- import_module mercury_term_parser.
|
|
:- import_module require.
|
|
:- import_module set.
|
|
:- import_module string.
|
|
:- import_module term.
|
|
:- import_module term_int.
|
|
:- import_module term_io.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% The version 1 module_dep file format is the same as version 2 except that
|
|
% it does not include a list of files included by `pragma foreign_decl' and
|
|
% `pragma foreign_code'. We continue to write version 1 files when
|
|
% possible.
|
|
%
|
|
% XXX We should consider
|
|
%
|
|
% - adding a version 3 that differs from 2 in deleting the field
|
|
% that now *always* contains "no_main", and
|
|
% - switching to always generating version 3.
|
|
%
|
|
% XXX The precise on-disk representation of each (current) module_dep file
|
|
% format version should be explicitly documented. This documentation
|
|
% should explain what the meaning of each field is, what purposes
|
|
% does it servce, an what invariants (if any) apply to it. It should
|
|
% also have some examples to help readers understand it all.
|
|
%
|
|
:- type module_dep_file_version
|
|
---> module_dep_file_v1
|
|
; module_dep_file_v2.
|
|
|
|
:- pred version_number(module_dep_file_version, int).
|
|
:- mode version_number(in, out) is det.
|
|
:- mode version_number(out, in) is semidet.
|
|
|
|
version_number(module_dep_file_v1, 1).
|
|
version_number(module_dep_file_v2, 2).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
get_module_dependencies(Globals, ModuleName, MaybeModuleDepInfo, !Info, !IO) :-
|
|
RebuildModuleDeps = make_info_get_rebuild_module_deps(!.Info),
|
|
(
|
|
ModuleName = unqualified(_),
|
|
maybe_get_module_dependencies(Globals, RebuildModuleDeps, ModuleName,
|
|
MaybeModuleDepInfo, !Info, !IO)
|
|
;
|
|
ModuleName = qualified(_, _),
|
|
% For submodules, we need to generate the dependencies for the
|
|
% parent modules first (make_module_dependencies expects to be given
|
|
% the top-level module in a source file).
|
|
% If the module is a nested module, its dependencies will be generated
|
|
% as a side effect of generating the parent's dependencies.
|
|
AncestorsAndSelf = get_ancestors(ModuleName) ++ [ModuleName],
|
|
Error0 = no,
|
|
maybe_get_modules_dependencies(Globals, RebuildModuleDeps,
|
|
AncestorsAndSelf, Error0, !Info, !IO),
|
|
|
|
ModuleDepMap = make_info_get_module_dependencies(!.Info),
|
|
map.lookup(ModuleDepMap, ModuleName, MaybeModuleDepInfo)
|
|
).
|
|
|
|
:- pred maybe_get_modules_dependencies(globals::in,
|
|
maybe_rebuild_module_deps::in, list(module_name)::in, bool::in,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
maybe_get_modules_dependencies(_Globals, _RebuildModuleDeps,
|
|
[], _, !Info, !IO).
|
|
maybe_get_modules_dependencies(Globals, RebuildModuleDeps,
|
|
[ModuleName | ModuleNames], !.Error, !Info, !IO) :-
|
|
(
|
|
!.Error = no,
|
|
maybe_get_module_dependencies(Globals, RebuildModuleDeps, ModuleName,
|
|
MaybeModuleDepInfo, !Info, !IO),
|
|
(
|
|
MaybeModuleDepInfo = some_module_dep_info(_)
|
|
;
|
|
MaybeModuleDepInfo = no_module_dep_info,
|
|
!:Error = yes
|
|
)
|
|
;
|
|
!.Error = yes,
|
|
% If we found a problem when processing an ancestor, don't even try
|
|
% to process the later modules.
|
|
ModuleDepMap0 = make_info_get_module_dependencies(!.Info),
|
|
% XXX Could this be map.det_update or map.det_insert?
|
|
map.set(ModuleName, no_module_dep_info, ModuleDepMap0, ModuleDepMap),
|
|
make_info_set_module_dependencies(ModuleDepMap, !Info)
|
|
),
|
|
maybe_get_modules_dependencies(Globals, RebuildModuleDeps,
|
|
ModuleNames, !.Error, !Info, !IO).
|
|
|
|
:- pred maybe_get_module_dependencies(globals::in,
|
|
maybe_rebuild_module_deps::in, module_name::in, maybe_module_dep_info::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
maybe_get_module_dependencies(Globals, RebuildModuleDeps, ModuleName,
|
|
MaybeModuleDepInfo, !Info, !IO) :-
|
|
ModuleDepMap0 = make_info_get_module_dependencies(!.Info),
|
|
( if map.search(ModuleDepMap0, ModuleName, MaybeModuleDepInfo0) then
|
|
MaybeModuleDepInfo = MaybeModuleDepInfo0
|
|
else
|
|
do_get_module_dependencies(Globals, RebuildModuleDeps, ModuleName,
|
|
MaybeModuleDepInfo, !Info, !IO)
|
|
).
|
|
|
|
:- pred do_get_module_dependencies(globals::in, maybe_rebuild_module_deps::in,
|
|
module_name::in, maybe_module_dep_info::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
do_get_module_dependencies(Globals, RebuildModuleDeps, ModuleName,
|
|
!:MaybeModuleDepInfo, !Info, !IO) :-
|
|
% We can't just use
|
|
% `get_target_timestamp(ModuleName - source, ..)'
|
|
% because that could recursively call get_module_dependencies,
|
|
% leading to an infinite loop. Just using module_name_to_file_name
|
|
% will fail if the module name doesn't match the file name, but
|
|
% that case is handled below.
|
|
module_name_to_source_file_name(ModuleName, SourceFileName, !IO),
|
|
get_file_timestamp([dir.this_directory], SourceFileName,
|
|
MaybeSourceFileTimestamp, !Info, !IO),
|
|
|
|
module_name_to_file_name(Globals, $pred,
|
|
ext_misc_ngs(ext_misc_ngs_module_dep), ModuleName, DepFileName),
|
|
globals.lookup_accumulating_option(Globals, search_directories,
|
|
SearchDirs),
|
|
get_file_timestamp(SearchDirs, DepFileName, MaybeDepFileTimestamp,
|
|
!Info, !IO),
|
|
(
|
|
MaybeSourceFileTimestamp = ok(SourceFileTimestamp),
|
|
MaybeDepFileTimestamp = ok(DepFileTimestamp),
|
|
( if
|
|
( RebuildModuleDeps = do_not_rebuild_module_deps
|
|
; compare((>), DepFileTimestamp, SourceFileTimestamp)
|
|
)
|
|
then
|
|
% Since the source file was found in this directory, do not use
|
|
% module_dep files which might be for installed copies
|
|
% of the module.
|
|
%
|
|
% XXX SourceFileName may not actually be the correct source file
|
|
% for the required module. Usually the purported source file would
|
|
% have a later timestamp than the .module_dep file, though, so the
|
|
% other branch would be taken.
|
|
read_module_dependencies_no_search(Globals, RebuildModuleDeps,
|
|
ModuleName, !Info, !IO)
|
|
else
|
|
make_module_dependencies(Globals, ModuleName, !Info, !IO)
|
|
)
|
|
;
|
|
MaybeSourceFileTimestamp = error(_),
|
|
MaybeDepFileTimestamp = ok(DepFileTimestamp),
|
|
read_module_dependencies_search(Globals, RebuildModuleDeps,
|
|
ModuleName, !Info, !IO),
|
|
|
|
% Check for the case where the module name doesn't match the
|
|
% source file name (e.g. parse.m contains module mdb.parse).
|
|
% Get the correct source file name from the module dependency file,
|
|
% then check whether the module dependency file is up to date.
|
|
|
|
map.lookup(make_info_get_module_dependencies(!.Info), ModuleName,
|
|
!:MaybeModuleDepInfo),
|
|
( if
|
|
!.MaybeModuleDepInfo = some_module_dep_info(ModuleDepInfo0),
|
|
module_dep_info_get_source_file_dir(ModuleDepInfo0, ModuleDir),
|
|
ModuleDir = dir.this_directory
|
|
then
|
|
module_dep_info_get_source_file_name(ModuleDepInfo0,
|
|
SourceFileName1),
|
|
get_file_timestamp([dir.this_directory], SourceFileName1,
|
|
MaybeSourceFileTimestamp1, !Info, !IO),
|
|
(
|
|
MaybeSourceFileTimestamp1 = ok(SourceFileTimestamp1),
|
|
( if
|
|
( RebuildModuleDeps = do_not_rebuild_module_deps
|
|
; compare((>), DepFileTimestamp, SourceFileTimestamp1)
|
|
)
|
|
then
|
|
true
|
|
else
|
|
% XXX The existence of a .module_dep file reflects a
|
|
% previous state of the workspace which may not match the
|
|
% current workspace.
|
|
%
|
|
% Here is a (contrived) case where we run into an issue:
|
|
% 1. create prog.m which imports the standard library lexer
|
|
% module
|
|
% 2. copy the standard library lexer.m file to the current
|
|
% directory for editing
|
|
% 3. run mmc --make; it creates lexer.module_dep
|
|
% 4. change lexer.m into a submodule of prog
|
|
% 5. run mmc --make again, it no longer works
|
|
%
|
|
% The local lexer.module_dep prevents mmc --make finding
|
|
% the lexer.module_dep from the standard library, even
|
|
% though there is no longer any local source file for the
|
|
% `lexer' module.
|
|
|
|
make_module_dependencies(Globals, ModuleName, !Info, !IO)
|
|
)
|
|
;
|
|
MaybeSourceFileTimestamp1 = error(Message),
|
|
io.format("** Error reading file `%s' " ++
|
|
"to generate dependencies: %s.\n",
|
|
[s(SourceFileName1), s(Message)], !IO),
|
|
maybe_write_importing_module(ModuleName,
|
|
make_info_get_importing_module(!.Info), !IO)
|
|
)
|
|
else
|
|
true
|
|
)
|
|
;
|
|
MaybeDepFileTimestamp = error(_),
|
|
SearchDirsString = join_list(", ",
|
|
map((func(Dir) = "`" ++ Dir ++ "'"), SearchDirs)),
|
|
debug_make_msg(Globals,
|
|
string.format(
|
|
"Module dependencies file '%s' not found in directories %s.\n",
|
|
[s(DepFileName), s(SearchDirsString)]),
|
|
DebugMsg),
|
|
% XXX MAKE_STREAM
|
|
maybe_write_msg(DebugMsg, !IO),
|
|
|
|
% Try to make the dependencies. This will succeed when the module name
|
|
% doesn't match the file name and the dependencies for this module
|
|
% haven't been built before. It will fail if the source file
|
|
% is in another directory.
|
|
(
|
|
RebuildModuleDeps = do_rebuild_module_deps,
|
|
make_module_dependencies(Globals, ModuleName, !Info, !IO)
|
|
;
|
|
RebuildModuleDeps = do_not_rebuild_module_deps,
|
|
ModuleDepMap0 = make_info_get_module_dependencies(!.Info),
|
|
% XXX Could this be map.det_update or map.det_insert?
|
|
map.set(ModuleName, no_module_dep_info,
|
|
ModuleDepMap0, ModuleDepMap1),
|
|
make_info_set_module_dependencies(ModuleDepMap1, !Info)
|
|
)
|
|
),
|
|
ModuleDepMap2 = make_info_get_module_dependencies(!.Info),
|
|
( if map.search(ModuleDepMap2, ModuleName, MaybeModuleDepInfo0) then
|
|
!:MaybeModuleDepInfo = MaybeModuleDepInfo0
|
|
else
|
|
!:MaybeModuleDepInfo = no_module_dep_info,
|
|
map.det_insert(ModuleName, no_module_dep_info,
|
|
ModuleDepMap2, ModuleDepMap),
|
|
make_info_set_module_dependencies(ModuleDepMap, !Info)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
write_module_dep_file(Globals, BurdenedModule0, !IO) :-
|
|
BurdenedModule0 = burdened_module(Baggage0, ParseTreeModuleSrc),
|
|
Baggage0 = module_baggage(SourceFileName, _SourceFileDir,
|
|
SourceFileModuleName, MaybeTopModule, _MaybeTimestampMap,
|
|
_GrabbedFileMap, _Errors),
|
|
|
|
MaybeTimestampMap = maybe.no,
|
|
ModuleName = ParseTreeModuleSrc ^ ptms_module_name,
|
|
GrabbedFileMap = map.singleton(ModuleName, gf_src(ParseTreeModuleSrc)),
|
|
Errors = init_read_module_errors,
|
|
Baggage = module_baggage(SourceFileName, dir.this_directory,
|
|
SourceFileModuleName, MaybeTopModule, MaybeTimestampMap,
|
|
GrabbedFileMap, Errors),
|
|
|
|
BurdenedModule = burdened_module(Baggage, ParseTreeModuleSrc),
|
|
do_write_module_dep_file(Globals, BurdenedModule, !IO).
|
|
|
|
:- pred do_write_module_dep_file(globals::in, burdened_module::in,
|
|
io::di, io::uo) is det.
|
|
|
|
do_write_module_dep_file(Globals, BurdenedModule, !IO) :-
|
|
BurdenedModule = burdened_module(Baggage, ParseTreeModuleSrc),
|
|
ModuleName = ParseTreeModuleSrc ^ ptms_module_name,
|
|
module_name_to_file_name_create_dirs(Globals, $pred,
|
|
ext_misc_ngs(ext_misc_ngs_module_dep), ModuleName, ProgDepFile, !IO),
|
|
io.open_output(ProgDepFile, ProgDepResult, !IO),
|
|
(
|
|
ProgDepResult = ok(ProgDepStream),
|
|
do_write_module_dep_file_to_stream(ProgDepStream, Globals,
|
|
Baggage, ParseTreeModuleSrc, !IO),
|
|
io.close_output(ProgDepStream, !IO)
|
|
;
|
|
ProgDepResult = error(Error),
|
|
io.error_message(Error, Msg),
|
|
io.format("Error opening %s for output: %s\n",
|
|
[s(ProgDepFile), s(Msg)], !IO),
|
|
io.set_exit_status(1, !IO)
|
|
).
|
|
|
|
:- pred do_write_module_dep_file_to_stream(io.text_output_stream::in,
|
|
globals::in, module_baggage::in, parse_tree_module_src::in,
|
|
io::di, io::uo) is det.
|
|
|
|
do_write_module_dep_file_to_stream(Stream, Globals,
|
|
Baggage, ParseTreeModuleSrc, !IO) :-
|
|
Version = module_dep_file_v2,
|
|
version_number(Version, VersionNumber),
|
|
SourceFileName = Baggage ^ mb_source_file_name,
|
|
SourceFileModuleName = Baggage ^ mb_source_file_module_name,
|
|
SourceFileModuleNameStr =
|
|
mercury_bracketed_sym_name_to_string(SourceFileModuleName),
|
|
ModuleName = ParseTreeModuleSrc ^ ptms_module_name,
|
|
Ancestors = set.to_sorted_list(get_ancestors_set(ModuleName)),
|
|
IncludeMap = ParseTreeModuleSrc ^ ptms_include_map,
|
|
Children = map.keys(IncludeMap),
|
|
parse_tree_module_src_get_int_imp_deps(ParseTreeModuleSrc,
|
|
IntDepSet, ImpDepSet),
|
|
set.to_sorted_list(IntDepSet, IntDeps),
|
|
set.to_sorted_list(ImpDepSet, ImpDeps),
|
|
MaybeTopModule = Baggage ^ mb_maybe_top_module,
|
|
NestedSubModules = get_nested_children_list_of_top_module(MaybeTopModule),
|
|
get_fact_tables(ParseTreeModuleSrc, FactTableFilesSet),
|
|
FactTableFilesStrs = list.map(term_io.quoted_string,
|
|
set.to_sorted_list(FactTableFilesSet)),
|
|
globals.get_backend_foreign_languages(Globals, BackendLangsList),
|
|
BackendLangs = set.list_to_set(BackendLangsList),
|
|
get_foreign_code_langs(ParseTreeModuleSrc, CodeLangs),
|
|
get_foreign_export_langs(ParseTreeModuleSrc, ExportLangs),
|
|
set.intersect(BackendLangs, CodeLangs, BackendCodeLangs),
|
|
set.intersect(BackendLangs, ExportLangs, BackendExportLangs),
|
|
CodeLangStrs = list.map(mercury_foreign_language_to_string,
|
|
set.to_sorted_list(BackendCodeLangs)),
|
|
( if set.is_empty(BackendExportLangs) then
|
|
ContainsForeignExport = contains_no_foreign_export
|
|
else
|
|
ContainsForeignExport = contains_foreign_export
|
|
),
|
|
get_fim_specs(ParseTreeModuleSrc, FIMSpecs),
|
|
get_foreign_include_file_infos(ParseTreeModuleSrc, ForeignIncludeFiles),
|
|
FIMSpecStrs = list.map(fim_spec_to_string, set.to_sorted_list(FIMSpecs)),
|
|
FIFOStrs = list.map(foreign_include_file_info_to_string,
|
|
set.to_sorted_list(ForeignIncludeFiles)),
|
|
contains_foreign_export_to_string(ContainsForeignExport,
|
|
ContainsForeignExportStr),
|
|
io.format(Stream,
|
|
"module(%d, ""%s"",\n" ++
|
|
"\t%s,\n" ++
|
|
"\t{%s},\n" ++
|
|
"\t{%s},\n" ++
|
|
"\t{%s},\n" ++
|
|
"\t{%s},\n" ++
|
|
"\t{%s},\n" ++
|
|
"\t{%s},\n" ++
|
|
"\t{%s},\n" ++
|
|
"\t{%s},\n" ++
|
|
"\t%s,\n" ++
|
|
% The has_main/no_main slot is not needed anymore,
|
|
% so we just put no_main in there always.
|
|
"\tno_main,\n" ++
|
|
"\t{%s}\n" ++
|
|
").\n",
|
|
[i(VersionNumber), s(SourceFileName),
|
|
s(SourceFileModuleNameStr),
|
|
s(bracketed_sym_names_to_comma_list_string(Ancestors)),
|
|
s(bracketed_sym_names_to_comma_list_string(IntDeps)),
|
|
s(bracketed_sym_names_to_comma_list_string(ImpDeps)),
|
|
s(bracketed_sym_names_to_comma_list_string(Children)),
|
|
s(bracketed_sym_names_to_comma_list_string(NestedSubModules)),
|
|
s(string.join_list(", ", FactTableFilesStrs)),
|
|
s(string.join_list(", ", CodeLangStrs)),
|
|
s(string.join_list(", ", FIMSpecStrs)),
|
|
s(ContainsForeignExportStr),
|
|
s(string.join_list(", ", FIFOStrs))],
|
|
!IO).
|
|
|
|
:- func bracketed_sym_names_to_comma_list_string(list(sym_name)) = string.
|
|
|
|
bracketed_sym_names_to_comma_list_string(SymNames) = Str :-
|
|
Strs = list.map(mercury_bracketed_sym_name_to_string, SymNames),
|
|
Str = string.join_list(", ", Strs).
|
|
|
|
:- func fim_spec_to_string(fim_spec) = string.
|
|
|
|
fim_spec_to_string(FIMSpec) = Str :-
|
|
FIMSpec = fim_spec(Lang, ForeignImport),
|
|
LangStr = mercury_foreign_language_to_string(Lang),
|
|
ForeignImportStr = mercury_bracketed_sym_name_to_string(ForeignImport),
|
|
Str = LangStr ++ " - " ++ ForeignImportStr.
|
|
|
|
:- func foreign_include_file_info_to_string(foreign_include_file_info)
|
|
= string.
|
|
|
|
foreign_include_file_info_to_string(ForeignInclude) = Str :-
|
|
ForeignInclude = foreign_include_file_info(Lang, FileName),
|
|
LangStr = mercury_foreign_language_to_string(Lang),
|
|
Str = LangStr ++ " - " ++ term_io.quoted_string(FileName).
|
|
|
|
:- pred contains_foreign_export_to_string(contains_foreign_export, string).
|
|
:- mode contains_foreign_export_to_string(in, out) is det.
|
|
:- mode contains_foreign_export_to_string(out, in) is semidet.
|
|
|
|
contains_foreign_export_to_string(ContainsForeignExport,
|
|
ContainsForeignExportStr) :-
|
|
(
|
|
ContainsForeignExport = contains_foreign_export,
|
|
ContainsForeignExportStr = "contains_foreign_export"
|
|
;
|
|
ContainsForeignExport = contains_no_foreign_export,
|
|
% Yes, without the "contains_" prefix. Don't change it unless you mean
|
|
% to break compatibility with older .module_dep files.
|
|
ContainsForeignExportStr = "no_foreign_export"
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred read_module_dependencies_search(globals::in,
|
|
maybe_rebuild_module_deps::in, module_name::in,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
read_module_dependencies_search(Globals, RebuildModuleDeps, ModuleName,
|
|
!Info, !IO) :-
|
|
globals.lookup_accumulating_option(Globals, search_directories,
|
|
SearchDirs),
|
|
read_module_dependencies_2(Globals, RebuildModuleDeps, SearchDirs,
|
|
ModuleName, !Info, !IO).
|
|
|
|
:- pred read_module_dependencies_no_search(globals::in,
|
|
maybe_rebuild_module_deps::in, module_name::in,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
read_module_dependencies_no_search(Globals, RebuildModuleDeps, ModuleName,
|
|
!Info, !IO) :-
|
|
read_module_dependencies_2(Globals, RebuildModuleDeps,
|
|
[dir.this_directory], ModuleName, !Info, !IO).
|
|
|
|
:- pred read_module_dependencies_2(globals::in, maybe_rebuild_module_deps::in,
|
|
list(dir_name)::in, module_name::in, make_info::in, make_info::out,
|
|
io::di, io::uo) is det.
|
|
|
|
read_module_dependencies_2(Globals, RebuildModuleDeps, SearchDirs, ModuleName,
|
|
!Info, !IO) :-
|
|
module_name_to_search_file_name(Globals, $pred,
|
|
ext_misc_ngs(ext_misc_ngs_module_dep), ModuleName, ModuleDepFile),
|
|
search_for_file_returning_dir_and_stream(SearchDirs, ModuleDepFile,
|
|
MaybeDirAndStream, !IO),
|
|
(
|
|
MaybeDirAndStream = ok(path_name_and_stream(ModuleDir, DepStream)),
|
|
mercury_term_parser.read_term(DepStream, TermResult, !IO),
|
|
io.close_input(DepStream, !IO),
|
|
(
|
|
TermResult = term(_, Term),
|
|
read_module_dependencies_3(Globals, SearchDirs, ModuleName,
|
|
ModuleDir, ModuleDepFile, Term, Result, !Info, !IO)
|
|
;
|
|
TermResult = eof,
|
|
Result = error("unexpected eof")
|
|
;
|
|
TermResult = error(ParseError, _),
|
|
Result = error("parse error: " ++ ParseError)
|
|
),
|
|
(
|
|
Result = ok
|
|
;
|
|
Result = error(ErrorMsg),
|
|
read_module_dependencies_remake_msg(RebuildModuleDeps,
|
|
ModuleDir ++ "/" ++ ModuleDepFile, ErrorMsg, Msg),
|
|
% XXX MAKE_STREAM
|
|
io.write_string(Msg, !IO),
|
|
read_module_dependencies_remake(Globals, RebuildModuleDeps,
|
|
ModuleName, !Info, !IO)
|
|
)
|
|
;
|
|
MaybeDirAndStream = error(ErrorMsg),
|
|
debug_make_msg(Globals,
|
|
read_module_dependencies_remake_msg(RebuildModuleDeps,
|
|
ModuleDepFile, ErrorMsg),
|
|
DebugMsg),
|
|
% XXX MAKE_STREAM
|
|
maybe_write_msg(DebugMsg, !IO),
|
|
read_module_dependencies_remake(Globals, RebuildModuleDeps,
|
|
ModuleName, !Info, !IO)
|
|
).
|
|
|
|
:- pred read_module_dependencies_3(globals::in, list(dir_name)::in,
|
|
module_name::in, dir_name::in, file_name::in, term::in, maybe_error::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
read_module_dependencies_3(Globals, SearchDirs, ModuleName, ModuleDir,
|
|
ModuleDepFile, Term, Result, !Info, !IO) :-
|
|
( if
|
|
parse_module_summary_file(ModuleName, ModuleDir, Term, ModuleSummary)
|
|
then
|
|
ModuleDepInfo = module_dep_info_summary(ModuleSummary),
|
|
MaybeModuleDepInfo = some_module_dep_info(ModuleDepInfo),
|
|
|
|
% Discard the module dependencies if the module is a local module
|
|
% but the source file no longer exists.
|
|
( if ModuleDir = dir.this_directory then
|
|
SourceFileName = ModuleSummary ^ mds_source_file_name,
|
|
check_regular_file_exists(SourceFileName, SourceFileExists, !IO),
|
|
(
|
|
SourceFileExists = ok
|
|
;
|
|
SourceFileExists = error(_),
|
|
io.file.remove_file(ModuleDepFile, _, !IO)
|
|
)
|
|
else
|
|
SourceFileExists = ok
|
|
),
|
|
(
|
|
SourceFileExists = ok,
|
|
ModuleDepMap0 = make_info_get_module_dependencies(!.Info),
|
|
% XXX Could this be map.det_insert?
|
|
map.set(ModuleName, MaybeModuleDepInfo,
|
|
ModuleDepMap0, ModuleDepMap),
|
|
make_info_set_module_dependencies(ModuleDepMap, !Info),
|
|
|
|
% Read the dependencies for any nested children. If something
|
|
% goes wrong (for example one of the files was removed), the
|
|
% dependencies for all modules in the source file will be remade
|
|
% (make_module_dependencies expects to be given the top-level
|
|
% module in the source file).
|
|
MaybeTopModule = ModuleSummary ^ mds_maybe_top_module,
|
|
NestedSubModules =
|
|
get_nested_children_list_of_top_module(MaybeTopModule),
|
|
list.foldl2(
|
|
read_module_dependencies_2(Globals,
|
|
do_not_rebuild_module_deps, SearchDirs),
|
|
NestedSubModules, !Info, !IO),
|
|
( if some_bad_module_dependency(!.Info, NestedSubModules) then
|
|
Result = error("error in nested submodules")
|
|
else
|
|
Result = ok
|
|
)
|
|
;
|
|
SourceFileExists = error(Error),
|
|
Result = error(Error)
|
|
)
|
|
else
|
|
Result = error("failed to parse term")
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred parse_module_summary_file(module_name::in, dir_name::in, term::in,
|
|
module_dep_summary::out) is semidet.
|
|
|
|
parse_module_summary_file(ModuleName, ModuleDir, Term, ModuleSummary) :-
|
|
atom_term(Term, "module", ModuleArgs),
|
|
ModuleArgs = [
|
|
VersionNumberTerm,
|
|
SourceFileTerm,
|
|
SourceFileModuleNameTerm,
|
|
ParentsTerm, % XXX Redundant term
|
|
IntDepsTerm,
|
|
ImpDepsTerm,
|
|
ChildrenTerm,
|
|
NestedSubModulesTerm,
|
|
FactDepsTerm,
|
|
ForeignLanguagesTerm,
|
|
ForeignImportsTerm,
|
|
ContainsForeignExportTerm,
|
|
_HasMainTerm % XXX Redundant term
|
|
| ModuleArgsTail
|
|
],
|
|
|
|
version_number_term(VersionNumberTerm, Version),
|
|
string_term(SourceFileTerm, SourceFileName),
|
|
try_parse_sym_name_and_no_args(SourceFileModuleNameTerm,
|
|
SourceFileModuleName),
|
|
|
|
sym_names_term(ParentsTerm, Parents),
|
|
sym_names_term(IntDepsTerm, IntDeps),
|
|
sym_names_term(ImpDepsTerm, ImpDeps),
|
|
sym_names_term(ChildrenTerm, Children),
|
|
sym_names_term(NestedSubModulesTerm, NestedSubModules0),
|
|
|
|
braces_term(fact_dep_term, FactDepsTerm, FactDeps),
|
|
braces_term(foreign_language_term, ForeignLanguagesTerm,
|
|
ForeignLanguages),
|
|
braces_term(foreign_import_term, ForeignImportsTerm, ForeignImports),
|
|
|
|
contains_foreign_export_term(ContainsForeignExportTerm,
|
|
ContainsForeignExport),
|
|
|
|
(
|
|
Version = module_dep_file_v1,
|
|
ModuleArgsTail = [],
|
|
ForeignIncludes = []
|
|
;
|
|
Version = module_dep_file_v2,
|
|
ModuleArgsTail = [ForeignIncludesTerm],
|
|
braces_term(foreign_include_term, ForeignIncludesTerm,
|
|
ForeignIncludes)
|
|
),
|
|
|
|
require_det (
|
|
( if ModuleName = SourceFileModuleName then
|
|
MaybeTopModule = top_module(set.list_to_set(NestedSubModules0))
|
|
else
|
|
MaybeTopModule = not_top_module,
|
|
expect(unify(NestedSubModules0, []), $pred,
|
|
"NestedSubModules0 != []")
|
|
),
|
|
set.list_to_set(Parents, ParentsSet),
|
|
AncestorsSet = get_ancestors_set(ModuleName),
|
|
expect(set.equal(ParentsSet, AncestorsSet), $pred,
|
|
"ParentsSet != AncestorsSet"),
|
|
ContainsForeignCode =
|
|
foreign_code_langs_known(set.list_to_set(ForeignLanguages)),
|
|
ModuleSummary = module_dep_summary(SourceFileName, ModuleDir,
|
|
SourceFileModuleName, ModuleName, set.list_to_set(Children),
|
|
MaybeTopModule,
|
|
set.list_to_set(IntDeps), set.list_to_set(ImpDeps),
|
|
set.list_to_set(FactDeps), set.list_to_set(ForeignImports),
|
|
set.list_to_set(ForeignIncludes),
|
|
ContainsForeignCode, ContainsForeignExport)
|
|
).
|
|
|
|
:- pred atom_term(term::in, string::out, list(term)::out) is semidet.
|
|
|
|
atom_term(Term, Atom, Args) :-
|
|
Term = term.functor(term.atom(Atom), Args, _).
|
|
|
|
:- pred version_number_term(term::in, module_dep_file_version::out) is semidet.
|
|
|
|
version_number_term(Term, Version) :-
|
|
term_int.decimal_term_to_int(Term, Int),
|
|
version_number(Version, Int).
|
|
|
|
:- pred string_term(term::in, string::out) is semidet.
|
|
|
|
string_term(Term, String) :-
|
|
Term = term.functor(term.string(String), [], _).
|
|
|
|
:- pred braces_term(pred(term, U), term, list(U)).
|
|
:- mode braces_term(in(pred(in, out) is semidet), in, out) is semidet.
|
|
|
|
braces_term(P, Term, Args) :-
|
|
atom_term(Term, "{}", ArgTerms),
|
|
list.map(P, ArgTerms, Args).
|
|
|
|
:- pred sym_names_term(term::in, list(sym_name)::out) is semidet.
|
|
|
|
sym_names_term(Term, SymNames) :-
|
|
braces_term(try_parse_sym_name_and_no_args, Term, SymNames).
|
|
|
|
:- pred fact_dep_term(term::in, string::out) is semidet.
|
|
|
|
fact_dep_term(Term, FactDep) :-
|
|
string_term(Term, FactDep).
|
|
|
|
:- pred foreign_language_term(term::in, foreign_language::out) is semidet.
|
|
|
|
foreign_language_term(Term, Lang) :-
|
|
string_term(Term, String),
|
|
globals.convert_foreign_language(String, Lang).
|
|
|
|
:- pred foreign_import_term(term::in, fim_spec::out) is semidet.
|
|
|
|
foreign_import_term(Term, FIMSpec) :-
|
|
atom_term(Term, "-", [LanguageTerm, ImportedModuleTerm]),
|
|
foreign_language_term(LanguageTerm, Language),
|
|
try_parse_sym_name_and_no_args(ImportedModuleTerm, ImportedModuleName),
|
|
FIMSpec = fim_spec(Language, ImportedModuleName).
|
|
|
|
:- pred foreign_include_term(term::in, foreign_include_file_info::out)
|
|
is semidet.
|
|
|
|
foreign_include_term(Term, ForeignInclude) :-
|
|
atom_term(Term, "-", [LanguageTerm, FileNameTerm]),
|
|
foreign_language_term(LanguageTerm, Language),
|
|
string_term(FileNameTerm, FileName),
|
|
ForeignInclude = foreign_include_file_info(Language, FileName).
|
|
|
|
:- pred contains_foreign_export_term(term::in, contains_foreign_export::out)
|
|
is semidet.
|
|
|
|
contains_foreign_export_term(Term, ContainsForeignExport) :-
|
|
atom_term(Term, Atom, []),
|
|
contains_foreign_export_to_string(ContainsForeignExport, Atom).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred some_bad_module_dependency(make_info::in, list(module_name)::in)
|
|
is semidet.
|
|
|
|
some_bad_module_dependency(Info, ModuleNames) :-
|
|
list.member(ModuleName, ModuleNames),
|
|
map.search(make_info_get_module_dependencies(Info), ModuleName,
|
|
no_module_dep_info).
|
|
|
|
:- pred check_regular_file_exists(file_name::in, maybe_error::out,
|
|
io::di, io::uo) is det.
|
|
|
|
check_regular_file_exists(FileName, FileExists, !IO) :-
|
|
FollowSymLinks = yes,
|
|
io.file.file_type(FollowSymLinks, FileName, ResFileType, !IO),
|
|
(
|
|
ResFileType = ok(FileType),
|
|
(
|
|
( FileType = regular_file
|
|
; FileType = unknown
|
|
),
|
|
FileExists = ok
|
|
;
|
|
( FileType = directory
|
|
; FileType = symbolic_link
|
|
; FileType = named_pipe
|
|
; FileType = socket
|
|
; FileType = character_device
|
|
; FileType = block_device
|
|
; FileType = message_queue
|
|
; FileType = semaphore
|
|
; FileType = shared_memory
|
|
),
|
|
FileExists = error(FileName ++ ": not a regular file")
|
|
)
|
|
;
|
|
ResFileType = error(Error),
|
|
FileExists = error(FileName ++ ": " ++ io.error_message(Error))
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Something went wrong reading the dependencies, so just rebuild them.
|
|
%
|
|
:- pred read_module_dependencies_remake(globals::in,
|
|
maybe_rebuild_module_deps::in, module_name::in,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
read_module_dependencies_remake(Globals, RebuildModuleDeps, ModuleName,
|
|
!Info, !IO) :-
|
|
(
|
|
RebuildModuleDeps = do_rebuild_module_deps,
|
|
make_module_dependencies(Globals, ModuleName, !Info, !IO)
|
|
;
|
|
RebuildModuleDeps = do_not_rebuild_module_deps
|
|
).
|
|
|
|
:- pred read_module_dependencies_remake_msg(maybe_rebuild_module_deps::in,
|
|
string::in, string::in, string::out) is det.
|
|
|
|
read_module_dependencies_remake_msg(RebuildModuleDeps, ModuleDepsFile,
|
|
ErrorMsg, Msg) :-
|
|
(
|
|
RebuildModuleDeps = do_rebuild_module_deps,
|
|
RebuildSuffix = " ...rebuilding"
|
|
;
|
|
RebuildModuleDeps = do_not_rebuild_module_deps,
|
|
RebuildSuffix = ""
|
|
),
|
|
string.format("** Error reading file `%s': %s%s\n",
|
|
[s(ModuleDepsFile), s(ErrorMsg), s(RebuildSuffix)], Msg).
|
|
|
|
% The module_name given must be the top level module in the source file.
|
|
% get_module_dependencies ensures this by making the dependencies
|
|
% for all parent modules of the requested module first.
|
|
%
|
|
:- pred make_module_dependencies(globals::in, module_name::in,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
make_module_dependencies(Globals, ModuleName, !Info, !IO) :-
|
|
prepare_to_redirect_output(ModuleName, MaybeErrorStream, !Info, !IO),
|
|
(
|
|
MaybeErrorStream = yes(ErrorStream),
|
|
% Both make_module_dependencies_fatal_error and
|
|
% make_module_dependencies_no_fatal_error call unredirect_output,
|
|
% but factoring that call out of the latter would be non-trivial,
|
|
% and is better left for when we replace the whole redirect/unredirect
|
|
% machinery with the use of explicit streams.
|
|
io.set_output_stream(ErrorStream, OldOutputStream, !IO),
|
|
% XXX Why ask for the timestamp if we then ignore it?
|
|
% NOTE: Asking for a timestamp and then ignoring it *could* make sense
|
|
% if we recorded HaveReadSrc in a have_read_module_map, because
|
|
% it would make the timestamp available for a later lookup,
|
|
% However, we do not record HaveReadSrc in a have_read_module_map.
|
|
MaybeProgressStream = maybe.no,
|
|
read_module_src(MaybeProgressStream, Globals, rrm_get_deps(ModuleName),
|
|
do_not_ignore_errors, do_not_search, ModuleName, [],
|
|
always_read_module(do_return_timestamp), HaveReadSrc, !IO),
|
|
(
|
|
HaveReadSrc = have_read_module(SourceFileName, _MaybeTimestamp,
|
|
ParseTreeSrc, ReadModuleErrors),
|
|
FatalErrorSpecs0 = ReadModuleErrors ^ rm_fatal_error_specs,
|
|
NonFatalErrorSpecs0 = ReadModuleErrors ^ rm_nonfatal_error_specs,
|
|
write_error_specs(ErrorStream, Globals,
|
|
FatalErrorSpecs0 ++ NonFatalErrorSpecs0, !IO),
|
|
|
|
Fatal = ReadModuleErrors ^ rm_fatal_errors,
|
|
NonFatal = ReadModuleErrors ^ rm_nonfatal_errors,
|
|
( if set.is_non_empty(Fatal) then
|
|
DisplayErrorReadingFile = yes,
|
|
make_module_dependencies_fatal_error(Globals,
|
|
OldOutputStream, ErrorStream, SourceFileName, ModuleName,
|
|
ReadModuleErrors, DisplayErrorReadingFile, !Info, !IO)
|
|
else if set.contains(NonFatal, rme_unexpected_module_name) then
|
|
% If the source file does not contain the expected module, then
|
|
% do not make the .module_dep file; it would leave a
|
|
% .module_dep file for the wrong module lying around,
|
|
% which the user needs to delete manually.
|
|
DisplayErrorReadingFile = no,
|
|
make_module_dependencies_fatal_error(Globals,
|
|
OldOutputStream, ErrorStream, SourceFileName, ModuleName,
|
|
ReadModuleErrors, DisplayErrorReadingFile, !Info, !IO)
|
|
else
|
|
make_module_dependencies_no_fatal_error(Globals,
|
|
OldOutputStream, ErrorStream, SourceFileName, ModuleName,
|
|
ParseTreeSrc, ReadModuleErrors, !Info, !IO)
|
|
)
|
|
;
|
|
HaveReadSrc = have_not_read_module(SourceFileName,
|
|
ReadModuleErrors),
|
|
FatalErrorSpecs0 = ReadModuleErrors ^ rm_fatal_error_specs,
|
|
NonFatalErrorSpecs0 = ReadModuleErrors ^ rm_nonfatal_error_specs,
|
|
write_error_specs(ErrorStream, Globals,
|
|
FatalErrorSpecs0 ++ NonFatalErrorSpecs0, !IO),
|
|
|
|
DisplayErrorReadingFile = yes,
|
|
make_module_dependencies_fatal_error(Globals,
|
|
OldOutputStream, ErrorStream, SourceFileName, ModuleName,
|
|
ReadModuleErrors, DisplayErrorReadingFile, !Info, !IO)
|
|
)
|
|
;
|
|
MaybeErrorStream = no
|
|
).
|
|
|
|
:- pred make_module_dependencies_fatal_error(globals::in,
|
|
io.text_output_stream::in, io.text_output_stream::in,
|
|
file_name::in, module_name::in, read_module_errors::in, bool::in,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
make_module_dependencies_fatal_error(Globals, OldOutputStream, ErrorStream,
|
|
SourceFileName, ModuleName, ReadModuleErrors, DisplayErrorReadingFile,
|
|
!Info, !IO) :-
|
|
Specs0 = get_read_module_specs(ReadModuleErrors),
|
|
write_error_specs(ErrorStream, Globals, Specs0, !IO),
|
|
io.set_output_stream(OldOutputStream, _, !IO),
|
|
(
|
|
DisplayErrorReadingFile = yes,
|
|
io.format("** Error reading file `%s' to generate dependencies.\n",
|
|
[s(SourceFileName)], !IO),
|
|
maybe_write_importing_module(ModuleName,
|
|
make_info_get_importing_module(!.Info), !IO)
|
|
;
|
|
DisplayErrorReadingFile = no
|
|
),
|
|
|
|
% Display the contents of the `.err' file, then remove it
|
|
% so we don't leave `.err' files lying around for nonexistent modules.
|
|
globals.set_option(output_compile_error_lines, maybe_int(no),
|
|
Globals, UnredirectGlobals),
|
|
unredirect_output(UnredirectGlobals, ModuleName, ErrorStream, !Info, !IO),
|
|
module_name_to_file_name(Globals, $pred, ext_cur(ext_cur_user_err),
|
|
ModuleName, ErrFileName),
|
|
io.file.remove_file(ErrFileName, _, !IO),
|
|
|
|
ModuleDepMap0 = make_info_get_module_dependencies(!.Info),
|
|
% XXX Could this be map.det_update?
|
|
map.set(ModuleName, no_module_dep_info, ModuleDepMap0, ModuleDepMap),
|
|
make_info_set_module_dependencies(ModuleDepMap, !Info).
|
|
|
|
:- pred make_module_dependencies_no_fatal_error(globals::in,
|
|
io.text_output_stream::in, io.text_output_stream::in,
|
|
file_name::in, module_name::in, parse_tree_src::in,
|
|
read_module_errors::in,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
make_module_dependencies_no_fatal_error(Globals, OldOutputStream, ErrorStream,
|
|
SourceFileName, ModuleName, ParseTreeSrc, ReadModuleErrors,
|
|
!Info, !IO) :-
|
|
parse_tree_src_to_burdened_module_list(Globals, SourceFileName,
|
|
ParseTreeSrc, ReadModuleErrors, Specs, BurdenedModules),
|
|
ParseTreeModuleSrcs = list.map((func(burdened_module(_, PTMS)) = PTMS),
|
|
BurdenedModules),
|
|
SubModuleNames = list.map(parse_tree_module_src_project_name,
|
|
ParseTreeModuleSrcs),
|
|
|
|
% io.set_output_stream(ErrorStream, _, !IO),
|
|
% XXX Why are we ignoring all previously reported errors?
|
|
io.set_exit_status(0, !IO),
|
|
write_error_specs(ErrorStream, Globals, Specs, !IO),
|
|
% XXX MAKE_STREAM
|
|
% XXX Now that we pass ErrorStream to write_error_specs instead of
|
|
% setting the output stream to ErrorStream, this may now be redundant.
|
|
io.set_output_stream(OldOutputStream, _, !IO),
|
|
|
|
list.foldl(make_info_add_module_and_imports_as_dep,
|
|
BurdenedModules, !Info),
|
|
|
|
MadeTarget = target_file(ModuleName, module_target_int3),
|
|
get_make_target_file_name(Globals, $pred,
|
|
MadeTarget, MadeTargetFileName, !IO),
|
|
|
|
% If there were no errors, write out the `.int3' file
|
|
% while we have the contents of the module. The `int3' file
|
|
% does not depend on anything else.
|
|
globals.lookup_bool_option(Globals, very_verbose, VeryVerbose),
|
|
% We already know FatalReadError is empty.
|
|
NonFatalErrors = ReadModuleErrors ^ rm_nonfatal_errors,
|
|
( if set.is_empty(NonFatalErrors) then
|
|
maybe_making_filename_msg(Globals, MadeTargetFileName, MakingMsg),
|
|
maybe_write_msg(OldOutputStream, MakingMsg, !IO),
|
|
setup_checking_for_interrupt(CookieMSI, !IO),
|
|
|
|
globals.get_default_options(Globals, DefaultOptionTable),
|
|
DetectedGradeFlags = make_info_get_detected_grade_flags(!.Info),
|
|
OptionVariables = make_info_get_options_variables(!.Info),
|
|
OptionArgs = make_info_get_option_args(!.Info),
|
|
ExtraOptions = ["--make-short-interface"],
|
|
setup_for_build_with_module_options(DefaultOptionTable,
|
|
invoked_by_mmc_make, ModuleName, DetectedGradeFlags,
|
|
OptionVariables, OptionArgs, ExtraOptions, MayBuild, !IO),
|
|
(
|
|
MayBuild = may_not_build(MSISpecs),
|
|
write_error_specs(ErrorStream, Globals, MSISpecs, !IO),
|
|
Succeeded0 = did_not_succeed
|
|
;
|
|
MayBuild = may_build(_AllOptions, BuildGlobals),
|
|
% Printing progress to the current output stream
|
|
% preserves old behavior.
|
|
% XXX MAKE_STREAM
|
|
% XXX Our caller should pass us ProgressStream.
|
|
io.output_stream(ProgressStream, !IO),
|
|
make_int3_files(ProgressStream, ErrorStream, BuildGlobals,
|
|
ParseTreeModuleSrcs, Succeeded0, !Info, !IO)
|
|
),
|
|
|
|
CleanupMSI = cleanup_int3_files(Globals, SubModuleNames),
|
|
teardown_checking_for_interrupt(VeryVerbose, CookieMSI,
|
|
CleanupMSI, Succeeded0, Succeeded, !Info, !IO)
|
|
else
|
|
Succeeded = did_not_succeed
|
|
),
|
|
|
|
setup_checking_for_interrupt(CookieWMDF, !IO),
|
|
list.foldl(do_write_module_dep_file(Globals), BurdenedModules, !IO),
|
|
CleanupWMDF = cleanup_module_dep_files(Globals, SubModuleNames),
|
|
teardown_checking_for_interrupt(VeryVerbose, CookieWMDF,
|
|
CleanupWMDF, succeeded, _Succeeded, !Info, !IO),
|
|
|
|
record_made_target(Globals, MadeTarget, MadeTargetFileName,
|
|
process_module(task_make_int3), Succeeded, !Info, !IO),
|
|
unredirect_output(Globals, ModuleName, ErrorStream, !Info, !IO).
|
|
|
|
:- pred make_info_add_module_and_imports_as_dep(burdened_module::in,
|
|
make_info::in, make_info::out) is det.
|
|
|
|
make_info_add_module_and_imports_as_dep(BurdenedModule, !Info) :-
|
|
ParseTreeModuleSrc = BurdenedModule ^ bm_module,
|
|
ModuleName = ParseTreeModuleSrc ^ ptms_module_name,
|
|
ModuleDepInfo = module_dep_info_full(BurdenedModule),
|
|
MaybeModuleDepInfo = some_module_dep_info(ModuleDepInfo),
|
|
ModuleDepMap0 = make_info_get_module_dependencies(!.Info),
|
|
% XXX Could this be map.det_insert?
|
|
map.set(ModuleName, MaybeModuleDepInfo, ModuleDepMap0, ModuleDepMap),
|
|
make_info_set_module_dependencies(ModuleDepMap, !Info).
|
|
|
|
:- pred make_int3_files(io.text_output_stream::in, io.text_output_stream::in,
|
|
globals::in, list(parse_tree_module_src)::in, maybe_succeeded::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
make_int3_files(ProgressStream, ErrorStream, Globals,
|
|
ParseTreeModuleSrcs, Succeeded, !Info, !IO) :-
|
|
list.map_foldl(
|
|
write_short_interface_file_int3(ProgressStream, ErrorStream, Globals),
|
|
ParseTreeModuleSrcs, Succeededs, !IO),
|
|
Succeeded = and_list(Succeededs).
|
|
|
|
:- pred cleanup_int3_files(globals::in, list(module_name)::in,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
cleanup_int3_files(Globals, ModuleNames, !Info, !IO) :-
|
|
list.foldl2(cleanup_int3_file(Globals), ModuleNames, !Info, !IO).
|
|
|
|
:- pred cleanup_int3_file(globals::in, module_name::in,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
cleanup_int3_file(Globals, ModuleName, !Info, !IO) :-
|
|
remove_make_target_file_by_name(Globals, $pred, very_verbose,
|
|
ModuleName, module_target_int3, !Info, !IO).
|
|
|
|
:- pred cleanup_module_dep_files(globals::in, list(module_name)::in,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
cleanup_module_dep_files(Globals, ModuleNames, !Info, !IO) :-
|
|
list.foldl2(cleanup_module_dep_file(Globals), ModuleNames, !Info, !IO).
|
|
|
|
:- pred cleanup_module_dep_file(globals::in, module_name::in,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
cleanup_module_dep_file(Globals, ModuleName, !Info, !IO) :-
|
|
remove_make_module_file(Globals, verbose_make, ModuleName,
|
|
ext_misc_ngs(ext_misc_ngs_module_dep), !Info, !IO).
|
|
|
|
:- pred maybe_write_importing_module(module_name::in,
|
|
maybe(import_or_include)::in, io::di, io::uo) is det.
|
|
|
|
maybe_write_importing_module(_, no, !IO).
|
|
maybe_write_importing_module(ModuleName, yes(ImportOrInclude), !IO) :-
|
|
(
|
|
ImportOrInclude = ioi_import(ImportingModuleName),
|
|
io.format("** Module `%s' is imported by module `%s'.\n",
|
|
[s(escaped_sym_name_to_string(ModuleName)),
|
|
s(escaped_sym_name_to_string(ImportingModuleName))], !IO)
|
|
;
|
|
ImportOrInclude = ioi_include(IncludingModuleName),
|
|
io.format("** Module `%s' is included by module `%s'.\n",
|
|
[s(escaped_sym_name_to_string(ModuleName)),
|
|
s(escaped_sym_name_to_string(IncludingModuleName))], !IO)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module make.module_dep_file.
|
|
%---------------------------------------------------------------------------%
|