mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-17 10:23:46 +00:00
compiler/make.util.m:
Many operations in this module that operate on filenames did not take
those filenames as arguments; instead, they took an argument such as
a target_file from which they *computed* the filename. This meant that
any predicate that called more than one of these operations implicitly
computed the filename more than once. This could be a problem, because
- there are several predicates one can use to compute the filename, but
- there is no guarantee that different operations use the same predicate.
As a first step in fixing this, change the predicates that print
filenames in progress or error messages to take those filenames
as parameters. Delete one of them, target_file_error, because
after this change, it would have become identical to the existing
file_error predicate.
compiler/make.module_target.m:
Require the callers of record_made_target to supply the filename
as well as the target_file from which it is derived.
compiler/make.dependencies.m:
compiler/make.module_dep_file.m:
compiler/make.program_target.m:
Compute the filename before calling the updated operations in make.util.m
and/or make.module_target.m.
Add "XXX MAKE_STREAM" to places in the code that operate on either
implicit or badly-chosed explicit streams.
1698 lines
68 KiB
Mathematica
1698 lines
68 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 2002-2011 The University of Melbourne.
|
|
% Copyright (C) 2013-2017, 2019-2022 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.dependencies.m.
|
|
% Author: stayl.
|
|
%
|
|
% Code to find the dependencies for a particular target,
|
|
% e.g. module.c depends on module.m, import.int, etc.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module make.dependencies.
|
|
:- interface.
|
|
|
|
:- import_module libs.
|
|
:- import_module libs.file_util.
|
|
:- import_module libs.globals.
|
|
:- import_module libs.maybe_util.
|
|
:- import_module libs.timestamp.
|
|
:- import_module make.deps_set.
|
|
:- import_module make.make_info.
|
|
:- import_module mdbcomp.
|
|
:- import_module mdbcomp.sym_name.
|
|
|
|
:- import_module io.
|
|
:- import_module list.
|
|
:- import_module maybe.
|
|
:- import_module set.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- type dependency_file
|
|
---> dep_target(target_file)
|
|
% A target which could be made.
|
|
|
|
; dep_file(file_name).
|
|
% An ordinary file which `mmc --make' does not know how to rebuild.
|
|
|
|
% Like dependency_file but refers to a module by index instead of by name,
|
|
% which is more efficient when the name is not required.
|
|
%
|
|
:- type dependency_file_with_module_index
|
|
---> dfmi_target(module_index, module_target_type)
|
|
; dfmi_file(file_name).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% find_target_dependencies_of_modules(KeepGoing, Globals, TargetType,
|
|
% ModuleIndexes, !Succeeded, !Deps, !Info, !IO):
|
|
%
|
|
% The TargetType and ModuleIndexes arguments define a set of make targets.
|
|
% Add to !Deps the dependency_file_indexes of all the files that
|
|
% these make targets depend on, and which therefore have to be built
|
|
% before we can build those make targets.
|
|
%
|
|
:- pred find_target_dependencies_of_modules(maybe_keep_going::in, globals::in,
|
|
module_target_type::in, list(module_index)::in,
|
|
maybe_succeeded::in, maybe_succeeded::out,
|
|
deps_set(dependency_file_index)::in, deps_set(dependency_file_index)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Find all modules in the current directory which are reachable
|
|
% (by import or include) from the given module.
|
|
%
|
|
:- pred find_reachable_local_modules(globals::in, module_name::in,
|
|
maybe_succeeded::out, set(module_name)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
% Remove all nested modules from a list of modules.
|
|
%
|
|
:- pred remove_nested_modules(globals::in,
|
|
list(module_name)::in, list(module_name)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Find all modules in the current directory which are reachable (by import)
|
|
% from the given module. Return a list of `--local-module-id' options
|
|
% suitable for the command line.
|
|
%
|
|
:- pred make_local_module_id_options(globals::in, module_name::in,
|
|
maybe_succeeded::out, list(string)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred dependency_status(globals::in, dependency_file::in,
|
|
dependency_status::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- type dependencies_result
|
|
---> deps_up_to_date
|
|
; deps_out_of_date
|
|
; deps_error.
|
|
|
|
% check_dependencies(Globals, TargetFileName, TargetFileTimestamp,
|
|
% BuildDepsSucceeded, Dependencies, Result, !IO)
|
|
%
|
|
% Check that all the dependency targets are up-to-date.
|
|
%
|
|
:- pred check_dependencies(globals::in, file_name::in,
|
|
maybe_error(timestamp)::in, maybe_succeeded::in, list(dependency_file)::in,
|
|
dependencies_result::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
% check_dependencies(Globals, TargetFileName, TargetFileTimestamp,
|
|
% BuildDepsSucceeded, Dependencies, Result, !IO)
|
|
%
|
|
% Check that all the dependency files are up-to-date.
|
|
%
|
|
:- pred check_dependency_timestamps(globals::in, file_name::in,
|
|
maybe_error(timestamp)::in, maybe_succeeded::in, list(File)::in,
|
|
pred(File, string, io, io)::in(pred(in, out, di, uo) is det),
|
|
list(maybe_error(timestamp))::in, dependencies_result::out,
|
|
io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- type cached_direct_imports.
|
|
:- func init_cached_direct_imports = cached_direct_imports.
|
|
|
|
:- type cached_indirect_imports.
|
|
:- func init_cached_indirect_imports = cached_indirect_imports.
|
|
|
|
:- type cached_transitive_foreign_imports.
|
|
:- func init_cached_transitive_foreign_imports =
|
|
cached_transitive_foreign_imports.
|
|
|
|
:- type cached_transitive_dependencies.
|
|
:- func init_cached_transitive_dependencies = cached_transitive_dependencies.
|
|
|
|
:- type cached_computed_module_deps.
|
|
:- func init_cached_computed_module_deps = cached_computed_module_deps.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module backend_libs.
|
|
:- import_module backend_libs.compile_target_code.
|
|
:- import_module libs.options.
|
|
:- import_module make.module_dep_file.
|
|
:- import_module make.util.
|
|
:- import_module parse_tree.
|
|
:- import_module parse_tree.file_names.
|
|
:- import_module parse_tree.module_baggage.
|
|
:- import_module parse_tree.module_dep_info.
|
|
:- import_module parse_tree.prog_data_foreign.
|
|
|
|
:- import_module assoc_list.
|
|
:- import_module bool.
|
|
:- import_module dir.
|
|
:- import_module map.
|
|
:- import_module pair.
|
|
:- import_module require.
|
|
:- import_module sparse_bitset.
|
|
:- import_module string.
|
|
:- import_module version_hash_table.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% find_module_deps(Globals, ModuleIndex, Succeeded, Deps, !Info, !IO).
|
|
%
|
|
% The reason we don't return maybe(Deps) is that with `--keep-going'
|
|
% we want to do as much work as possible.
|
|
%
|
|
:- type find_module_deps(T) ==
|
|
pred(globals, module_index, maybe_succeeded, deps_set(T),
|
|
make_info, make_info, io, io).
|
|
:- inst find_module_deps ==
|
|
(pred(in, in, out, out, in, out, di, uo) is det).
|
|
|
|
:- type find_module_deps_plain_set(T) ==
|
|
pred(globals, module_index, maybe_succeeded, set(T),
|
|
make_info, make_info, io, io).
|
|
:- inst find_module_deps_plain_set ==
|
|
(pred(in, in, out, out, in, out, di, uo) is det).
|
|
|
|
:- type deps_result(T)
|
|
---> deps_result(
|
|
dr_success :: maybe_succeeded,
|
|
dr_set :: deps_set(T)
|
|
).
|
|
|
|
:- type module_deps_result == deps_result(module_index).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
find_target_dependencies_of_modules(_KeepGoing, _Globals, _TargetType,
|
|
[], !Succeeded, !Deps, !Info, !IO).
|
|
find_target_dependencies_of_modules(KeepGoing, Globals, TargetType,
|
|
[ModuleIndex | ModuleIndexes], !Succeeded, !Deps, !Info, !IO) :-
|
|
(
|
|
( TargetType = module_target_source
|
|
; TargetType = module_target_track_flags
|
|
),
|
|
NewSucceeded = succeeded
|
|
;
|
|
TargetType = module_target_int3,
|
|
% module_target_source of self
|
|
add_targets_of_modules_as_deps(module_target_source,
|
|
[ModuleIndex], !Deps, !Info),
|
|
NewSucceeded = succeeded
|
|
;
|
|
( TargetType = module_target_int0
|
|
; TargetType = module_target_int1
|
|
; TargetType = module_target_int2
|
|
),
|
|
FindDeps = interface_file_dependencies,
|
|
FindDeps(Globals, ModuleIndex, NewSucceeded, NewDeps, !Info, !IO),
|
|
union(NewDeps, !Deps)
|
|
;
|
|
( TargetType = module_target_c_code
|
|
; TargetType = module_target_c_header(_)
|
|
; TargetType = module_target_csharp_code
|
|
; TargetType = module_target_java_code
|
|
; TargetType = module_target_errors
|
|
),
|
|
FindDeps = compiled_code_dependencies(Globals),
|
|
FindDeps(Globals, ModuleIndex, NewSucceeded, NewDeps, !Info, !IO),
|
|
union(NewDeps, !Deps)
|
|
;
|
|
TargetType = module_target_java_class_code,
|
|
% module_target_java_code of self
|
|
add_targets_of_modules_as_deps(module_target_java_code,
|
|
[ModuleIndex], !Deps, !Info),
|
|
NewSucceeded = succeeded
|
|
;
|
|
( TargetType = module_target_foreign_object(PIC, _)
|
|
; TargetType = module_target_fact_table_object(PIC, _)
|
|
),
|
|
add_compilation_targets_of_module_as_deps(Globals, PIC, ModuleIndex,
|
|
!Deps, !Info),
|
|
NewSucceeded = succeeded
|
|
;
|
|
TargetType = module_target_object_code(PIC),
|
|
add_compilation_targets_of_module_as_deps(Globals, PIC, ModuleIndex,
|
|
!Deps, !Info),
|
|
globals.get_target(Globals, CompilationTarget),
|
|
globals.lookup_bool_option(Globals, highlevel_code, HighLevelCode),
|
|
% For --highlevel-code, the `.c' file will #include the header file
|
|
% for all imported modules.
|
|
( if
|
|
CompilationTarget = target_c,
|
|
HighLevelCode = yes
|
|
then
|
|
HeaderDeps = combine_deps_list([
|
|
module_target_c_header(header_mih) `of` direct_imports,
|
|
module_target_c_header(header_mih) `of` indirect_imports,
|
|
module_target_c_header(header_mih) `of` ancestors,
|
|
module_target_c_header(header_mih) `of` intermod_imports
|
|
])
|
|
else
|
|
HeaderDeps = no_deps
|
|
),
|
|
FindDeps = combine_deps_list([
|
|
module_target_c_header(header_mh) `of` foreign_imports,
|
|
HeaderDeps
|
|
]),
|
|
FindDeps(Globals, ModuleIndex, NewSucceeded, NewDeps, !Info, !IO),
|
|
union(NewDeps, !Deps)
|
|
;
|
|
( TargetType = module_target_opt
|
|
; TargetType = module_target_xml_doc
|
|
),
|
|
% module_target_java_code of self
|
|
add_targets_of_modules_as_deps(module_target_source, [ModuleIndex],
|
|
!Deps, !Info),
|
|
% module_target_int0 of ancestors
|
|
add_targets_of_ancestors_as_deps(module_target_int0, ModuleIndex,
|
|
!Deps, !Info),
|
|
FindDeps = combine_deps_list([
|
|
module_target_int1 `of` non_intermod_direct_imports,
|
|
module_target_int2 `of` non_intermod_indirect_imports
|
|
]),
|
|
FindDeps(Globals, ModuleIndex, NewSucceeded, NewDeps, !Info, !IO),
|
|
union(NewDeps, !Deps)
|
|
;
|
|
TargetType = module_target_analysis_registry,
|
|
% module_target_java_code of self
|
|
add_targets_of_modules_as_deps(module_target_source, [ModuleIndex],
|
|
!Deps, !Info),
|
|
% module_target_int0 of ancestors
|
|
add_targets_of_ancestors_as_deps(module_target_int0, ModuleIndex,
|
|
!Deps, !Info),
|
|
FindDeps = combine_deps_list([
|
|
module_target_int1 `of` non_intermod_direct_imports,
|
|
module_target_int2 `of` non_intermod_indirect_imports,
|
|
module_target_opt `of` direct_imports,
|
|
module_target_opt `of` indirect_imports,
|
|
module_target_opt `of` intermod_imports
|
|
]),
|
|
FindDeps(Globals, ModuleIndex, NewSucceeded, NewDeps, !Info, !IO),
|
|
union(NewDeps, !Deps)
|
|
),
|
|
( if
|
|
( NewSucceeded = succeeded
|
|
; KeepGoing = do_keep_going
|
|
)
|
|
then
|
|
!:Succeeded = !.Succeeded `and` NewSucceeded,
|
|
find_target_dependencies_of_modules(KeepGoing, Globals, TargetType,
|
|
ModuleIndexes, !Succeeded, !Deps, !Info, !IO)
|
|
else
|
|
!:Succeeded = did_not_succeed
|
|
).
|
|
|
|
:- pred add_compilation_targets_of_module_as_deps(globals::in, pic::in,
|
|
module_index::in,
|
|
deps_set(dependency_file_index)::in, deps_set(dependency_file_index)::out,
|
|
make_info::in, make_info::out) is det.
|
|
|
|
add_compilation_targets_of_module_as_deps(Globals, PIC, ModuleIndex,
|
|
!Deps, !Info) :-
|
|
globals.get_target(Globals, CompilationTarget),
|
|
TargetCode = target_to_module_target_code(CompilationTarget, PIC),
|
|
% TargetCode of self
|
|
add_targets_of_modules_as_deps(TargetCode, [ModuleIndex], !Deps, !Info).
|
|
|
|
:- func target_to_module_target_code(compilation_target, pic)
|
|
= module_target_type.
|
|
|
|
target_to_module_target_code(_CompilationTarget, _PIC) = TargetCode :-
|
|
% XXX it looks wrong to be returning module_target_c_code for
|
|
% all compilation targets.
|
|
TargetCode = module_target_c_code.
|
|
|
|
:- func interface_file_dependencies =
|
|
(find_module_deps(dependency_file_index)::out(find_module_deps)) is det.
|
|
|
|
interface_file_dependencies =
|
|
combine_deps_list([
|
|
module_target_source `of` self,
|
|
module_target_int0 `of` ancestors,
|
|
module_target_int3 `of` direct_imports,
|
|
module_target_int3 `of` indirect_imports
|
|
]).
|
|
|
|
:- func compiled_code_dependencies(globals::in) =
|
|
(find_module_deps(dependency_file_index)::out(find_module_deps)) is det.
|
|
|
|
compiled_code_dependencies(Globals) = Deps :-
|
|
% We build up Deps in stages.
|
|
|
|
% Stage 0: dependencies on flags.
|
|
globals.lookup_bool_option(Globals, track_flags, TrackFlags),
|
|
(
|
|
TrackFlags = yes,
|
|
DepsTracks = [module_target_track_flags `of` self]
|
|
;
|
|
TrackFlags = no,
|
|
DepsTracks = []
|
|
),
|
|
|
|
% Stage 1: dependencies on the source file, and on the fact table files,
|
|
% foreign language files and Mercury interface files it imports.
|
|
DepsSrcInts = [
|
|
module_target_source `of` self,
|
|
fact_table_files `files_of` self,
|
|
foreign_include_files `files_of` self,
|
|
module_target_int1 `of` self,
|
|
module_target_int1 `of` ancestors,
|
|
find_own_imports_012
|
|
],
|
|
|
|
globals.lookup_bool_option(Globals, intermodule_optimization, IntermodOpt),
|
|
globals.lookup_bool_option(Globals, intermodule_analysis,
|
|
IntermodAnalysis),
|
|
AnyIntermod = bool.or(IntermodOpt, IntermodAnalysis),
|
|
|
|
% Stage 2: dependencies on optimization files.
|
|
(
|
|
AnyIntermod = yes,
|
|
DepsOpts = [
|
|
module_target_opt `of` self,
|
|
module_target_opt `of` intermod_imports,
|
|
get_intermod_imports_their_ancestors_and_012
|
|
]
|
|
;
|
|
AnyIntermod = no,
|
|
DepsOpts = []
|
|
),
|
|
|
|
% Stage 3: dependencies on analysis result files.
|
|
(
|
|
IntermodAnalysis = yes,
|
|
DepsRegistries = [
|
|
module_target_analysis_registry `of` self,
|
|
module_target_analysis_registry `of` direct_imports
|
|
]
|
|
;
|
|
IntermodAnalysis = no,
|
|
DepsRegistries = []
|
|
),
|
|
|
|
DepsAll = inst_preserving_condense(
|
|
[DepsTracks, DepsSrcInts, DepsOpts, DepsRegistries]),
|
|
Deps = combine_deps_list(DepsAll).
|
|
|
|
:- func imports_012 =
|
|
(find_module_deps(dependency_file_index)::out(find_module_deps)) is det.
|
|
|
|
imports_012 =
|
|
cache_computed_module_deps(computed_module_deps_import_012,
|
|
combine_deps_list([
|
|
module_target_int0 `of` ancestors,
|
|
module_target_int1 `of` direct_imports,
|
|
module_target_int2 `of` indirect_imports
|
|
])
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% TargetType `of` F is function that returns the set of TargetType targets
|
|
% based on the modules generated by F.
|
|
%
|
|
% e.g. module_target_int0 `of` ancestors takes a module and returns the
|
|
% set of .int0 targets for the module's ancestor modules.
|
|
%
|
|
:- func of(module_target_type, find_module_deps(module_index)) =
|
|
find_module_deps(dependency_file_index).
|
|
:- mode of(in, in(find_module_deps)) = out(find_module_deps) is det.
|
|
|
|
of(FileType, FindDeps) =
|
|
of_2(FileType, FindDeps).
|
|
|
|
:- pred of_2(module_target_type::in,
|
|
find_module_deps(module_index)::in(find_module_deps),
|
|
globals::in, module_index::in, maybe_succeeded::out,
|
|
deps_set(dependency_file_index)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
of_2(FileType, FindDeps, Globals, ModuleIndex, Succeeded, TargetFiles,
|
|
!Info, !IO) :-
|
|
FindDeps(Globals, ModuleIndex, Succeeded, ModuleIndexes, !Info, !IO),
|
|
foldl2(of_3(FileType), ModuleIndexes, [], TargetFileIndexes, !Info),
|
|
list_to_set(TargetFileIndexes, TargetFiles).
|
|
|
|
:- pred of_3(module_target_type::in, module_index::in,
|
|
list(dependency_file_index)::in, list(dependency_file_index)::out,
|
|
make_info::in, make_info::out) is det.
|
|
|
|
of_3(FileType, ModuleIndex, !List, !Info) :-
|
|
TargetFile = dfmi_target(ModuleIndex, FileType),
|
|
dependency_file_to_index(TargetFile, TargetFileIndex, !Info),
|
|
!:List = [TargetFileIndex | !.List].
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred add_targets_of_modules_as_deps(module_target_type::in,
|
|
list(module_index)::in,
|
|
deps_set(dependency_file_index)::in, deps_set(dependency_file_index)::out,
|
|
make_info::in, make_info::out) is det.
|
|
|
|
add_targets_of_modules_as_deps(TargetType, ModuleIndexes, !Deps, !Info) :-
|
|
list.map_foldl(target_of_module_to_dep_file_index(TargetType),
|
|
ModuleIndexes, TargetFileIndexes, !Info),
|
|
% Converting TargetFileIndexes to a set, and then unioning !.Deps
|
|
% with that set should usually be faster than inserting its elements
|
|
% into !.Deps one by one. This is because TargetFileIndexes can be expected
|
|
% to usually be not-seen-before indexes, which means that calling
|
|
% insert_list here would end up repeatedly appending to the end of !.Deps.
|
|
union(list_to_set(TargetFileIndexes), !Deps).
|
|
|
|
:- pred target_of_module_to_dep_file_index(module_target_type::in,
|
|
module_index::in, dependency_file_index::out,
|
|
make_info::in, make_info::out) is det.
|
|
|
|
target_of_module_to_dep_file_index(TargetType, ModuleIndex, TargetFileIndex,
|
|
!Info) :-
|
|
TargetFile = dfmi_target(ModuleIndex, TargetType),
|
|
dependency_file_to_index(TargetFile, TargetFileIndex, !Info).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- func files_of(find_module_deps_plain_set(dependency_file),
|
|
find_module_deps(module_index)) = find_module_deps(dependency_file_index).
|
|
:- mode files_of(in(find_module_deps_plain_set), in(find_module_deps))
|
|
= out(find_module_deps) is det.
|
|
|
|
files_of(FindFiles, FindDeps) =
|
|
files_of_2(FindFiles, FindDeps).
|
|
|
|
:- pred files_of_2(
|
|
find_module_deps_plain_set(dependency_file)::
|
|
in(find_module_deps_plain_set),
|
|
find_module_deps(module_index)::in(find_module_deps),
|
|
globals::in, module_index::in, maybe_succeeded::out,
|
|
deps_set(dependency_file_index)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
files_of_2(FindFiles, FindDeps, Globals, ModuleIndex, Succeeded, DepIndices,
|
|
!Info, !IO) :-
|
|
KeepGoing = !.Info ^ mki_keep_going,
|
|
FindDeps(Globals, ModuleIndex, Succeeded1, ModuleIndices, !Info, !IO),
|
|
( if
|
|
Succeeded1 = did_not_succeed,
|
|
KeepGoing = do_not_keep_going
|
|
then
|
|
Succeeded = did_not_succeed,
|
|
DepIndices = init
|
|
else
|
|
deps_set_foldl3_maybe_stop_at_error_find_plain_union_mi(KeepGoing,
|
|
FindFiles, Globals, to_sorted_list(ModuleIndices),
|
|
succeeded, Succeeded2, init, FileNames, !Info, !IO),
|
|
Succeeded = Succeeded1 `and` Succeeded2,
|
|
dependency_files_to_index_set(set.to_sorted_list(FileNames),
|
|
DepIndices, !Info)
|
|
).
|
|
|
|
:- pred get_intermod_imports_and_their_ancestors(
|
|
globals::in, module_index::in, maybe_succeeded::out,
|
|
deps_set(module_index)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
get_intermod_imports_and_their_ancestors(Globals, ModuleIndex, Succeeded,
|
|
Result, !Info, !IO) :-
|
|
KeepGoing = !.Info ^ mki_keep_going,
|
|
intermod_imports(Globals, ModuleIndex, Succeeded1, Modules1, !Info, !IO),
|
|
( if
|
|
Succeeded1 = did_not_succeed,
|
|
KeepGoing = do_not_keep_going
|
|
then
|
|
Succeeded = did_not_succeed,
|
|
Result = init
|
|
else
|
|
deps_set_foldl3_maybe_stop_at_error_find_union_mi(KeepGoing,
|
|
ancestors, Globals, to_sorted_list(Modules1),
|
|
succeeded, Succeeded2, init, Result, !Info, !IO),
|
|
Succeeded = Succeeded1 `and` Succeeded2
|
|
).
|
|
|
|
:- pred get_intermod_imports_their_ancestors_and_012(globals::in,
|
|
module_index::in, maybe_succeeded::out,
|
|
deps_set(dependency_file_index)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
get_intermod_imports_their_ancestors_and_012(Globals, ModuleIndex,
|
|
Succeeded, Result, !Info, !IO) :-
|
|
KeepGoing = !.Info ^ mki_keep_going,
|
|
get_intermod_imports_and_their_ancestors(Globals,
|
|
ModuleIndex, Succeeded1, Modules1, !Info, !IO),
|
|
( if
|
|
Succeeded1 = did_not_succeed,
|
|
KeepGoing = do_not_keep_going
|
|
then
|
|
Succeeded = did_not_succeed,
|
|
Result = init
|
|
else
|
|
deps_set_foldl3_maybe_stop_at_error_find_union_fi(KeepGoing,
|
|
imports_012, Globals, to_sorted_list(Modules1),
|
|
succeeded, Succeeded2, init, Result, !Info, !IO),
|
|
Succeeded = Succeeded1 `and` Succeeded2
|
|
).
|
|
|
|
:- pred find_own_imports_012(globals::in, module_index::in,
|
|
maybe_succeeded::out, deps_set(dependency_file_index)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
find_own_imports_012(Globals, ModuleIndex, Succeeded, Result, !Info, !IO) :-
|
|
KeepGoing = !.Info ^ mki_keep_going,
|
|
deps_set_foldl3_maybe_stop_at_error_find_union_fi(KeepGoing,
|
|
imports_012, Globals, [ModuleIndex],
|
|
succeeded, Succeeded, init, Result, !Info, !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred no_deps(globals::in, module_index::in, maybe_succeeded::out,
|
|
deps_set(T)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
no_deps(_, _, succeeded, init, !Info, !IO).
|
|
|
|
:- pred self(globals::in, module_index::in, maybe_succeeded::out,
|
|
deps_set(module_index)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
self(_Globals, ModuleIndex, succeeded, make_singleton_set(ModuleIndex),
|
|
!Info, !IO).
|
|
|
|
:- pred ancestors(globals::in, module_index::in, maybe_succeeded::out,
|
|
deps_set(module_index)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
ancestors(_Globals, ModuleIndex, succeeded, AncestorIndices, !Info, !IO) :-
|
|
module_index_to_name(!.Info, ModuleIndex, ModuleName),
|
|
Ancestors = get_ancestors(ModuleName),
|
|
module_names_to_index_set(Ancestors, AncestorIndices, !Info).
|
|
|
|
:- pred add_targets_of_ancestors_as_deps(module_target_type::in,
|
|
module_index::in,
|
|
deps_set(dependency_file_index)::in, deps_set(dependency_file_index)::out,
|
|
make_info::in, make_info::out) is det.
|
|
|
|
add_targets_of_ancestors_as_deps(TargetType, ModuleIndex, !Deps, !Info) :-
|
|
module_index_to_name(!.Info, ModuleIndex, ModuleName),
|
|
module_names_to_index_set(get_ancestors(ModuleName),
|
|
AncestorModuleIndexSet, !Info),
|
|
add_targets_of_modules_as_deps(TargetType,
|
|
to_sorted_list(AncestorModuleIndexSet), !Deps, !Info).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred direct_imports(globals::in, module_index::in,
|
|
maybe_succeeded::out, deps_set(module_index)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
direct_imports(Globals, ModuleIndex, Succeeded, Modules, !Info, !IO) :-
|
|
CachedDirectImports0 = !.Info ^ mki_cached_direct_imports,
|
|
( if map.search(CachedDirectImports0, ModuleIndex, Result0) then
|
|
Result0 = deps_result(Succeeded, Modules)
|
|
else
|
|
KeepGoing = !.Info ^ mki_keep_going,
|
|
non_intermod_direct_imports(Globals, ModuleIndex, Succeeded0, Modules0,
|
|
!Info, !IO),
|
|
( if
|
|
Succeeded0 = did_not_succeed,
|
|
KeepGoing = do_not_keep_going
|
|
then
|
|
Succeeded = did_not_succeed,
|
|
Modules = init
|
|
else
|
|
% We also read `.int' files for the modules for which we read
|
|
% `.opt' files, and for the modules imported by those modules.
|
|
intermod_imports(Globals, ModuleIndex, Succeeded1, IntermodModules,
|
|
!Info, !IO),
|
|
( if
|
|
Succeeded1 = did_not_succeed,
|
|
KeepGoing = do_not_keep_going
|
|
then
|
|
Succeeded = did_not_succeed,
|
|
Modules = init
|
|
else
|
|
union(Modules0, IntermodModules, Modules1),
|
|
deps_set_foldl3_maybe_stop_at_error_find_union_mi(KeepGoing,
|
|
non_intermod_direct_imports, Globals,
|
|
to_sorted_list(IntermodModules), succeeded, Succeeded2,
|
|
Modules1, Modules2, !Info, !IO),
|
|
Succeeded = Succeeded0 `and` Succeeded1 `and` Succeeded2,
|
|
Modules = delete(Modules2, ModuleIndex)
|
|
)
|
|
),
|
|
Result = deps_result(Succeeded, Modules),
|
|
CachedDirectImports1 = !.Info ^ mki_cached_direct_imports,
|
|
map.det_insert(ModuleIndex, Result,
|
|
CachedDirectImports1, CachedDirectImports),
|
|
!Info ^ mki_cached_direct_imports := CachedDirectImports
|
|
).
|
|
|
|
% Return the modules for which `.int' files are read in a compilation
|
|
% which does not use `--intermodule-optimization'.
|
|
%
|
|
:- pred non_intermod_direct_imports(globals::in, module_index::in,
|
|
maybe_succeeded::out, deps_set(module_index)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
non_intermod_direct_imports(Globals, ModuleIndex, Succeeded, Modules,
|
|
!Info, !IO) :-
|
|
CachedNonIntermodDirectImports0 =
|
|
!.Info ^ mki_cached_non_intermod_direct_imports,
|
|
( if map.search(CachedNonIntermodDirectImports0, ModuleIndex, Result0) then
|
|
Result0 = deps_result(Succeeded, Modules)
|
|
else
|
|
non_intermod_direct_imports_uncached(Globals, ModuleIndex, Succeeded,
|
|
Modules, !Info, !IO),
|
|
Result = deps_result(Succeeded, Modules),
|
|
CachedNonIntermodDirectImports1 =
|
|
!.Info ^ mki_cached_non_intermod_direct_imports,
|
|
map.det_insert(ModuleIndex, Result,
|
|
CachedNonIntermodDirectImports1, CachedNonIntermodDirectImports),
|
|
!Info ^ mki_cached_non_intermod_direct_imports
|
|
:= CachedNonIntermodDirectImports
|
|
).
|
|
|
|
:- pred non_intermod_direct_imports_uncached(globals::in, module_index::in,
|
|
maybe_succeeded::out, deps_set(module_index)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
non_intermod_direct_imports_uncached(Globals, ModuleIndex, Succeeded, Modules,
|
|
!Info, !IO) :-
|
|
module_index_to_name(!.Info, ModuleIndex, ModuleName),
|
|
get_module_dependencies(Globals, ModuleName, MaybeModuleDepInfo,
|
|
!Info, !IO),
|
|
(
|
|
MaybeModuleDepInfo = some_module_dep_info(ModuleDepInfo),
|
|
|
|
% Find the direct imports of this module (modules for which we will
|
|
% read the `.int' files).
|
|
%
|
|
% Note that we need to do this both for the imports of this module
|
|
% and for the imports of its ancestors. This is because if this module
|
|
% is a submodule, then it may depend on things imported only by its
|
|
% ancestors.
|
|
%
|
|
module_dep_info_get_int_deps(ModuleDepInfo, IntDeps),
|
|
module_dep_info_get_imp_deps(ModuleDepInfo, ImpDeps),
|
|
module_names_to_index_set(set.to_sorted_list(IntDeps), DepsInt, !Info),
|
|
module_names_to_index_set(set.to_sorted_list(ImpDeps), DepsImp, !Info),
|
|
Modules0 = sparse_bitset.union(DepsInt, DepsImp),
|
|
(
|
|
ModuleName = qualified(ParentModule, _),
|
|
module_name_to_index(ParentModule, ParentIndex, !Info),
|
|
non_intermod_direct_imports(Globals, ParentIndex, Succeeded,
|
|
ParentImports, !Info, !IO),
|
|
Modules = union(ParentImports, Modules0)
|
|
;
|
|
ModuleName = unqualified(_),
|
|
Succeeded = succeeded,
|
|
Modules = Modules0
|
|
)
|
|
;
|
|
MaybeModuleDepInfo = no_module_dep_info,
|
|
Succeeded = did_not_succeed,
|
|
Modules = init
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Return the list of modules for which we should read `.int2' files.
|
|
%
|
|
:- pred indirect_imports(globals::in, module_index::in,
|
|
maybe_succeeded::out, deps_set(module_index)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
indirect_imports(Globals, ModuleIndex, Succeeded, Modules, !Info, !IO) :-
|
|
CachedIndirectImports0 = !.Info ^ mki_cached_indirect_imports,
|
|
( if map.search(CachedIndirectImports0, ModuleIndex, CachedResult) then
|
|
CachedResult = deps_result(Succeeded, Modules)
|
|
else
|
|
indirect_imports_uncached(Globals, direct_imports, ModuleIndex,
|
|
Succeeded, Modules, !Info, !IO),
|
|
Result = deps_result(Succeeded, Modules),
|
|
CachedIndirectImports1 = !.Info ^ mki_cached_indirect_imports,
|
|
map.det_insert(ModuleIndex, Result,
|
|
CachedIndirectImports1, CachedIndirectImports),
|
|
!Info ^ mki_cached_indirect_imports := CachedIndirectImports
|
|
).
|
|
|
|
% Return the list of modules for which we should read `.int2' files,
|
|
% ignoring those which need to be read as a result of importing modules
|
|
% imported by a `.opt' file.
|
|
%
|
|
:- pred non_intermod_indirect_imports(globals::in, module_index::in,
|
|
maybe_succeeded::out, deps_set(module_index)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
non_intermod_indirect_imports(Globals, ModuleIndex, Succeeded, Modules,
|
|
!Info, !IO) :-
|
|
indirect_imports_uncached(Globals, non_intermod_direct_imports,
|
|
ModuleIndex, Succeeded, Modules, !Info, !IO).
|
|
|
|
:- pred indirect_imports_uncached(globals::in,
|
|
find_module_deps(module_index)::in(find_module_deps),
|
|
module_index::in, maybe_succeeded::out, deps_set(module_index)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
indirect_imports_uncached(Globals, FindDirectImports, ModuleIndex, Succeeded,
|
|
IndirectImports, !Info, !IO) :-
|
|
FindDirectImports(Globals, ModuleIndex, DirectSucceeded, DirectImports,
|
|
!Info, !IO),
|
|
% XXX The original version of this code by stayl had the line assigning
|
|
% to KeepGoing textually *before* the call to FindDirectImports, but
|
|
% looked up the keep_going in the version of !Info *after* that call.
|
|
KeepGoing = !.Info ^ mki_keep_going,
|
|
( if
|
|
DirectSucceeded = did_not_succeed,
|
|
KeepGoing = do_not_keep_going
|
|
then
|
|
Succeeded = did_not_succeed,
|
|
IndirectImports = init
|
|
else
|
|
deps_set_foldl3_maybe_stop_at_error_find_union_mi(KeepGoing,
|
|
find_transitive_implementation_imports, Globals,
|
|
to_sorted_list(DirectImports), succeeded, IndirectSucceeded,
|
|
init, IndirectImports0, !Info, !IO),
|
|
IndirectImports = difference(
|
|
delete(IndirectImports0, ModuleIndex),
|
|
DirectImports),
|
|
Succeeded = DirectSucceeded `and` IndirectSucceeded
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Return the list of modules for which we should read `.opt' files.
|
|
%
|
|
:- pred intermod_imports(globals::in, module_index::in,
|
|
maybe_succeeded::out, deps_set(module_index)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
intermod_imports(Globals, ModuleIndex, Succeeded, Modules, !Info, !IO) :-
|
|
globals.get_any_intermod(Globals, AnyIntermod),
|
|
(
|
|
AnyIntermod = yes,
|
|
globals.lookup_bool_option(Globals, read_opt_files_transitively,
|
|
Transitive),
|
|
(
|
|
Transitive = yes,
|
|
find_transitive_implementation_imports(Globals, ModuleIndex,
|
|
Succeeded, Modules, !Info, !IO)
|
|
;
|
|
Transitive = no,
|
|
non_intermod_direct_imports(Globals, ModuleIndex, Succeeded,
|
|
Modules, !Info, !IO)
|
|
)
|
|
;
|
|
AnyIntermod = no,
|
|
Succeeded = succeeded,
|
|
Modules = init
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred foreign_imports(globals::in, module_index::in,
|
|
maybe_succeeded::out, deps_set(module_index)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
foreign_imports(Globals, ModuleIndex, Succeeded, Modules, !Info, !IO) :-
|
|
% The object file depends on the header files for the modules
|
|
% mentioned in `:- pragma foreign_import_module' declarations
|
|
% in the current module and the `.opt' files it imports.
|
|
|
|
globals.get_backend_foreign_languages(Globals, Languages),
|
|
intermod_imports(Globals, ModuleIndex, IntermodSucceeded, IntermodModules,
|
|
!Info, !IO),
|
|
KeepGoing = !.Info ^ mki_keep_going,
|
|
deps_set_foldl3_maybe_stop_at_error_find_union_mi(KeepGoing,
|
|
find_module_foreign_imports(set.list_to_set(Languages)),
|
|
Globals, to_sorted_list(insert(IntermodModules, ModuleIndex)),
|
|
succeeded, ForeignSucceeded, init, Modules, !Info, !IO),
|
|
Succeeded = IntermodSucceeded `and` ForeignSucceeded.
|
|
|
|
:- pred find_module_foreign_imports(set(foreign_language)::in,
|
|
globals::in, module_index::in,
|
|
maybe_succeeded::out, deps_set(module_index)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
find_module_foreign_imports(Languages, Globals, ModuleIndex, Succeeded,
|
|
ForeignModules, !Info, !IO) :-
|
|
% Languages should be constant for the duration of the process,
|
|
% so is unnecessary to include in the cache key.
|
|
CachedForeignImports0 = !.Info ^ mki_cached_transitive_foreign_imports,
|
|
( if map.search(CachedForeignImports0, ModuleIndex, CachedResult) then
|
|
CachedResult = deps_result(Succeeded, ForeignModules)
|
|
else
|
|
find_transitive_implementation_imports(Globals, ModuleIndex,
|
|
Succeeded0, ImportedModules, !Info, !IO),
|
|
(
|
|
Succeeded0 = succeeded,
|
|
KeepGoing = !.Info ^ mki_keep_going,
|
|
deps_set_foldl3_maybe_stop_at_error_find_union_mi(KeepGoing,
|
|
find_module_foreign_imports_uncached(Languages),
|
|
Globals, to_sorted_list(insert(ImportedModules, ModuleIndex)),
|
|
succeeded, Succeeded, init, ForeignModules, !Info, !IO),
|
|
Result = deps_result(Succeeded, ForeignModules),
|
|
CachedForeignImports1 =
|
|
!.Info ^ mki_cached_transitive_foreign_imports,
|
|
map.det_insert(ModuleIndex, Result,
|
|
CachedForeignImports1, CachedForeignImports),
|
|
!Info ^ mki_cached_transitive_foreign_imports :=
|
|
CachedForeignImports
|
|
;
|
|
Succeeded0 = did_not_succeed,
|
|
Succeeded = did_not_succeed,
|
|
ForeignModules = init
|
|
)
|
|
).
|
|
|
|
:- pred find_module_foreign_imports_uncached(set(foreign_language)::in,
|
|
globals::in, module_index::in,
|
|
maybe_succeeded::out, deps_set(module_index)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
find_module_foreign_imports_uncached(Languages, Globals, ModuleIndex,
|
|
Succeeded, ForeignModules, !Info, !IO) :-
|
|
module_index_to_name(!.Info, ModuleIndex, ModuleName),
|
|
get_module_dependencies(Globals, ModuleName, MaybeModuleDepInfo,
|
|
!Info, !IO),
|
|
(
|
|
MaybeModuleDepInfo = some_module_dep_info(ModuleDepInfo),
|
|
module_dep_info_get_fims(ModuleDepInfo, FIMSpecs),
|
|
ForLangsPred =
|
|
( pred(fim_spec(Lang, Module)::in, Module::out) is semidet :-
|
|
set.contains(Languages, Lang)
|
|
),
|
|
set.filter_map(ForLangsPred, FIMSpecs, ForeignModuleNameSet),
|
|
module_names_to_index_set(set.to_sorted_list(ForeignModuleNameSet),
|
|
ForeignModules, !Info),
|
|
Succeeded = succeeded
|
|
;
|
|
MaybeModuleDepInfo = no_module_dep_info,
|
|
ForeignModules = init,
|
|
Succeeded = did_not_succeed
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred fact_table_files(globals::in, module_index::in,
|
|
maybe_succeeded::out, set(dependency_file)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
fact_table_files(Globals, ModuleIndex, Succeeded, Files, !Info, !IO) :-
|
|
module_index_to_name(!.Info, ModuleIndex, ModuleName),
|
|
get_module_dependencies(Globals, ModuleName, MaybeModuleDepInfo,
|
|
!Info, !IO),
|
|
(
|
|
MaybeModuleDepInfo = some_module_dep_info(ModuleDepInfo),
|
|
Succeeded = succeeded,
|
|
module_dep_info_get_fact_tables(ModuleDepInfo, FactTableFiles),
|
|
Files = set.map((func(File) = dep_file(File)), FactTableFiles)
|
|
;
|
|
MaybeModuleDepInfo = no_module_dep_info,
|
|
Succeeded = did_not_succeed,
|
|
Files = init
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred foreign_include_files(globals::in, module_index::in,
|
|
maybe_succeeded::out, set(dependency_file)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
foreign_include_files(Globals, ModuleIndex, Succeeded, Files, !Info, !IO) :-
|
|
globals.get_backend_foreign_languages(Globals, Languages),
|
|
module_index_to_name(!.Info, ModuleIndex, ModuleName),
|
|
get_module_dependencies(Globals, ModuleName, MaybeModuleDepInfo,
|
|
!Info, !IO),
|
|
(
|
|
MaybeModuleDepInfo = some_module_dep_info(ModuleDepInfo),
|
|
Succeeded = succeeded,
|
|
module_dep_info_get_source_file_name(ModuleDepInfo, SourceFileName),
|
|
module_dep_info_get_foreign_include_files(ModuleDepInfo,
|
|
ForeignIncludeFiles),
|
|
FilesList = get_foreign_include_files(set.list_to_set(Languages),
|
|
SourceFileName, set.to_sorted_list(ForeignIncludeFiles)),
|
|
Files = set.list_to_set(FilesList)
|
|
;
|
|
MaybeModuleDepInfo = no_module_dep_info,
|
|
Succeeded = did_not_succeed,
|
|
Files = set.init
|
|
).
|
|
|
|
:- func get_foreign_include_files(set(foreign_language), file_name,
|
|
list(foreign_include_file_info)) = list(dependency_file).
|
|
|
|
get_foreign_include_files(Languages, SourceFileName, ForeignIncludes)
|
|
= Files :-
|
|
list.filter_map(get_foreign_include_files_2(Languages, SourceFileName),
|
|
ForeignIncludes, Files).
|
|
|
|
:- pred get_foreign_include_files_2(set(foreign_language)::in, file_name::in,
|
|
foreign_include_file_info::in, dependency_file::out) is semidet.
|
|
|
|
get_foreign_include_files_2(Languages, SourceFileName, ForeignInclude, File) :-
|
|
ForeignInclude = foreign_include_file_info(Language, IncludeFileName),
|
|
set.member(Language, Languages),
|
|
make_include_file_path(SourceFileName, IncludeFileName, IncludePath),
|
|
File = dep_file(IncludePath).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Note that we go to some effort in this module to stop dependency
|
|
% calculation as soon as possible if there are errors.
|
|
% This is important, because the calls to get_module_dependencies from
|
|
% the dependency calculation predicates can result in every module in
|
|
% the program being read.
|
|
%
|
|
:- func combine_deps(
|
|
find_module_deps(T)::in(find_module_deps),
|
|
find_module_deps(T)::in(find_module_deps)) =
|
|
(find_module_deps(T)::out(find_module_deps)) is det.
|
|
|
|
combine_deps(FindDeps1, FindDeps2) =
|
|
combine_deps_2(FindDeps1, FindDeps2).
|
|
|
|
:- pred combine_deps_2(
|
|
find_module_deps(T)::in(find_module_deps),
|
|
find_module_deps(T)::in(find_module_deps),
|
|
globals::in, module_index::in, maybe_succeeded::out, deps_set(T)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
combine_deps_2(FindDeps1, FindDeps2, Globals, ModuleIndex, Succeeded, Deps,
|
|
!Info, !IO) :-
|
|
FindDeps1(Globals, ModuleIndex, Succeeded1, Deps1, !Info, !IO),
|
|
( if
|
|
Succeeded1 = did_not_succeed,
|
|
!.Info ^ mki_keep_going = do_not_keep_going
|
|
then
|
|
Succeeded = did_not_succeed,
|
|
Deps = Deps1
|
|
else
|
|
FindDeps2(Globals, ModuleIndex, Succeeded2, Deps2, !Info, !IO),
|
|
Succeeded = Succeeded1 `and` Succeeded2,
|
|
Deps = union(Deps1, Deps2)
|
|
).
|
|
|
|
:- func combine_deps_list(list(
|
|
find_module_deps(T))::in(list_skel(find_module_deps))) =
|
|
(find_module_deps(T)::out(find_module_deps)) is det.
|
|
|
|
combine_deps_list([]) = no_deps.
|
|
combine_deps_list([FindDeps]) = FindDeps.
|
|
combine_deps_list([FindDeps1, FindDeps2 | FindDepsTail]) =
|
|
combine_deps(FindDeps1, combine_deps_list([FindDeps2 | FindDepsTail])).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% cache_computed_module_deps(Label, FindDeps) adds caching to FindDeps.
|
|
% Label is used to discriminate cache entries for the same module;
|
|
% it must uniquely identify the set that is computed by FindDeps.
|
|
%
|
|
:- pred cache_computed_module_deps(computed_module_deps_label::in,
|
|
find_module_deps(dependency_file_index)::in(find_module_deps),
|
|
globals::in, module_index::in, maybe_succeeded::out,
|
|
deps_set(dependency_file_index)::out, make_info::in, make_info::out,
|
|
io::di, io::uo) is det.
|
|
|
|
cache_computed_module_deps(Label, FindDeps, Globals, ModuleIndex, Succeeded,
|
|
Deps, !Info, !IO) :-
|
|
Cache0 = !.Info ^ mki_cached_computed_module_deps,
|
|
Key = computed_module_deps_key(ModuleIndex, Label),
|
|
( if map.search(Cache0, Key, CachedResult) then
|
|
CachedResult = deps_result(Succeeded, Deps)
|
|
else
|
|
FindDeps(Globals, ModuleIndex, Succeeded, Deps, !Info, !IO),
|
|
Cache1 = !.Info ^ mki_cached_computed_module_deps,
|
|
Result = deps_result(Succeeded, Deps),
|
|
map.det_insert(Key, Result, Cache1, Cache),
|
|
!Info ^ mki_cached_computed_module_deps := Cache
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% XXX Document me.
|
|
%
|
|
:- pred deps_set_foldl3_find_trans_deps(maybe_keep_going::in,
|
|
transitive_dependencies_type::in, process_modules_where::in,
|
|
globals::in, list(module_index)::in,
|
|
maybe_succeeded::in, maybe_succeeded::out,
|
|
deps_set(module_index)::in, deps_set(module_index)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
deps_set_foldl3_find_trans_deps(_KeepGoing, _DependenciesType,
|
|
_IsModuleInCurDir, _Globals, [], !Succeeded, !Acc, !Info, !IO).
|
|
deps_set_foldl3_find_trans_deps(KeepGoing, DependenciesType,
|
|
IsModuleInCurDir, Globals, [T | Ts], !Succeeded, !Acc, !Info, !IO) :-
|
|
find_transitive_module_dependencies_uncached(KeepGoing, DependenciesType,
|
|
IsModuleInCurDir, Globals, T, NewSucceeded, !Acc, !Info, !IO),
|
|
( if
|
|
( NewSucceeded = succeeded
|
|
; KeepGoing = do_keep_going
|
|
)
|
|
then
|
|
!:Succeeded = !.Succeeded `and` NewSucceeded,
|
|
deps_set_foldl3_find_trans_deps(KeepGoing, DependenciesType,
|
|
IsModuleInCurDir, Globals, Ts, !Succeeded, !Acc, !Info, !IO)
|
|
else
|
|
!:Succeeded = did_not_succeed
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred deps_set_foldl3_maybe_stop_at_error_find_union_mi(
|
|
maybe_keep_going::in,
|
|
find_module_deps(module_index)::in(find_module_deps),
|
|
globals::in, list(module_index)::in,
|
|
maybe_succeeded::in, maybe_succeeded::out,
|
|
deps_set(module_index)::in, deps_set(module_index)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
deps_set_foldl3_maybe_stop_at_error_find_union_mi(_KeepGoing,
|
|
_FindDeps, _Globals, [], !Succeeded, !Deps, !Info, !IO).
|
|
deps_set_foldl3_maybe_stop_at_error_find_union_mi(KeepGoing,
|
|
FindDeps, Globals, [MI | MIs], !Succeeded, !Deps, !Info, !IO) :-
|
|
FindDeps(Globals, MI, NewSucceeded, NewDeps, !Info, !IO),
|
|
union(NewDeps, !Deps),
|
|
( if
|
|
( NewSucceeded = succeeded
|
|
; KeepGoing = do_keep_going
|
|
)
|
|
then
|
|
!:Succeeded = !.Succeeded `and` NewSucceeded,
|
|
deps_set_foldl3_maybe_stop_at_error_find_union_mi(KeepGoing,
|
|
FindDeps, Globals, MIs, !Succeeded, !Deps, !Info, !IO)
|
|
else
|
|
!:Succeeded = did_not_succeed
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
:- pred deps_set_foldl3_maybe_stop_at_error_find_plain_union_mi(
|
|
maybe_keep_going::in,
|
|
find_module_deps_plain_set(dependency_file)::
|
|
in(find_module_deps_plain_set),
|
|
globals::in, list(module_index)::in,
|
|
maybe_succeeded::in, maybe_succeeded::out,
|
|
set(dependency_file)::in, set(dependency_file)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
deps_set_foldl3_maybe_stop_at_error_find_plain_union_mi(_KeepGoing,
|
|
_FindDeps, _Globals, [], !Succeeded, !Deps, !Info, !IO).
|
|
deps_set_foldl3_maybe_stop_at_error_find_plain_union_mi(KeepGoing,
|
|
FindDeps, Globals, [MI | MIs], !Succeeded, !Deps, !Info, !IO) :-
|
|
FindDeps(Globals, MI, NewSucceeded, NewDeps, !Info, !IO),
|
|
set.union(NewDeps, !Deps),
|
|
( if
|
|
( NewSucceeded = succeeded
|
|
; KeepGoing = do_keep_going
|
|
)
|
|
then
|
|
!:Succeeded = !.Succeeded `and` NewSucceeded,
|
|
deps_set_foldl3_maybe_stop_at_error_find_plain_union_mi(KeepGoing,
|
|
FindDeps, Globals, MIs, !Succeeded, !Deps, !Info, !IO)
|
|
else
|
|
!:Succeeded = did_not_succeed
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
% XXX Document me.
|
|
%
|
|
% The difference between this predicate (and its local siblings) and
|
|
% the old deps_set_foldl3_maybe_stop_at_error (now replaced by these
|
|
% predicates) is that the second argument has a more specific job.
|
|
% That job used to be done by a predicate, union_deps, whose documentation
|
|
% used to say this:
|
|
%
|
|
% "Union the output set of dependencies for a given module
|
|
% with the accumulated set. This is used with
|
|
% deps_set_foldl3_maybe_stop_at_error to iterate over a list of
|
|
% module_names to find all target files for those modules."
|
|
%
|
|
:- pred deps_set_foldl3_maybe_stop_at_error_find_union_fi(maybe_keep_going::in,
|
|
find_module_deps(dependency_file_index)::in(find_module_deps),
|
|
globals::in, list(module_index)::in,
|
|
maybe_succeeded::in, maybe_succeeded::out,
|
|
deps_set(dependency_file_index)::in, deps_set(dependency_file_index)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
deps_set_foldl3_maybe_stop_at_error_find_union_fi(_KeepGoing,
|
|
_FindDeps, _Globals, [], !Succeeded, !Deps, !Info, !IO).
|
|
deps_set_foldl3_maybe_stop_at_error_find_union_fi(KeepGoing,
|
|
FindDeps, Globals, [MI | MIs], !Succeeded, !Deps, !Info, !IO) :-
|
|
FindDeps(Globals, MI, NewSucceeded, NewDeps, !Info, !IO),
|
|
union(NewDeps, !Deps),
|
|
( if
|
|
( NewSucceeded = succeeded
|
|
; KeepGoing = do_keep_going
|
|
)
|
|
then
|
|
!:Succeeded = !.Succeeded `and` NewSucceeded,
|
|
deps_set_foldl3_maybe_stop_at_error_find_union_fi(KeepGoing,
|
|
FindDeps, Globals, MIs, !Succeeded, !Deps, !Info, !IO)
|
|
else
|
|
!:Succeeded = did_not_succeed
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
find_reachable_local_modules(Globals, ModuleName, Succeeded, Modules,
|
|
!Info, !IO) :-
|
|
module_name_to_index(ModuleName, ModuleIndex, !Info),
|
|
find_transitive_module_dependencies(Globals, all_dependencies,
|
|
process_only_modules_in_cur_dir, ModuleIndex, Succeeded, Modules0,
|
|
!Info, !IO),
|
|
module_index_set_to_plain_set(!.Info, Modules0, Modules).
|
|
|
|
:- pred find_transitive_implementation_imports(globals::in, module_index::in,
|
|
maybe_succeeded::out, deps_set(module_index)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
find_transitive_implementation_imports(Globals, ModuleIndex,
|
|
Succeeded, Modules, !Info, !IO) :-
|
|
find_transitive_module_dependencies(Globals, all_imports,
|
|
process_modules_anywhere, ModuleIndex, Succeeded, Modules0,
|
|
!Info, !IO),
|
|
Modules = insert(Modules0, ModuleIndex).
|
|
|
|
:- pred find_transitive_module_dependencies(globals::in,
|
|
transitive_dependencies_type::in,
|
|
process_modules_where::in, module_index::in,
|
|
maybe_succeeded::out, deps_set(module_index)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
find_transitive_module_dependencies(Globals, DependenciesType,
|
|
IsModuleInCurDir, ModuleIndex, Succeeded, Modules, !Info, !IO) :-
|
|
DepsRoot = transitive_dependencies_root(ModuleIndex, DependenciesType,
|
|
IsModuleInCurDir),
|
|
CachedTransDeps0 = !.Info ^ mki_cached_transitive_dependencies,
|
|
( if map.search(CachedTransDeps0, DepsRoot, Result0) then
|
|
Result0 = deps_result(Succeeded, Modules)
|
|
else
|
|
KeepGoing = !.Info ^ mki_keep_going,
|
|
find_transitive_module_dependencies_uncached(KeepGoing,
|
|
DependenciesType, IsModuleInCurDir, Globals, ModuleIndex,
|
|
Succeeded, init, Modules, !Info, !IO),
|
|
Result = deps_result(Succeeded, Modules),
|
|
CachedTransDeps1 = !.Info ^ mki_cached_transitive_dependencies,
|
|
map.det_insert(DepsRoot, Result, CachedTransDeps1, CachedTransDeps),
|
|
!Info ^ mki_cached_transitive_dependencies := CachedTransDeps
|
|
).
|
|
|
|
:- pred find_transitive_module_dependencies_uncached(maybe_keep_going::in,
|
|
transitive_dependencies_type::in, process_modules_where::in, globals::in,
|
|
module_index::in, maybe_succeeded::out,
|
|
deps_set(module_index)::in, deps_set(module_index)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
find_transitive_module_dependencies_uncached(KeepGoing, DependenciesType,
|
|
IsModuleInCurDir, Globals, ModuleIndex, Succeeded, Modules0, Modules,
|
|
!Info, !IO) :-
|
|
( if
|
|
member(ModuleIndex, Modules0)
|
|
then
|
|
Succeeded = succeeded,
|
|
Modules = Modules0
|
|
else if
|
|
DepsRoot = transitive_dependencies_root(ModuleIndex,
|
|
DependenciesType, IsModuleInCurDir),
|
|
map.search(!.Info ^ mki_cached_transitive_dependencies, DepsRoot,
|
|
Result0)
|
|
then
|
|
Result0 = deps_result(Succeeded, Modules1),
|
|
Modules = union(Modules0, Modules1)
|
|
else
|
|
module_index_to_name(!.Info, ModuleIndex, ModuleName),
|
|
get_module_dependencies(Globals, ModuleName, MaybeModuleDepInfo,
|
|
!Info, !IO),
|
|
(
|
|
MaybeModuleDepInfo = some_module_dep_info(ModuleDepInfo),
|
|
module_dep_info_get_source_file_dir(ModuleDepInfo, ModuleDir),
|
|
( if
|
|
(
|
|
IsModuleInCurDir = process_modules_anywhere
|
|
;
|
|
IsModuleInCurDir = process_only_modules_in_cur_dir,
|
|
ModuleDir = dir.this_directory
|
|
)
|
|
then
|
|
do_find_transitive_module_dependencies_uncached(KeepGoing,
|
|
DependenciesType, IsModuleInCurDir, Globals,
|
|
ModuleIndex, ModuleName, ModuleDepInfo, Succeeded,
|
|
Modules0, Modules, !Info, !IO)
|
|
else
|
|
Succeeded = succeeded,
|
|
Modules = Modules0
|
|
)
|
|
;
|
|
MaybeModuleDepInfo = no_module_dep_info,
|
|
Succeeded = did_not_succeed,
|
|
Modules = Modules0
|
|
)
|
|
).
|
|
|
|
:- pred do_find_transitive_module_dependencies_uncached(maybe_keep_going::in,
|
|
transitive_dependencies_type::in, process_modules_where::in, globals::in,
|
|
module_index::in, module_name::in, module_dep_info::in,
|
|
maybe_succeeded::out,
|
|
deps_set(module_index)::in, deps_set(module_index)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
do_find_transitive_module_dependencies_uncached(KeepGoing, DependenciesType,
|
|
IsModuleInCurDir, Globals, ModuleIndex, ModuleName, ModuleDepInfo,
|
|
Succeeded, Modules0, Modules, !Info, !IO) :-
|
|
module_dep_info_get_fims(ModuleDepInfo, FIMSpecs),
|
|
module_dep_info_get_module_name(ModuleDepInfo, MDI_ModuleName),
|
|
expect(unify(ModuleName, MDI_ModuleName), $pred,
|
|
"ModuleName != MDI_ModuleName"),
|
|
Ancestors = get_ancestors_set(ModuleName),
|
|
module_dep_info_get_children(ModuleDepInfo, Children),
|
|
module_dep_info_get_int_deps(ModuleDepInfo, IntDeps),
|
|
module_dep_info_get_imp_deps(ModuleDepInfo, ImpDeps),
|
|
(
|
|
% Ancestors don't need to be considered here.
|
|
% Anywhere the interface of the child module is needed,
|
|
% the ancestors must also have been imported.
|
|
DependenciesType = interface_imports,
|
|
ImportsToCheck = IntDeps,
|
|
IncludesToCheck = set.init
|
|
;
|
|
DependenciesType = all_dependencies,
|
|
set.map((pred(fim_spec(_, Mod)::in, Mod::out) is det),
|
|
FIMSpecs, ForeignDeps),
|
|
ImportsToCheck = set.union_list([
|
|
Ancestors, IntDeps, ImpDeps, ForeignDeps
|
|
]),
|
|
IncludesToCheck = Children
|
|
;
|
|
DependenciesType = all_imports,
|
|
set.map((pred(fim_spec(_, Mod)::in, Mod::out) is det),
|
|
FIMSpecs, ForeignDeps),
|
|
ImportsToCheck = set.union_list([
|
|
Ancestors, IntDeps, ImpDeps, ForeignDeps
|
|
]),
|
|
IncludesToCheck = set.init
|
|
),
|
|
module_names_to_index_set(set.to_sorted_list(ImportsToCheck),
|
|
ImportsToCheckSet, !Info),
|
|
module_names_to_index_set(set.to_sorted_list(IncludesToCheck),
|
|
IncludesToCheckSet, !Info),
|
|
Modules1 = insert(Modules0, ModuleIndex),
|
|
% XXX The pattern of use of the mki_importing_module field
|
|
% here suggest that it should not be a field of make_info
|
|
% at all, but rather a separate parameter of this predicate.
|
|
OldImportingModule = !.Info ^ mki_importing_module,
|
|
!Info ^ mki_importing_module := yes(ioi_import(ModuleName)),
|
|
deps_set_foldl3_find_trans_deps(KeepGoing, DependenciesType,
|
|
IsModuleInCurDir, Globals, to_sorted_list(ImportsToCheckSet),
|
|
succeeded, SucceededImports, Modules1, Modules2, !Info, !IO),
|
|
!Info ^ mki_importing_module := yes(ioi_include(ModuleName)),
|
|
deps_set_foldl3_find_trans_deps(KeepGoing, DependenciesType,
|
|
IsModuleInCurDir, Globals, to_sorted_list(IncludesToCheckSet),
|
|
succeeded, SucceededIncludes, Modules2, Modules, !Info, !IO),
|
|
!Info ^ mki_importing_module := OldImportingModule,
|
|
Succeeded = SucceededImports `and` SucceededIncludes.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
remove_nested_modules(Globals, Modules0, Modules, !Info, !IO) :-
|
|
list.foldl3(collect_nested_modules(Globals), Modules0,
|
|
set.init, NestedModules, !Info, !IO),
|
|
list.negated_filter(set.contains(NestedModules), Modules0, Modules).
|
|
|
|
:- pred collect_nested_modules(globals::in, module_name::in,
|
|
set(module_name)::in, set(module_name)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
collect_nested_modules(Globals, ModuleName, !NestedModules, !Info, !IO) :-
|
|
get_module_dependencies(Globals, ModuleName, MaybeModuleDepInfo,
|
|
!Info, !IO),
|
|
(
|
|
MaybeModuleDepInfo = some_module_dep_info(ModuleDepInfo),
|
|
module_dep_info_get_maybe_top_module(ModuleDepInfo, MaybeTopModule),
|
|
NestedSubModules = get_nested_children_of_top_module(MaybeTopModule),
|
|
set.union(NestedSubModules, !NestedModules)
|
|
;
|
|
MaybeModuleDepInfo = no_module_dep_info
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
make_local_module_id_options(Globals, ModuleName, Succeeded, Options,
|
|
!Info, !IO) :-
|
|
find_reachable_local_modules(Globals, ModuleName, Succeeded, LocalModules,
|
|
!Info, !IO),
|
|
set.fold(make_local_module_id_option, LocalModules, [], Options).
|
|
|
|
:- pred make_local_module_id_option(module_name::in, list(string)::in,
|
|
list(string)::out) is det.
|
|
|
|
make_local_module_id_option(ModuleName, Opts0, Opts) :-
|
|
ModuleNameStr = sym_name_to_string(ModuleName),
|
|
Opts = ["--local-module-id", ModuleNameStr | Opts0].
|
|
|
|
:- pred make_write_target_dependency_status(globals::in,
|
|
pair(dependency_file, dependency_status)::in, io::di, io::uo) is det.
|
|
|
|
make_write_target_dependency_status(Globals, DepTarget - DepStatus, !IO) :-
|
|
(
|
|
DepStatus = deps_status_not_considered,
|
|
DepStatusStr = "deps_status_not_considered"
|
|
;
|
|
DepStatus = deps_status_being_built,
|
|
DepStatusStr = "deps_status_being_built"
|
|
;
|
|
DepStatus = deps_status_up_to_date,
|
|
DepStatusStr = "deps_status_up_to_date"
|
|
;
|
|
DepStatus = deps_status_error,
|
|
DepStatusStr = "deps_status_error"
|
|
),
|
|
dependency_file_to_file_name(Globals, DepTarget, DepTargetFileName, !IO),
|
|
io.format("\t%s - %s\n", [s(DepTargetFileName), s(DepStatusStr)], !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
dependency_status(Globals, Dep, Status, !Info, !IO) :-
|
|
(
|
|
Dep = dep_file(_FileName),
|
|
DepStatusMap0 = !.Info ^ mki_dependency_status,
|
|
( if version_hash_table.search(DepStatusMap0, Dep, StatusPrime) then
|
|
Status = StatusPrime
|
|
else
|
|
get_dependency_timestamp(Globals, Dep, MaybeTimestamp, !Info, !IO),
|
|
(
|
|
MaybeTimestamp = ok(_),
|
|
Status = deps_status_up_to_date
|
|
;
|
|
MaybeTimestamp = error(Error),
|
|
Status = deps_status_error,
|
|
io.format("** Error: %s\n", [s(Error)], !IO)
|
|
),
|
|
version_hash_table.det_insert(Dep, Status,
|
|
DepStatusMap0, DepStatusMap),
|
|
!Info ^ mki_dependency_status := DepStatusMap
|
|
)
|
|
;
|
|
Dep = dep_target(Target),
|
|
Target = target_file(ModuleName, FileType),
|
|
get_make_target_file_name(Globals, $pred, Target, TargetFileName, !IO),
|
|
( if
|
|
( FileType = module_target_source
|
|
; FileType = module_target_track_flags
|
|
)
|
|
then
|
|
% Source files are always up-to-date.
|
|
% .track_flags should already have been made, if required,
|
|
% so are also up-to-date.
|
|
ModuleTarget = module_target(module_target_source),
|
|
TopTargetFile = top_target_file(ModuleName, ModuleTarget),
|
|
maybe_warn_up_to_date_target(Globals, TopTargetFile,
|
|
TargetFileName, !Info, !IO),
|
|
Status = deps_status_up_to_date
|
|
else if
|
|
DepStatusMap0 = !.Info ^ mki_dependency_status,
|
|
version_hash_table.search(DepStatusMap0, Dep, StatusPrime)
|
|
then
|
|
Status = StatusPrime
|
|
else
|
|
get_module_dependencies(Globals, ModuleName, MaybeModuleDepInfo,
|
|
!Info, !IO),
|
|
(
|
|
MaybeModuleDepInfo = no_module_dep_info,
|
|
Status = deps_status_error
|
|
;
|
|
MaybeModuleDepInfo = some_module_dep_info(ModuleDepInfo),
|
|
module_dep_info_get_source_file_dir(ModuleDepInfo, ModuleDir),
|
|
( if ModuleDir = dir.this_directory then
|
|
Status = deps_status_not_considered
|
|
else
|
|
% Targets from libraries are always considered to be
|
|
% up-to-date if they exist.
|
|
get_target_timestamp(Globals, do_search, Target,
|
|
MaybeTimestamp, !Info, !IO),
|
|
(
|
|
MaybeTimestamp = ok(_),
|
|
Status = deps_status_up_to_date
|
|
;
|
|
MaybeTimestamp = error(Error),
|
|
Status = deps_status_error,
|
|
string.format("** Error: file `%s' not found: %s\n",
|
|
[s(TargetFileName), s(Error)], ErrorMsg),
|
|
% XXX MAKE_STREAM
|
|
% Try to write this with one call to avoid
|
|
% interleaved output when doing parallel builds.
|
|
io.write_string(ErrorMsg, !IO)
|
|
)
|
|
)
|
|
),
|
|
DepStatusMap1 = !.Info ^ mki_dependency_status,
|
|
version_hash_table.det_insert(Dep, Status,
|
|
DepStatusMap1, DepStatusMap),
|
|
!Info ^ mki_dependency_status := DepStatusMap
|
|
)
|
|
).
|
|
|
|
check_dependencies(Globals, TargetFileName, MaybeTimestamp, BuildDepsSucceeded,
|
|
DepFiles, DepsResult, !Info, !IO) :-
|
|
list.map_foldl2(dependency_status(Globals), DepFiles, DepStatusList,
|
|
!Info, !IO),
|
|
assoc_list.from_corresponding_lists(DepFiles, DepStatusList, DepStatusAL),
|
|
list.filter(
|
|
( pred((_ - DepStatus)::in) is semidet :-
|
|
DepStatus \= deps_status_up_to_date
|
|
), DepStatusAL, UnbuiltDependencies),
|
|
(
|
|
UnbuiltDependencies = [_ | _],
|
|
debug_make_msg(Globals,
|
|
check_dependencies_debug_unbuilt(Globals, TargetFileName,
|
|
UnbuiltDependencies),
|
|
!IO),
|
|
DepsResult = deps_error
|
|
;
|
|
UnbuiltDependencies = [],
|
|
debug_make_msg(Globals,
|
|
io.format("%s: finished dependencies\n",
|
|
[s(TargetFileName)]),
|
|
!IO),
|
|
list.map_foldl2(get_dependency_timestamp(Globals), DepFiles,
|
|
DepTimestamps, !Info, !IO),
|
|
|
|
check_dependency_timestamps(Globals, TargetFileName, MaybeTimestamp,
|
|
BuildDepsSucceeded, DepFiles,
|
|
dependency_file_to_file_name(Globals),
|
|
DepTimestamps, DepsResult, !IO)
|
|
).
|
|
|
|
:- pred check_dependencies_debug_unbuilt(globals::in, file_name::in,
|
|
assoc_list(dependency_file, dependency_status)::in,
|
|
io::di, io::uo) is det.
|
|
|
|
check_dependencies_debug_unbuilt(Globals, TargetFileName, UnbuiltDependencies,
|
|
!IO) :-
|
|
io.format("%s: dependencies could not be built.\n\t",
|
|
[s(TargetFileName)], !IO),
|
|
list.foldl(make_write_target_dependency_status(Globals),
|
|
UnbuiltDependencies, !IO).
|
|
|
|
:- pred check_dependencies_timestamps_write_missing_deps(file_name::in,
|
|
maybe_succeeded::in, list(File)::in,
|
|
pred(File, string, io, io)::in(pred(in, out, di, uo) is det),
|
|
list(maybe_error(timestamp))::in, io::di, io::uo) is det.
|
|
|
|
check_dependencies_timestamps_write_missing_deps(TargetFileName,
|
|
BuildDepsSucceeded, DepFiles, DepFileToStr, DepTimestamps, !IO) :-
|
|
assoc_list.from_corresponding_lists(DepFiles, DepTimestamps,
|
|
DepTimestampAL),
|
|
list.filter_map(
|
|
( pred(Pair::in, DepFile::out) is semidet :-
|
|
Pair = DepFile - error(_)
|
|
), DepTimestampAL, ErrorDeps),
|
|
list.map_foldl(DepFileToStr, ErrorDeps, ErrorDepStrs, !IO),
|
|
list.sort(ErrorDepStrs, SortedErrorDepStrs),
|
|
ErrorDepsStr = string.join_list(", ", SortedErrorDepStrs),
|
|
% This line can get very long.
|
|
io.format("** dependencies for `%s' do not exist: %s\n",
|
|
[s(TargetFileName), s(ErrorDepsStr)], !IO),
|
|
(
|
|
BuildDepsSucceeded = succeeded,
|
|
io.write_string("** This indicates a bug in `mmc --make'.\n", !IO)
|
|
;
|
|
BuildDepsSucceeded = did_not_succeed
|
|
).
|
|
|
|
check_dependency_timestamps(Globals, TargetFileName, MaybeTimestamp,
|
|
BuildDepsSucceeded, DepFiles, DepFileToStr, DepTimestamps,
|
|
DepsResult, !IO) :-
|
|
(
|
|
MaybeTimestamp = error(_),
|
|
DepsResult = deps_out_of_date,
|
|
debug_make_msg(Globals,
|
|
io.format("%s does not exist.\n", [s(TargetFileName)]),
|
|
!IO)
|
|
;
|
|
MaybeTimestamp = ok(Timestamp),
|
|
( if error_in_timestamps(DepTimestamps) then
|
|
DepsResult = deps_error,
|
|
WriteMissingDeps =
|
|
check_dependencies_timestamps_write_missing_deps(
|
|
TargetFileName, BuildDepsSucceeded, DepFiles,
|
|
DepFileToStr, DepTimestamps),
|
|
(
|
|
BuildDepsSucceeded = succeeded,
|
|
% Something has gone wrong -- building the target has
|
|
% succeeded, but there are some files missing.
|
|
% Report an error.
|
|
WriteMissingDeps(!IO)
|
|
;
|
|
BuildDepsSucceeded = did_not_succeed,
|
|
debug_make_msg(Globals, WriteMissingDeps, !IO)
|
|
)
|
|
else
|
|
globals.lookup_bool_option(Globals, rebuild, Rebuild),
|
|
(
|
|
Rebuild = yes,
|
|
% With `--rebuild', we always consider the target to be
|
|
% out-of-date, regardless of the timestamps of its
|
|
% dependencies.
|
|
DepsResult = deps_out_of_date
|
|
;
|
|
Rebuild = no,
|
|
( if newer_timestamp(DepTimestamps, Timestamp) then
|
|
debug_newer_dependencies(Globals, TargetFileName,
|
|
MaybeTimestamp, DepFiles, DepTimestamps, !IO),
|
|
DepsResult = deps_out_of_date
|
|
else
|
|
DepsResult = deps_up_to_date
|
|
)
|
|
)
|
|
)
|
|
).
|
|
|
|
:- pred error_in_timestamps(list(maybe_error(timestamp))::in) is semidet.
|
|
|
|
error_in_timestamps([H | T]) :-
|
|
( H = error(_)
|
|
; error_in_timestamps(T)
|
|
).
|
|
|
|
:- pred newer_timestamp(list(maybe_error(timestamp))::in, timestamp::in)
|
|
is semidet.
|
|
|
|
newer_timestamp([H | T], Timestamp) :-
|
|
(
|
|
H = ok(DepTimestamp),
|
|
compare((>), DepTimestamp, Timestamp)
|
|
;
|
|
newer_timestamp(T, Timestamp)
|
|
).
|
|
|
|
:- pred debug_newer_dependencies(globals::in, string::in,
|
|
maybe_error(timestamp)::in, list(T)::in, list(maybe_error(timestamp))::in,
|
|
io::di, io::uo) is det.
|
|
|
|
debug_newer_dependencies(Globals, TargetFileName, MaybeTimestamp,
|
|
DepFiles, DepTimestamps, !IO) :-
|
|
debug_make_msg(Globals,
|
|
debug_newer_dependencies_2(TargetFileName, MaybeTimestamp,
|
|
DepFiles, DepTimestamps),
|
|
!IO).
|
|
|
|
:- pred debug_newer_dependencies_2(string::in, maybe_error(timestamp)::in,
|
|
list(T)::in, list(maybe_error(timestamp))::in, io::di, io::uo) is det.
|
|
|
|
debug_newer_dependencies_2(TargetFileName, MaybeTimestamp,
|
|
DepFiles, DepTimestamps, !IO) :-
|
|
io.format("%s [%s]: newer dependencies:\n",
|
|
[s(TargetFileName), s(string(MaybeTimestamp))], !IO),
|
|
assoc_list.from_corresponding_lists(DepFiles, DepTimestamps,
|
|
DepTimestampAL),
|
|
list.filter(
|
|
( pred((_DepFile - MaybeDepTimestamp)::in) is semidet :-
|
|
(
|
|
MaybeDepTimestamp = error(_)
|
|
;
|
|
MaybeDepTimestamp = ok(DepTimestamp),
|
|
MaybeTimestamp = ok(Timestamp),
|
|
compare((>), DepTimestamp, Timestamp)
|
|
)
|
|
), DepTimestampAL, NewerDepsAL0),
|
|
list.sort(NewerDepsAL0, NewerDepsAL),
|
|
write_dependency_file_and_timestamp_list(NewerDepsAL, !IO).
|
|
|
|
:- pred write_dependency_file_and_timestamp_list(
|
|
assoc_list(T, maybe_error(timestamp))::in, io::di, io::uo) is det.
|
|
|
|
write_dependency_file_and_timestamp_list([], !IO).
|
|
write_dependency_file_and_timestamp_list([Head | Tail], !IO) :-
|
|
Head = DepFile - MaybeTimestamp,
|
|
io.format("\t%s %s\n",
|
|
[s(string(DepFile)), s(string(MaybeTimestamp))], !IO),
|
|
write_dependency_file_and_timestamp_list(Tail, !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- type cached_direct_imports == map(module_index, module_deps_result).
|
|
|
|
init_cached_direct_imports = map.init.
|
|
|
|
:- type cached_indirect_imports == map(module_index, module_deps_result).
|
|
|
|
init_cached_indirect_imports = map.init.
|
|
|
|
:- type cached_transitive_foreign_imports
|
|
== map(module_index, module_deps_result).
|
|
|
|
init_cached_transitive_foreign_imports = map.init.
|
|
|
|
:- type transitive_dependencies_root
|
|
---> transitive_dependencies_root(
|
|
module_index,
|
|
transitive_dependencies_type,
|
|
process_modules_where
|
|
).
|
|
|
|
:- type transitive_dependencies_type
|
|
---> interface_imports
|
|
; all_imports % every import_module and use_module
|
|
; all_dependencies. % all_imports plus every include_module
|
|
|
|
:- type process_modules_where
|
|
---> process_only_modules_in_cur_dir
|
|
% The source file for the module is in the current directory.
|
|
; process_modules_anywhere.
|
|
|
|
:- type cached_transitive_dependencies ==
|
|
map(transitive_dependencies_root, deps_result(module_index)).
|
|
|
|
init_cached_transitive_dependencies = map.init.
|
|
|
|
:- type cached_computed_module_deps ==
|
|
map(computed_module_deps_key, deps_result(dependency_file_index)).
|
|
|
|
:- type computed_module_deps_key
|
|
---> computed_module_deps_key(
|
|
module_index,
|
|
computed_module_deps_label
|
|
).
|
|
|
|
:- type computed_module_deps_label
|
|
---> computed_module_deps_import_012.
|
|
|
|
init_cached_computed_module_deps = map.init.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module make.dependencies.
|
|
%---------------------------------------------------------------------------%
|