Files
mercury/compiler/make.get_module_dep_info.m
Zoltan Somogyi 7ebb01cf12 Pass some related data structures together ...
... because they are almost always passed together, and grouping them
makes this clear. Also, code with shorter argument lists is more readable.

compiler/options_file.m:
    Define the types of the collective structures. Defined them here
    because one of them is defined here, and all the others are
    lists of strings.

compiler/make.make_info.m:
    Store one of its collective structures instead of its components.

compiler/make.build.m:
compiler/make.get_module_dep_info.m:
compiler/make.library_install.m:
compiler/make.module_target.m:
compiler/make.program_target.m:
compiler/make.top_level.m:
compiler/make.track_flags.m:
compiler/mercury_compile_args.m:
compiler/mercury_compile_main.m:
    Conform to the changes above.
2025-12-13 09:56:08 +11:00

749 lines
33 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, 2023-2025 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.get_module_dep_info.m.
% Author: stayl.
%
% Code to find module_dep_infos, either by reading `<module>.module_dep'
% files, or by reading a module's source file and creating that file.
%
%---------------------------------------------------------------------------%
:- module make.get_module_dep_info.
:- interface.
:- import_module libs.
:- import_module libs.globals.
:- import_module make.make_info.
:- import_module mdbcomp.
:- import_module mdbcomp.sym_name.
:- import_module io.
%---------------------------------------------------------------------------%
% Get the module_dep_info for a given module.
%
% The information in that data structure is generated on demand,
% not by a `mmc --make depend' command, so this predicate may need
% to read the source for the module.
%
:- pred get_maybe_module_dep_info(io.text_output_stream::in, globals::in,
module_name::in, maybe_module_dep_info::out,
make_info::in, make_info::out, 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_dep_file.
:- import_module make.module_target.
:- import_module make.options_file.
:- import_module make.timestamp.
:- import_module make.util.
:- import_module parse_tree.
:- import_module parse_tree.comp_unit_interface.
:- import_module parse_tree.file_names.
:- import_module parse_tree.find_module.
:- import_module parse_tree.item_util.
:- import_module parse_tree.maybe_error.
:- import_module parse_tree.module_baggage.
:- import_module parse_tree.module_dep_info.
:- import_module parse_tree.parse_error.
:- 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.prog_parse_tree.
:- 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 set.
:- import_module string.
%---------------------------------------------------------------------------%
get_maybe_module_dep_info(ProgressStream, Globals, ModuleName,
MaybeModuleDepInfo, !Info, !IO) :-
RebuildModuleDeps = make_info_get_rebuild_module_deps(!.Info),
(
ModuleName = unqualified(_),
maybe_get_maybe_module_dep_info(ProgressStream, Globals,
RebuildModuleDeps, ModuleName, MaybeModuleDepInfo, !Info, !IO)
;
ModuleName = qualified(_, _),
% For submodules, we need to generate the dependencies for the
% parent modules first (try_to_write_module_dep_files_for_top_module
% 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_record_modules_maybe_module_dep_infos(ProgressStream, Globals,
RebuildModuleDeps, AncestorsAndSelf, Error0, !Info, !IO),
ModuleDepMap = make_info_get_maybe_module_dep_info_map(!.Info),
map.lookup(ModuleDepMap, ModuleName, MaybeModuleDepInfo)
).
:- pred maybe_record_modules_maybe_module_dep_infos(io.text_output_stream::in,
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_record_modules_maybe_module_dep_infos(_, _, _, [], _, !Info, !IO).
maybe_record_modules_maybe_module_dep_infos(ProgressStream, Globals,
RebuildModuleDeps, [ModuleName | ModuleNames], !.Error, !Info, !IO) :-
(
!.Error = no,
maybe_get_maybe_module_dep_info(ProgressStream, 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_maybe_module_dep_info_map(!.Info),
% XXX Could this be map.det_update or map.det_insert?
map.set(ModuleName, no_module_dep_info, ModuleDepMap0, ModuleDepMap),
make_info_set_maybe_module_dep_info_map(ModuleDepMap, !Info)
),
maybe_record_modules_maybe_module_dep_infos(ProgressStream, Globals,
RebuildModuleDeps, ModuleNames, !.Error, !Info, !IO).
:- pred maybe_get_maybe_module_dep_info(io.text_output_stream::in, 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_maybe_module_dep_info(ProgressStream, Globals, RebuildModuleDeps,
ModuleName, MaybeModuleDepInfo, !Info, !IO) :-
ModuleDepMap0 = make_info_get_maybe_module_dep_info_map(!.Info),
( if map.search(ModuleDepMap0, ModuleName, MaybeModuleDepInfo0) then
MaybeModuleDepInfo = MaybeModuleDepInfo0
else
do_get_maybe_module_dep_info(ProgressStream, Globals,
RebuildModuleDeps, ModuleName, MaybeModuleDepInfo, !Info, !IO)
).
:- pred do_get_maybe_module_dep_info(io.text_output_stream::in, 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_maybe_module_dep_info(ProgressStream, Globals, RebuildModuleDeps,
ModuleName, !:MaybeModuleDepInfo, !Info, !IO) :-
ModuleDepExt = ext_cur_ngs(ext_cur_ngs_misc_module_dep),
% XXX LEGACY
module_name_to_file_name(Globals, $pred, ModuleDepExt,
ModuleName, DepFileName, _DepFileNameProposed),
SearchAuthDirs = get_search_auth_interface_dirs(ife_module_dep, Globals),
get_file_timestamp(SearchAuthDirs, DepFileName,
SearchDirs, MaybeDepFileTimestamp, !Info, !IO),
(
MaybeDepFileTimestamp = ok(DepFileTimestamp),
% We can't just use
% `get_target_timestamp(ModuleName - source, ..)'
% because that could recursively call get_maybe_module_dep_info,
% 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(search_auth_cur_dir, SourceFileName,
_SearchDirs, MaybeSourceFileTimestamp, !Info, !IO),
(
MaybeSourceFileTimestamp = ok(SourceFileTimestamp),
( 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.
find_and_read_module_dep_file(ProgressStream, Globals,
RebuildModuleDeps, search_cur_dir, ModuleName,
!Info, !IO)
else
try_to_write_module_dep_files_for_top_module(ProgressStream,
Globals, ModuleName, !Info, !IO)
)
;
MaybeSourceFileTimestamp = error(_),
find_and_read_module_dep_file(ProgressStream, Globals,
RebuildModuleDeps, search_interface_dirs, 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).
% (XXX I (zs) do not see how this code does that.)
% 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_maybe_module_dep_info_map(!.Info),
ModuleName, !:MaybeModuleDepInfo),
( if
!.MaybeModuleDepInfo = some_module_dep_info(ModuleDepInfo0),
module_dep_info_get_source_file_dir(ModuleDepInfo0,
DepFileDir),
DepFileDir = dir.this_directory
then
module_dep_info_get_source_file_name(ModuleDepInfo0,
SourceFileName1),
get_file_timestamp(search_auth_cur_dir, SourceFileName1,
_SearchCurDirs1, 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
% mercury_term_lexer module
% 2. copy the standard library mercury_term_lexer.m
% file to the current directory for editing
% 3. run mmc --make; it creates
% mercury_term_lexer.module_dep
% 4. change mercury_term_lexer.m into a submodule
% of prog
% 5. run mmc --make again, it no longer works
%
% The local mercury_term_lexer.module_dep prevents
% mmc --make finding the mercury_term_lexer.module_dep
% from the standard library, even though there is
% no longer any local source file for the
% `mercury_term_lexer' module.
try_to_write_module_dep_files_for_top_module(
ProgressStream, Globals, ModuleName, !Info, !IO)
)
;
MaybeSourceFileTimestamp1 = error(Message),
io.format(ProgressStream,
"** Error reading file `%s' " ++
"to generate dependencies: %s.\n",
[s(SourceFileName1), s(Message)], !IO),
maybe_write_importing_module(ProgressStream, 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),
maybe_write_msg(ProgressStream, 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,
try_to_write_module_dep_files_for_top_module(ProgressStream,
Globals, ModuleName, !Info, !IO)
;
RebuildModuleDeps = do_not_rebuild_module_deps,
ModuleDepMap0 = make_info_get_maybe_module_dep_info_map(!.Info),
% XXX Could this be map.det_update or map.det_insert?
map.set(ModuleName, no_module_dep_info,
ModuleDepMap0, ModuleDepMap1),
make_info_set_maybe_module_dep_info_map(ModuleDepMap1, !Info)
)
),
ModuleDepMap2 = make_info_get_maybe_module_dep_info_map(!.Info),
map.search_insert(ModuleName, no_module_dep_info,
MaybeOldMaybeModuleDepInfo, ModuleDepMap2, ModuleDepMap),
(
MaybeOldMaybeModuleDepInfo = yes(OldMaybeModuleDepInfo),
!:MaybeModuleDepInfo = OldMaybeModuleDepInfo
;
MaybeOldMaybeModuleDepInfo = no,
!:MaybeModuleDepInfo = no_module_dep_info,
make_info_set_maybe_module_dep_info_map(ModuleDepMap, !Info)
).
%---------------------------------------------------------------------------%
:- pred find_and_read_module_dep_file(io.text_output_stream::in, globals::in,
maybe_rebuild_module_deps::in,
search_which_dirs::in(search_cur_or_interface),
module_name::in, make_info::in, make_info::out, io::di, io::uo) is det.
find_and_read_module_dep_file(ProgressStream, Globals, RebuildModuleDeps,
SearchWhichDirs, ModuleName, !Info, !IO) :-
ExtDep = ext_cur_ngs(ext_cur_ngs_misc_module_dep),
% XXX LEGACY
module_name_to_search_file_name(Globals, $pred, ExtDep, ModuleName,
SearchWhichDirs, SearchAuthDirs, DepFileName, _DepFileNameProposed),
search_for_file_returning_dir_and_contents(SearchAuthDirs,
DepFileName, _SearchDirs, MaybeDirAndContents, !IO),
(
MaybeDirAndContents = ok(DirAndContents),
DirAndContents = dir_name_and_contents(DepFileDir, DepFileContents),
read_module_dep_file(DepFileDir, DepFileName, DepFileContents,
ModuleName, ParseResult),
(
ParseResult = ok1(ModuleSummary),
handle_parsed_module_dep_file(ProgressStream, Globals,
SearchWhichDirs, ModuleName, DepFileDir, DepFileName,
ModuleSummary, Result, !Info, !IO)
;
ParseResult = error1(ParseErrorMsg),
Result = error(ParseErrorMsg)
),
(
Result = ok
;
Result = error(ErrorMsg),
error_and_maybe_rebuilding_msg(RebuildModuleDeps,
DepFileDir ++ "/" ++ DepFileName, ErrorMsg, Msg),
% XXX MAKE_STREAM
io.write_string(ProgressStream, Msg, !IO),
(
RebuildModuleDeps = do_rebuild_module_deps,
try_to_write_module_dep_files_for_top_module(ProgressStream,
Globals, ModuleName, !Info, !IO)
;
RebuildModuleDeps = do_not_rebuild_module_deps
)
)
;
MaybeDirAndContents = error(ErrorMsg),
% XXX Why is this invocation of error_and_maybe_rebuilding_msg
% more conditional than the one above?
debug_make_msg(Globals,
error_and_maybe_rebuilding_msg(RebuildModuleDeps,
DepFileName, ErrorMsg),
DebugMsg),
maybe_write_msg(ProgressStream, DebugMsg, !IO),
(
RebuildModuleDeps = do_rebuild_module_deps,
try_to_write_module_dep_files_for_top_module(ProgressStream,
Globals, ModuleName, !Info, !IO)
;
RebuildModuleDeps = do_not_rebuild_module_deps
)
).
:- pred handle_parsed_module_dep_file(io.text_output_stream::in, globals::in,
search_which_dirs::in(search_cur_or_interface),
module_name::in, dir_name::in, file_name::in, module_dep_summary::in,
maybe_error::out, make_info::in, make_info::out, io::di, io::uo) is det.
handle_parsed_module_dep_file(ProgressStream, Globals, SearchWhichDirs,
ModuleName, DepFileDir, DepFileName, ModuleSummary, Result,
!Info, !IO) :-
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 DepFileDir = 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(DepFileName, _, !IO)
)
else
SourceFileExists = ok
),
(
SourceFileExists = ok,
ModuleDepMap0 = make_info_get_maybe_module_dep_info_map(!.Info),
% XXX Could this be map.det_insert?
map.set(ModuleName, MaybeModuleDepInfo, ModuleDepMap0, ModuleDepMap),
make_info_set_maybe_module_dep_info_map(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
% (try_to_write_module_dep_files_for_top_module 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(
find_and_read_module_dep_file(ProgressStream, Globals,
do_not_rebuild_module_deps, SearchWhichDirs),
NestedSubModules, !Info, !IO),
( if some_module_has_dep_info(!.Info, NestedSubModules) then
Result = error("error in nested submodules")
else
Result = ok
)
;
SourceFileExists = error(Error),
Result = error(Error)
).
%---------------------------------------------------------------------------%
:- 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))
).
:- pred some_module_has_dep_info(make_info::in, list(module_name)::in)
is semidet.
some_module_has_dep_info(Info, ModuleNames) :-
some [ModuleName] (
list.member(ModuleName, ModuleNames),
map.search(make_info_get_maybe_module_dep_info_map(Info),
ModuleName, MaybeModuleDepInfo),
MaybeModuleDepInfo = no_module_dep_info
).
%---------------------------------------------------------------------------%
:- pred error_and_maybe_rebuilding_msg(maybe_rebuild_module_deps::in,
string::in, string::in, string::out) is det.
error_and_maybe_rebuilding_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_maybe_module_dep_info ensures this by making the dependencies
% for all ancestor modules of the requested module first.
% XXX But even though get_maybe_module_dep_info calls
% maybe_record_modules_maybe_module_dep_infos with a module list
% in which, for every parent/child pair, the parent is listed first,
% maybe_record_modules_maybe_module_dep_infos *does* eventually process
% the children later as well, and that processing may include a call
% to this predicate. I (zs) see no correctness argument for guaranteeing
% the absence of such calls.
%
:- pred try_to_write_module_dep_files_for_top_module(io.text_output_stream::in,
globals::in, module_name::in,
make_info::in, make_info::out, io::di, io::uo) is det.
try_to_write_module_dep_files_for_top_module(ProgressStream, Globals,
ModuleName, !Info, !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_parse_tree_map, because
% it would make the timestamp available for a later lookup,
% However, we do not record HaveReadSrc in a have_parse_tree_map.
read_module_src(ProgressStream, Globals, rrm_get_deps,
do_not_search, ModuleName, [],
always_read_module(do_return_timestamp), HaveReadSrc, !IO),
(
HaveReadSrc = have_module(SourceFileName, ParseTreeSrc, Source),
Source = was_read(MaybeTimestamp, ReadModuleErrors),
Fatal = ReadModuleErrors ^ rm_fatal_errors,
NonFatal = ReadModuleErrors ^ rm_nonfatal_errors,
( if set.is_non_empty(Fatal) then
report_cannot_read_src_to_generate_module_dep(ProgressStream,
SourceFileName, ModuleName, !.Info, !IO),
cannot_write_module_dep_files(Globals, ProgressStream,
ModuleName, ReadModuleErrors, !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 would need to delete manually.
cannot_write_module_dep_files(Globals, ProgressStream,
ModuleName, ReadModuleErrors, !Info, !IO)
else
open_module_error_stream(ProgressStream, Globals, !.Info,
ModuleName, MaybeErrorStream, !IO),
(
MaybeErrorStream = es_ok(MESI, ErrorStream),
write_module_dep_files_for_source_file(Globals,
ProgressStream, MESI, ErrorStream, SourceFileName,
ModuleName, ReadModuleErrors, MaybeTimestamp,
ParseTreeSrc, !Info, !IO)
;
MaybeErrorStream = es_error_already_reported
)
)
;
HaveReadSrc = have_not_read_module(SourceFileName,
ReadModuleErrors0),
report_cannot_read_src_to_generate_module_dep(ProgressStream,
SourceFileName, ModuleName, !.Info, !IO),
% I (zs) do not understand why we ignore warning specs, since
% there shouldn't be any if we couldn't read the module.
% It is probably a hangover from the days before we separated out
% warnings from errors, but without some test cases targeting
% this kind of error, I cannot know for certain that removing
% the next line does not have any effect.
ReadModuleErrors = ReadModuleErrors0 ^ rm_warning_specs := [],
cannot_write_module_dep_files(Globals, ProgressStream,
ModuleName, ReadModuleErrors, !Info, !IO)
).
:- pred report_cannot_read_src_to_generate_module_dep(
io.text_output_stream::in, file_name::in, module_name::in,
make_info::in, io::di, io::uo) is det.
report_cannot_read_src_to_generate_module_dep(ProgressStream, SourceFileName,
ModuleName, Info, !IO) :-
io.format(ProgressStream,
"** Error reading file `%s' to generate dependencies.\n",
[s(SourceFileName)], !IO),
maybe_write_importing_module(ProgressStream, ModuleName,
make_info_get_importing_module(Info), !IO).
:- pred cannot_write_module_dep_files(globals::in, io.text_output_stream::in,
module_name::in, read_module_errors::in,
make_info::in, make_info::out, io::di, io::uo) is det.
cannot_write_module_dep_files(Globals, ProgressStream, ModuleName,
ReadModuleErrors, !Info, !IO) :-
Specs0 = get_read_module_specs(ReadModuleErrors),
% XXX ProgressStream may not be stdout.
with_locked_stdout(!.Info,
write_error_specs(ProgressStream, Globals, Specs0),
!IO),
ModuleDepMap0 = make_info_get_maybe_module_dep_info_map(!.Info),
% XXX Could this be map.det_update?
map.set(ModuleName, no_module_dep_info, ModuleDepMap0, ModuleDepMap),
make_info_set_maybe_module_dep_info_map(ModuleDepMap, !Info).
:- pred write_module_dep_files_for_source_file(globals::in,
io.text_output_stream::in,
module_error_stream_info::in, io.text_output_stream::in,
file_name::in, module_name::in, read_module_errors::in,
maybe(timestamp)::in, parse_tree_src::in,
make_info::in, make_info::out, io::di, io::uo) is det.
write_module_dep_files_for_source_file(Globals, ProgressStream,
MESI, ErrorStream, SourceFileName, ModuleName, ReadModuleErrors,
MaybeTimestamp, ParseTreeSrc, !Info, !IO) :-
parse_tree_src_to_burdened_module_list(Globals, SourceFileName,
ReadModuleErrors, MaybeTimestamp, ParseTreeSrc,
Specs, BurdenedModules),
ParseTreeModuleSrcs = list.map((func(burdened_module(_, PTMS)) = PTMS),
BurdenedModules),
SubModuleNames = list.map(parse_tree_module_src_project_name,
ParseTreeModuleSrcs),
% XXX Why are we ignoring all previously reported errors?
io.set_exit_status(0, !IO),
write_error_specs(ErrorStream, Globals, Specs, !IO),
list.foldl(make_info_add_burdened_module_as_dep, BurdenedModules, !Info),
% 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.
MadeTarget = target_file(ModuleName, module_target_int3),
% XXX LEGACY
module_target_file_to_file_name(Globals, $pred,
MadeTarget, MadeTargetFileName, _MadeTargetFileNameProposed, !IO),
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(ProgressStream, MakingMsg, !IO),
setup_checking_for_interrupt(CookieMSI, !IO),
globals.get_default_options(Globals, DefaultOptionTable),
MaybeStdLibGrades = make_info_get_maybe_stdlib_grades(!.Info),
Params = make_info_get_compiler_params(!.Info),
ExtraOptions = ["--make-short-interface"],
setup_for_build_with_module_options(ProgressStream, DefaultOptionTable,
MaybeStdLibGrades, invoked_by_mmc_make, ModuleName,
Params, ExtraOptions, MayBuild, !IO),
(
MayBuild = may_not_build(MSISpecs),
% XXX MAKE_STREAM
write_error_specs(ErrorStream, Globals, MSISpecs, !IO),
Succeeded0 = did_not_succeed
;
MayBuild = may_build(_AllOptions, BuildGlobals),
make_int3_files(ProgressStream, ErrorStream, BuildGlobals,
BurdenedModules, Succeeded0, !IO)
),
CleanupMSI =
cleanup_int3_files(ProgressStream, 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(ProgressStream, Globals),
BurdenedModules, !IO),
CleanupWMDF =
cleanup_module_dep_files(ProgressStream, Globals, SubModuleNames),
teardown_checking_for_interrupt(VeryVerbose, CookieWMDF,
CleanupWMDF, succeeded, _Succeeded, !Info, !IO),
record_made_target(ProgressStream, Globals, MadeTarget, MadeTargetFileName,
process_module(task_make_int3), Succeeded, !Info, !IO),
close_module_error_stream_handle_errors(ProgressStream, Globals,
MESI, ErrorStream, !.Info, !IO).
:- pred make_info_add_burdened_module_as_dep(burdened_module::in,
make_info::in, make_info::out) is det.
make_info_add_burdened_module_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_maybe_module_dep_info_map(!.Info),
% XXX Could this be map.det_insert?
map.set(ModuleName, MaybeModuleDepInfo, ModuleDepMap0, ModuleDepMap),
make_info_set_maybe_module_dep_info_map(ModuleDepMap, !Info).
:- pred make_int3_files(io.text_output_stream::in, io.text_output_stream::in,
globals::in, list(burdened_module)::in, maybe_succeeded::out,
io::di, io::uo) is det.
make_int3_files(ProgressStream, ErrorStream, Globals,
BurdenedModules, Succeeded, !IO) :-
% XXX MAKE We should probably add to, and keep, HaveParseTreeMaps.
list.map2_foldl2(
generate_and_write_interface_file_int3(ProgressStream, Globals,
do_not_add_new_to_hptm),
BurdenedModules, Succeededs, SpecsList,
init_have_parse_tree_maps, _HaveParseTreeMaps, !IO),
list.foldl(write_error_specs(ErrorStream, Globals), SpecsList, !IO),
Succeeded = and_list(Succeededs).
:- pred cleanup_int3_files(io.text_output_stream::in, globals::in,
list(module_name)::in,
make_info::in, make_info::out, io::di, io::uo) is det.
cleanup_int3_files(ProgressStream, Globals, ModuleNames, !Info, !IO) :-
list.foldl2(cleanup_int3_file(ProgressStream, Globals), ModuleNames,
!Info, !IO).
:- pred cleanup_int3_file(io.text_output_stream::in, globals::in,
module_name::in, make_info::in, make_info::out, io::di, io::uo) is det.
cleanup_int3_file(ProgressStream, Globals, ModuleName, !Info, !IO) :-
remove_make_target_file_by_name(ProgressStream, Globals, $pred,
very_verbose, ModuleName, module_target_int3, !Info, !IO).
:- pred cleanup_module_dep_files(io.text_output_stream::in, globals::in,
list(module_name)::in,
make_info::in, make_info::out, io::di, io::uo) is det.
cleanup_module_dep_files(ProgressStream, Globals, ModuleNames, !Info, !IO) :-
list.foldl2(cleanup_module_dep_file(ProgressStream, Globals),
ModuleNames, !Info, !IO).
:- pred cleanup_module_dep_file(io.text_output_stream::in, globals::in,
module_name::in, make_info::in, make_info::out, io::di, io::uo) is det.
cleanup_module_dep_file(ProgressStream, Globals, ModuleName, !Info, !IO) :-
remove_module_file_for_make(ProgressStream, Globals, verbose_make,
ModuleName, ext_cur_ngs(ext_cur_ngs_misc_module_dep), !Info, !IO).
:- pred maybe_write_importing_module(io.text_output_stream::in,
module_name::in, maybe(import_or_include)::in, io::di, io::uo) is det.
maybe_write_importing_module(ProgressStream, ModuleName, MaybeIoI, !IO) :-
(
MaybeIoI = no
;
MaybeIoI = yes(ImportOrInclude),
(
ImportOrInclude = ioi_import(ImportingModuleName),
io.format(ProgressStream,
"** 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(ProgressStream,
"** 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.get_module_dep_info.
%---------------------------------------------------------------------------%