Files
mercury/compiler/module_deps_graph.m
Zoltan Somogyi 1296ec11e5 Partially clarify and partially fix d_file_deps.
Before this diff,

- the .d filed generated by "mmc --generate-dependencies mer_std.m", and
- the .d files generated by compiling all the modules in the library

had *two*-way differences: the first set of .d files contained dependencies
that the second did not, and *vice versa*. The latter differences were bugs.
Now, as far as I can tell from the deluge of data,
"mmc --generate-dependencies" generates a superset of the dependencies
generated by code generating compiler invocations, which is a safe
overapproximation of the actual dependencies.

compiler/generate_mmakefile_fragments.m:
    Flatten the d_file_deps structure by effectively inlining the std_deps
    structure inside it, and putting the resulting fields into a meaningful
    order. Document the resulting structure as well as I can.

    Use notag types to record the intended semantics of some fields
    into their values, with the intention of making them harder to misuse.
    They were misused before this diff; in particular, a missing module
    name in one of these fields would reliably lead to the failure
    of the hard_coded/foreign_import_module test case in hlc grades,
    though only with a sequential invocation of mmake. (The bug was
    that after "mmc --generate-dependencies foreign_import_module.m",
    foreign_import_module.d was missing the dependency of
    foreign_import_module.o on foreign_import_module_helper_1.mh,
    and therefore the compilation foreign_import_module.c got a gcc abort
    complaining about this .mh file being missing. The reason for
    the bug being intermittent was that the mmc invocation that created
    foreign_import_module.c would add the missing dependency, so *later*
    mmake invocations, though not existing ones, would know
    to build that .mh file.)

    Generate rules for object files depending on .mh files that
    account for both foreign_import_module declarations, and for
    foreign type definitions. Add an XXX about the absence of the
    information we need to properly handle the latter in the presence
    of intermodule optimization.

    Generate just one rule for object files depending on .mh files,
    instead of generating two (one for the dependencies that exist
    without intermodule optimization, and for one those that exist only
    with intermodule optimization.)

    Flatten the intermod_deps structure as well. It used to have two
    components that encoded the outcomes of two *almost* identical tests,
    but a change to d_file_deps.m below makes them actually identical,
    so they do not need to be recorded twice.

    Inline the old (and misnamed) gather_foreign_import_deps predicate
    at its only call site, for greater clarity.

    Simplify the code constructing some actions.

    Use more specifically descriptive predicate and variable names.

compiler/d_file_deps.m:
    Stop requiring the caller of construct_d_file_deps_gendep to pass
    an aug_compilation_unit; get it to pass instead two of its components,
    the only ones that are meaningful and also the only ones we actually need:
    the parse_tree of the module in question and its baggage.

    Eliminate some unnecessary differences between compute_d_file_deps_gendep
    and compute_d_file_deps_hlds by replacing some existing tests for just
    --intermod-opt with tests for *either* --intermod-opt *or* --use-opt-files,
    which is the test used elsewhere for the same purpose in the rest of this
    module. The two tests are equivalent for now, because handle_options.m
    force-sets --no-use-opt-files. And even when we undo that force-set,
    the new test will actually be what we want.

    Completely redo the code that computes the dependencies that
    generate_mmakefile_fragments.m converts into the dependencies
    of object files on .mh files.

    Give some predicates more meaningful names.

compiler/mmakefiles.m:
    Add a mechanism to allow the simplification of some codes
    creating actions.

compiler/module_deps_graph.m:
    Give a type a more descriptive name.

    Document a predicate.

    Add an XXX.

compiler/make.program_target.m:
compiler/write_deps_file.m:
    Conform to the changes above.

compiler/intermod.m:
    Fix comment rot.

compiler/parse_tree_out_item.m:
    Generate more readable output for foreign_enum pragmas.

library/digraph.m:
    Put the predicates/functions of this file into meaningful groups.

    We have several operations that have two names, one old and short,
    and one newer, longer and more descriptive. Implement the short named
    versions in terms of the longer named versions, not vice versa.

    Give some internal predicates more meaningful names.

    There are no algorithmic changes in this module.

browser/Mmakefile:
    Update a comment.

scripts/mmake.in:
    Allow $MMAKE_DEBUG to specify what debug flags to invoke gmake with.
2025-08-11 10:51:29 +02:00

152 lines
6.4 KiB
Mathematica

%-----------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%-----------------------------------------------------------------------------%
% Copyright (C) 2014-2015, 2017, 2019, 2021-2022, 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: module_deps_graph.m.
%
% XXX document me.
% The contents of this module used to be in the old giant version of modules.m.
% If you want to understand it and clean it up, you will also want to look at
% deps_map.m, whose functionality seems to be quite related.
%
%-----------------------------------------------------------------------------%
:- module parse_tree.module_deps_graph.
:- interface.
:- import_module mdbcomp.
:- import_module mdbcomp.sym_name.
:- import_module parse_tree.module_dep_info.
:- import_module digraph.
%-----------------------------------------------------------------------------%
% (Module1 -> Module2) means Module1 is imported by Module2.
% XXX Actually, the add_dep predicate and its callers behave
% as if it means "Module1 *imports* Module2".
:- type deps_graph == digraph(module_name).
:- type lookup_module_dep_info_func == (func(module_name) = module_dep_info).
% add_module_dep_info_to_deps_graph(ModuleDepInfo, LookupModuleDepInfoFunc,
% !IntDepsGraph, !ImpDepsGraph)
%
:- pred add_module_dep_info_to_deps_graph(module_dep_info::in,
lookup_module_dep_info_func::in,
deps_graph::in, deps_graph::out, deps_graph::in, deps_graph::out) is det.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module set.
:- type deps_graph_key == digraph_key(module_name).
%-----------------------------------------------------------------------------%
add_module_dep_info_to_deps_graph(ModuleDepInfo, LookupModuleDepInfoFunc,
!IntDepsGraph, !ImpDepsGraph) :-
% Add interface dependencies to the interface deps graph.
%
% Note that we need to do this both for the interface imports of this
% module and for the *implementation* imports of its ancestors.
% This is because if this module is defined in the implementation section
% of its parent, then the interface of this module may depend on things
% imported only by its parent's implementation.
%
% If this module was actually defined in the interface section of one
% of its ancestors, then it should only depend on the interface imports
% of that ancestor, so the dependencies added here are in fact more
% conservative than they need to be in that case. However, that should
% not be a major problem.
% XXX Actually, I (zs) think it is, because I suspect that after some
% source code changes, it can lead to the unnecessary recompilation
% of not just a few, but many modules.
module_dep_info_get_module_name(ModuleDepInfo, ModuleName),
Ancestors = get_ancestors_set(ModuleName),
digraph.add_vertex(ModuleName, IntModuleKey, !IntDepsGraph),
add_int_deps(IntModuleKey, ModuleDepInfo, !IntDepsGraph),
add_parent_imp_deps_set(LookupModuleDepInfoFunc, IntModuleKey, Ancestors,
!IntDepsGraph),
% Add implementation dependencies to the implementation deps graph.
% (The implementation dependencies are a superset of the interface
% dependencies.)
%
% Note that we need to do this both for the imports of this module
% and for the imports of its parents, because this module may depend on
% things imported only by its parents.
digraph.add_vertex(ModuleName, ImpModuleKey, !ImpDepsGraph),
add_imp_deps(ImpModuleKey, ModuleDepInfo, !ImpDepsGraph),
add_parent_imp_deps_set(LookupModuleDepInfoFunc, ImpModuleKey, Ancestors,
!ImpDepsGraph).
% Add interface dependencies to the interface deps graph.
%
:- pred add_int_deps(deps_graph_key::in, module_dep_info::in,
deps_graph::in, deps_graph::out) is det.
add_int_deps(ModuleKey, ModuleDepInfo, !DepsGraph) :-
AddDep = add_dep(ModuleKey),
module_dep_info_get_module_name(ModuleDepInfo, ModuleName),
Ancestors = get_ancestors_set(ModuleName),
module_dep_info_get_int_deps(ModuleDepInfo, IntDeps),
set.fold(AddDep, Ancestors, !DepsGraph),
set.fold(AddDep, IntDeps, !DepsGraph).
% Add direct implementation dependencies for a module to the
% implementation deps graph.
%
:- pred add_imp_deps(deps_graph_key::in, module_dep_info::in,
deps_graph::in, deps_graph::out) is det.
add_imp_deps(ModuleKey, ModuleDepInfo, !DepsGraph) :-
% The implementation dependencies are a superset of the
% interface dependencies, so first we add the interface deps, ...
add_int_deps(ModuleKey, ModuleDepInfo, !DepsGraph),
% ... and then we add the implementation deps.
module_dep_info_get_imp_deps(ModuleDepInfo, ImpDeps),
set.foldl(add_dep(ModuleKey), ImpDeps, !DepsGraph).
% Add parent implementation dependencies for the given Parent module
% to the implementation deps graph values for the given ModuleKey.
%
:- pred add_parent_imp_deps(lookup_module_dep_info_func::in,
deps_graph_key::in, module_name::in, deps_graph::in, deps_graph::out)
is det.
add_parent_imp_deps(LookupModuleDepInfoFunc, ModuleKey, Parent, !DepsGraph) :-
ParentModuleDepInfo = LookupModuleDepInfoFunc(Parent),
add_imp_deps(ModuleKey, ParentModuleDepInfo, !DepsGraph).
:- pred add_parent_imp_deps_set(lookup_module_dep_info_func::in,
deps_graph_key::in, set(module_name)::in, deps_graph::in, deps_graph::out)
is det.
add_parent_imp_deps_set(LookupModuleDepInfoFunc, ModuleKey, Parents,
!DepsGraph) :-
set.fold(add_parent_imp_deps(LookupModuleDepInfoFunc, ModuleKey), Parents,
!DepsGraph).
% Add a single dependency to a graph.
%
:- pred add_dep(digraph_key(T)::in, T::in, digraph(T)::in, digraph(T)::out)
is det.
add_dep(ModuleKey, Dep, !DepsGraph) :-
digraph.add_vertex(Dep, DepKey, !DepsGraph),
digraph.add_edge(ModuleKey, DepKey, !DepsGraph).
%-----------------------------------------------------------------------------%
:- end_module parse_tree.module_deps_graph.
%-----------------------------------------------------------------------------%