Files
mercury/compiler/find_module.m
Zoltan Somogyi bb1a06db96 Do not use dummy burdened_modules.
compiler/deps_map.m:
    When we couldn't read a file during the computation of dependencies,
    we used to add a dummy burdened_module to the deps_map. This never
    really made sense, so stop doing that.

    Delete the maybe_dummy_burdened_module flags from entries in the deps_map.
    They are no longer needed, since we no longer add dummy burdened modules
    to the deps_map.

compiler/generate_dep_d_files.m:
compiler/generate_mmakefile_fragments.m:
compiler/mercury_compile_main.m:
compiler/write_deps_file.m:
    Conform to the changes above.

    In one case, delete a comment that has been obsolete for a while.

compiler/find_module.m:
    If a purpose-specific environment variable is set, then change the error
    message we generate for not being able to find a file to a form that is
    independent of the pathname of the current directory.

    An only slightly related change: deal with the failure of a loop over
    a list of search directories to find a file *outside the loop*, not
    in its base case. The base case code is shorter, but it requires strange
    code (passing the same parameter twice to the same callee) that violates
    the law of least astonishment.

tests/invalid_make_int/Mmakefile:
    Execute the multi-module test cases in this directory with that environment
    variable set, so that the sub_c test case can have a working .int_err_exp
    file.

    Clean up some more files between bootchecks.

tests/invalid_make_int/sub_c.int_err_exp:
    Expect a message about not being able to read a file. That file does
    not exist because the dependency that would have caused it to be built
    is missing from the code of sub_c.m, and the handling of that absence
    is one of things that this test case is for.

    We expect the message now because it was the presence of the dummy
    burdened_module representation of the missing file that has been
    blocking the generation of that diagnostic until now.
2025-01-26 00:25:05 +11:00

681 lines
28 KiB
Mathematica

%-----------------------------------------------------------------------------e
% vim: ft=mercury ts=4 sw=4 et
%-----------------------------------------------------------------------------e
% Copyright (C) 1993-2012 The University of Melbourne.
% Copyright (C) 2014-2017, 2019-2020, 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.
%---------------------------------------------------------------------------%
%
% This module defines predicates that find Mercury modules.
%
%---------------------------------------------------------------------------%
:- module parse_tree.find_module.
:- interface.
:- import_module libs.
:- import_module libs.file_util.
:- import_module libs.globals.
:- import_module libs.options.
:- import_module mdbcomp.
:- import_module mdbcomp.sym_name.
:- import_module io.
:- import_module list.
:- import_module maybe.
:- import_module time.
%---------------------------------------------------------------------------%
:- type path_name_and_stream
---> path_name_and_stream(file_name, io.text_input_stream).
% The string is a file name.
:- type dir_name_and_stream
---> dir_name_and_stream(dir_name, io.text_input_stream).
% The string is a dir name.
:- type dir_name_and_contents
---> dir_name_and_contents(dir_name, string).
% The first string is a dir name.
% The second string is the contents of the file.
%---------------------%
% The search_auth_dirs type represents a "search authorization",
% in the sense that it says "it makes sense to search for the associated
% file name in the directories it specifies".
%
% Searching in the current directory, and in a user-specified directory,
% requires no special permission, so the first four values of this type
% (modulo the tail dirs) can be constructed by code in any compiler module.
% The private ones should be constructed *only*
%
% - by the module_name_to_search_file_name predicate in file_names.m,
% which checks the compatibility between the file's extension and the
% specification of the directories to be searched, and
%
% - by the get_search_auth_* functions below. Note that ascertaining
% whether their callers pair them sensibly with the file names
% to be searched for requires inspecting each one separately.
%
% Any file name reported by "grep -l private_auth *.m" *other than*
% file_names.m and find_module.m represents a violation of this rule.
%
% The *point* of such authorizations is to centralize the lookup
% of options representing lists of directories to search in this module,
% and specifically in the compute_search_dirs predicate. This
% centralization makes it feasible to replace the existing set of options,
% which require users to specify more than one directory in e.g. an
% installed library (e.g. both the non-grade-specific and the
% grade-specific location containing files with the same extension),
% with a new set of options that do not require such duplication.
:- type search_auth_dirs
---> search_auth_cur_dir
; search_auth_cur_dir_and(search_auth_tail_dirs)
% XXX LEGACY All existing uses of search_auth_cur_dir_and take
% the list of tail directories from the value of an option.
% All these uses should be replaced by code in handle_options.m
% that includes the current directory in the value of that option.
% However, there is no point in doing this for the LEGACY searches,
% and doing it for PROPOSED searches will be much easier once
% we no longer support LEGACY searches.
; search_auth_this_dir(dir_name)
; search_auth_this_dir_and(dir_name, search_auth_tail_dirs)
; search_auth_private(search_auth_private_dirs).
:- type search_auth_private_dirs
---> private_auth_interface_dirs(interface_ext, globals)
; private_auth_intermod_dirs(intermod_ext, globals)
; private_auth_c_include_dirs(c_incl_ext, globals)
; private_auth_options_file_dirs(option_table)
; private_auth_lib_dirs(lib_ext, globals)
; private_auth_stdlib_dirs(stdlib_ext, globals).
% search_which_tail_dirs/search_auth_private_tail_dirs together
% differ from search_auth_dirs/search_auth_private_dirs the same way
% as search_which_tail_dirs differs from search_which_dirs.
%
:- type search_auth_tail_dirs =< search_auth_dirs
---> search_auth_cur_dir
; search_auth_private(search_auth_private_tail_dirs).
:- type search_auth_private_tail_dirs =< search_auth_private_dirs
---> private_auth_interface_dirs(interface_ext, globals)
; private_auth_intermod_dirs(intermod_ext, globals)
; private_auth_c_include_dirs(c_incl_ext, globals)
; private_auth_options_file_dirs(option_table).
:- func get_search_auth_interface_dirs(interface_ext, globals)
= search_auth_dirs.
:- func get_search_auth_intermod_dirs(intermod_ext, globals)
= search_auth_dirs.
:- func get_search_auth_options_file_dirs(option_table)
= search_auth_tail_dirs.
:- func get_search_auth_lib_dirs(lib_ext, globals)
= search_auth_dirs.
:- func get_search_auth_stdlib_dirs(stdlib_ext, globals)
= search_auth_dirs.
%---------------------%
% search_for_file(SearchAuthDirs, FileName,
% SearchDirs, MaybeFilePathName, !IO):
%
% Search the specified directories for FileName. If found,
% return the path name of the file. We also return the list of directories
% we searched as SearchDirs, for possible use in error messages.
%
% NB. Consider using search_for_file_returning_dir, which does not
% canonicalise the path, and is therefore more efficient.
%
:- pred search_for_file(search_auth_dirs::in, file_name::in,
list(dir_name)::out, maybe_error(file_name)::out, io::di, io::uo) is det.
% search_for_file_and_stream(SearchAuthDirs, FileName,
% SearchDirs, MaybeFilePathNameAndStream, !IO):
%
% Search the specified directories for FileName. If found,
% return the path name of the file and an open input stream
% reading from that file. Closing that stream is the caller's
% responsibility.
%
% NB. Consider using search_for_file_returning_dir_and_stream,
% which does not canonicalise the path, and is therefore more efficient.
%
:- pred search_for_file_and_stream(search_auth_dirs::in, file_name::in,
list(dir_name)::out, maybe_error(path_name_and_stream)::out,
io::di, io::uo) is det.
%---------------------%
% search_for_file_returning_dir(SearchAuthDirs, FileName,
% SearchDirs, MaybeDirName, !IO):
%
% Search the specified directories for FileName. If found,
% return the name of the directory in which the file was found.
%
:- pred search_for_file_returning_dir(search_auth_dirs::in, file_name::in,
list(dir_name)::out, maybe_error(dir_name)::out, io::di, io::uo) is det.
% search_for_file_returning_dir_and_stream(SearchAuthDirs, FileName,
% SearchDirs, MaybeDirNameAndStream, !IO):
%
% Search the specified directory for FileName. If found,
% return the name of the directory in which the file was found,
% and an open input stream reading from that file. Closing that stream
% is the caller's responsibility.
%
:- pred search_for_file_returning_dir_and_stream(search_auth_dirs::in,
file_name::in, list(dir_name)::out,
maybe_error(path_name_and_stream)::out, io::di, io::uo) is det.
% search_for_file_returning_dir_and_contents(SearchAuthDirs, FileName,
% SearchDirs, MaybeDirNameAndContents, !IO):
%
% Search the specified directories for FileName. If found,
% return the name of the directory in which the file was found,
% and the contents of the file as a string.
%
:- pred search_for_file_returning_dir_and_contents(search_auth_dirs::in,
file_name::in, list(dir_name)::out,
maybe_error(dir_name_and_contents)::out, io::di, io::uo) is det.
%---------------------%
% search_for_file_mod_time(SearchAuthDirs, FileName,
% SearchDirs, MaybeModTime, !IO)
%
% Search the specified directories for FileName. If found,
% return the last modification time of the file that was found.
% Do NOT open the file for reading.
%
:- pred search_for_file_mod_time(search_auth_dirs::in, file_name::in,
list(dir_name)::out, maybe_error(time_t)::out, io::di, io::uo) is det.
%---------------------------------------------------------------------------%
% search_for_module_source(SearchAuthDirs, ModuleName,
% SearchDirs, FoundSourceFile, !IO):
%
% Search the specified directories for the source code of ModuleName.
% If found, return the (relative or absolute) path name of the
% source file that contains the module.
%
:- pred search_for_module_source(search_auth_dirs::in, module_name::in,
list(dir_name)::out, maybe_error(file_name)::out, io::di, io::uo) is det.
% search_for_module_source_and_stream(SearchAuthDirs, ModuleName,
% SearchDirs, FoundSourceFileNameAndStream, !IO):
%
% As search_for_module_source, but if we find the file, then return
% not just its path name, but also an open stream reading from it.
% Closing that stream is the caller's responsibility.
%
:- pred search_for_module_source_and_stream(search_auth_dirs::in,
module_name::in, list(dir_name)::out,
maybe_error(path_name_and_stream)::out, io::di, io::uo) is det.
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
:- implementation.
:- import_module parse_tree.file_names.
:- import_module dir.
:- import_module getopt.
:- import_module io.environment.
:- import_module io.file.
:- import_module map.
:- import_module string.
%---------------------------------------------------------------------------%
get_search_auth_interface_dirs(InterfaceExt, Globals) =
search_auth_private(private_auth_interface_dirs(InterfaceExt, Globals)).
get_search_auth_intermod_dirs(IntermodExt, Globals) =
search_auth_private(private_auth_intermod_dirs(IntermodExt, Globals)).
get_search_auth_options_file_dirs(OptionTable) =
search_auth_private(private_auth_options_file_dirs(OptionTable)).
get_search_auth_lib_dirs(LibExt, Globals) =
search_auth_private(private_auth_lib_dirs(LibExt, Globals)).
get_search_auth_stdlib_dirs(StdLibExt, Globals) =
search_auth_private(private_auth_stdlib_dirs(StdLibExt, Globals)).
%---------------------------------------------------------------------------%
search_for_file(SearchAuthDirs, FileName,
SearchDirs, MaybeFilePathName, !IO) :-
search_for_file_and_stream(SearchAuthDirs, FileName,
SearchDirs, MaybeFilePathNameAndStream, !IO),
(
MaybeFilePathNameAndStream =
ok(path_name_and_stream(FilePathName, Stream)),
io.close_input(Stream, !IO),
MaybeFilePathName = ok(FilePathName)
;
MaybeFilePathNameAndStream = error(Msg),
MaybeFilePathName = error(Msg)
).
search_for_file_and_stream(SearchAuthDirs, FileName,
SearchDirs, Result, !IO) :-
compute_search_dirs(SearchAuthDirs, SearchDirs),
search_for_file_and_stream_loop(SearchDirs, FileName,
MaybeFilePathNameAndStream, !IO),
(
MaybeFilePathNameAndStream = no,
cannot_find_in_dirs_msg(FileName, SearchDirs, Msg, !IO),
Result = error(Msg)
;
MaybeFilePathNameAndStream = yes(FilePathNameAndStream),
Result = ok(FilePathNameAndStream)
).
:- pred search_for_file_and_stream_loop(list(dir_name)::in, file_name::in,
maybe(path_name_and_stream)::out, io::di, io::uo) is det.
search_for_file_and_stream_loop(Dirs, FileName,
MaybeFilePathNameAndStream, !IO) :-
(
Dirs = [],
MaybeFilePathNameAndStream = no
;
Dirs = [HeadDir | TailDirs],
make_path_name_noncanon(HeadDir, FileName, HeadFilePathNameNC),
io.open_input(HeadFilePathNameNC, MaybeHeadStream, !IO),
(
MaybeHeadStream = ok(HeadStream),
% HeadFilePathName should be a canonical version of
% HeadFilePathNameNC.
( if dir.this_directory(HeadDir) then
HeadFilePathName = FileName
else
HeadFilePathName = dir.make_path_name(HeadDir, FileName)
),
MaybeFilePathNameAndStream =
yes(path_name_and_stream(HeadFilePathName, HeadStream))
;
MaybeHeadStream = error(_),
search_for_file_and_stream_loop(TailDirs, FileName,
MaybeFilePathNameAndStream, !IO)
)
).
%---------------------%
search_for_file_returning_dir(SearchAuthDirs, FileName,
SearchDirs, MaybeDirPathName, !IO) :-
search_for_file_returning_dir_and_stream(SearchAuthDirs, FileName,
SearchDirs, MaybeDirPathNameAndStream, !IO),
(
MaybeDirPathNameAndStream =
ok(path_name_and_stream(DirPathName, Stream)),
io.close_input(Stream, !IO),
MaybeDirPathName = ok(DirPathName)
;
MaybeDirPathNameAndStream = error(Msg),
MaybeDirPathName = error(Msg)
).
search_for_file_returning_dir_and_stream(SearchAuthDirs, FileName,
SearchDirs, Result, !IO) :-
compute_search_dirs(SearchAuthDirs, SearchDirs),
search_for_file_returning_dir_and_stream_loop(SearchDirs, FileName,
MaybeFilePathNameAndStream, !IO),
(
MaybeFilePathNameAndStream = no,
cannot_find_in_dirs_msg(FileName, SearchDirs, Msg, !IO),
Result = error(Msg)
;
MaybeFilePathNameAndStream = yes(FilePathNameAndStream),
Result = ok(FilePathNameAndStream)
).
:- pred search_for_file_returning_dir_and_stream_loop(list(dir_name)::in,
file_name::in, maybe(path_name_and_stream)::out, io::di, io::uo) is det.
search_for_file_returning_dir_and_stream_loop(Dirs, FileName,
MaybeDirNameAndStream, !IO) :-
(
Dirs = [],
MaybeDirNameAndStream = no
;
Dirs = [HeadDir | TailDirs],
make_path_name_noncanon(HeadDir, FileName, HeadFilePathNameNC),
io.open_input(HeadFilePathNameNC, MaybeHeadStream, !IO),
(
MaybeHeadStream = ok(HeadStream),
MaybeDirNameAndStream =
yes(path_name_and_stream(HeadDir, HeadStream))
;
MaybeHeadStream = error(_),
search_for_file_returning_dir_and_stream_loop(TailDirs, FileName,
MaybeDirNameAndStream, !IO)
)
).
%---------------------%
search_for_file_returning_dir_and_contents(SearchAuthDirs, FileName,
SearchDirs, Result, !IO) :-
compute_search_dirs(SearchAuthDirs, SearchDirs),
search_for_file_returning_dir_and_contents_loop(SearchDirs, FileName,
MaybeDirPathNameAndContents, !IO),
(
MaybeDirPathNameAndContents = no,
cannot_find_in_dirs_msg(FileName, SearchDirs, Msg, !IO),
Result = error(Msg)
;
MaybeDirPathNameAndContents = yes(DirPathNameAndContents),
Result = ok(DirPathNameAndContents)
).
:- pred search_for_file_returning_dir_and_contents_loop(list(dir_name)::in,
file_name::in, maybe(dir_name_and_contents)::out, io::di, io::uo) is det.
search_for_file_returning_dir_and_contents_loop(Dirs, FileName,
MaybeDirNameAndContents, !IO) :-
(
Dirs = [],
MaybeDirNameAndContents = no
;
Dirs = [HeadDir | TailDirs],
make_path_name_noncanon(HeadDir, FileName, HeadFilePathNameNC),
io.read_named_file_as_string_wf(HeadFilePathNameNC,
MaybeHeadContents, !IO),
(
MaybeHeadContents = ok(HeadContents),
MaybeDirNameAndContents =
yes(dir_name_and_contents(HeadDir, HeadContents))
;
MaybeHeadContents = error(_),
search_for_file_returning_dir_and_contents_loop(TailDirs, FileName,
MaybeDirNameAndContents, !IO)
)
).
%---------------------%
search_for_file_mod_time(SearchAuthDirs, FileName, SearchDirs, Result, !IO) :-
compute_search_dirs(SearchAuthDirs, SearchDirs),
search_for_file_mod_time_loop(SearchDirs, FileName, MaybeModTime, !IO),
(
MaybeModTime = no,
cannot_find_in_dirs_msg(FileName, SearchDirs, Msg, !IO),
Result = error(Msg)
;
MaybeModTime = yes(ModTime),
Result = ok(ModTime)
).
:- pred search_for_file_mod_time_loop(list(dir_name)::in, file_name::in,
maybe(time_t)::out, io::di, io::uo) is det.
search_for_file_mod_time_loop(Dirs, FileName, MaybeModTime, !IO) :-
(
Dirs = [],
MaybeModTime = no
;
Dirs = [HeadDir | TailDirs],
make_path_name_noncanon(HeadDir, FileName, HeadFilePathNameNC),
io.file.file_modification_time(HeadFilePathNameNC,
MaybeHeadModTime, !IO),
(
MaybeHeadModTime = ok(HeadModTime),
MaybeModTime = yes(HeadModTime)
;
MaybeHeadModTime = error(_),
search_for_file_mod_time_loop(TailDirs, FileName,
MaybeModTime, !IO)
)
).
%---------------------%
:- pred cannot_find_in_dirs_msg(file_name::in, list(dir_name)::in, string::out,
io::di, io::uo) is det.
cannot_find_in_dirs_msg(FileName, Dirs, Msg, !IO) :-
% This environment variable is the mechanism we use in the invalid_make_int
% test directory to ensure that the output generated by the compiler
% does NOT depend on the exact pathnames in Dirs.
%
% The cost of looking up this environment variable is negligible compared
% to the cost of trying the find the file.
io.environment.get_environment_var("MERCURY_NO_PATHS_IN_CANNOT_FIND_MSG",
MaybeEnvVarValue, !IO),
( if
MaybeEnvVarValue = yes(EnvVarValue),
EnvVarValue \= ""
then
% We include a period at the end of this message because
% MERCURY_NO_PATHS_IN_CANNOT_FIND_MSG is intended to be set
% only for test cases in tests/invalid_make_int, and for those,
% this is the right output.
string.format("cannot find `%s' in the search path.",
[s(FileName)], Msg)
else
% We do not include a period at the end of these messages
% because they may end up being returned to the
% error_and_maybe_rebuilding_msg predicate in
% make.get_module_dep_info.m. All other places in the compiler
% that get these message want to print them at the end of a sentence,
% but that predicate may decide to add a "...rebuilding" suffix.
% The callers that want to add periods after Msg will do so.
% (Actually, while some do, and do not want to, there are some
% in which a period would look better, but is not added.)
(
Dirs = [],
string.format("cannot find `%s' in the empty list of directories",
[s(FileName)], Msg)
;
Dirs = [SingleDir],
string.format("cannot find `%s' in directory `%s'",
[s(FileName), s(SingleDir)], Msg)
;
Dirs = [_, _ | _],
WrapInQuotes = (func(N) = "`" ++ N ++ "'"),
DirsStr = string.join_list(", ", list.map(WrapInQuotes, Dirs)),
string.format("cannot find `%s' in directories %s",
[s(FileName), s(DirsStr)], Msg)
)
).
:- pred make_path_name_noncanon(dir_name::in, file_name::in, file_name::out)
is det.
make_path_name_noncanon(Dir, FileName, PathName) :-
( if dir.this_directory(Dir) then
PathName = FileName
else
% dir.make_path_name is slow so we avoid it when path names don't
% need to be canonicalised.
Sep = string.from_char(dir.directory_separator),
PathName = string.append_list([Dir, Sep, FileName])
).
%---------------------------------------------------------------------------%
search_for_module_source(SearchAuthDirs, ModuleName,
SearchDirs, MaybeFileName, !IO) :-
search_for_module_source_and_stream(SearchAuthDirs, ModuleName,
SearchDirs, MaybeFileNameAndStream, !IO),
(
MaybeFileNameAndStream =
ok(path_name_and_stream(SourceFileName, SourceStream)),
io.close_input(SourceStream, !IO),
MaybeFileName = ok(SourceFileName)
;
MaybeFileNameAndStream = error(Msg),
MaybeFileName = error(Msg)
).
search_for_module_source_and_stream(SearchAuthDirs, ModuleName,
SearchDirs, MaybeFileNameAndStream, !IO) :-
module_name_to_source_file_name(ModuleName, FileName0, !IO),
search_for_file_and_stream(SearchAuthDirs, FileName0,
SearchDirs, MaybeFileNameAndStream0, !IO),
(
MaybeFileNameAndStream0 = ok(_),
MaybeFileNameAndStream = MaybeFileNameAndStream0
;
MaybeFileNameAndStream0 = error(_),
Error = find_source_error(ModuleName, SearchDirs, no),
MaybeFileNameAndStream = error(Error)
).
%------------%
:- func find_source_error(module_name, list(dir_name), maybe(file_name))
= string.
find_source_error(ModuleName, Dirs, MaybeBetterMatch) = Msg :-
ModuleNameStr = sym_name_to_string(ModuleName),
WrapInQuotes = (func(N) = "`" ++ N ++ "'"),
DirsStr = string.join_list(", ", list.map(WrapInQuotes, Dirs)),
string.format("cannot find source for module `%s' in directories %s",
[s(ModuleNameStr), s(DirsStr)], Msg0),
(
MaybeBetterMatch = no,
Msg = Msg0
;
MaybeBetterMatch = yes(BetterMatchFile),
string.format("%s, but found `%s' in interface search path",
[s(Msg0), s(BetterMatchFile)], Msg)
).
%---------------------------------------------------------------------------%
:- pred compute_search_dirs(search_auth_dirs::in, list(dir_name)::out) is det.
compute_search_dirs(SearchAuthDirs, Dirs) :-
% NOTE This code operates on the option settings set up by
% handle_directory_options in handle_options.m, and by the predicates
% option_table_add_mercury_library_directory and
% option_table_add_search_library_files_directory in options.m.
% These set things up for searches in LEGACY installed libraries.
% Switching over to the PROPOSED install directory structure
% will require changes there as well as here.
%
% The code of check_stdlib_is_installed in check_libgrades.m also knows
% the install structure. It should be updated to use the facilities
% of this module to do its test, or, failing that, it will also need
% to be updated to use the PROPOSED structure.
(
SearchAuthDirs = search_auth_cur_dir,
dir.this_directory(Dir),
Dirs = [Dir]
;
SearchAuthDirs = search_auth_this_dir(Dir),
Dirs = [Dir]
;
(
SearchAuthDirs = search_auth_cur_dir_and(TailSearchAuthDirs),
dir.this_directory(Dir)
;
SearchAuthDirs = search_auth_this_dir_and(Dir, TailSearchAuthDirs)
),
compute_search_dirs(coerce(TailSearchAuthDirs), TailDirs0),
% XXX We could replace this with just Dirs = TailDirs0.
% The question is: should Dir always precede TailDirs0,
% or should it be in the position given by TailSearchAuthDirs?
% Most of the time, Dir will be at the start of TailDirs0,
% so this may not matter, but I (zs) don't know whether
% we can rely on that.
( if list.delete_first(TailDirs0, Dir, TailDirs) then
Dirs = [Dir | TailDirs]
else
Dirs = [Dir | TailDirs0]
)
;
SearchAuthDirs = search_auth_private(SearchAuthPrivateDirs),
% The switchover from the LEGACY library install structure
% to its PROPOSED version will also be a period of switchover
% from the old options specifying search dirs to the new options.
% Given a program P that uses library L1, which in turn uses
% library L2, one should switch over P first, then L1, and then L2,
% with the general rule being if entity (program or library) E1
% uses entity E2, then we switch over E1 first. The value we
% assign to Dirs is designed to work for this approach.
(
SearchAuthPrivateDirs =
private_auth_interface_dirs(InterfaceExt, Globals),
globals.get_ext_dirs_maps(Globals, ExtDirsMaps),
InterfaceDirsMap = ExtDirsMaps ^ edm_interface,
map.lookup(InterfaceDirsMap, InterfaceExt, ProposedDirs),
globals.lookup_accumulating_option(Globals,
search_directories, LegacyDirs),
Dirs = ProposedDirs ++ LegacyDirs
;
SearchAuthPrivateDirs =
private_auth_intermod_dirs(IntermodExt, Globals),
globals.get_ext_dirs_maps(Globals, ExtDirsMaps),
IntermodDirsMap = ExtDirsMaps ^ edm_intermod,
map.lookup(IntermodDirsMap, IntermodExt, ProposedDirs),
globals.lookup_accumulating_option(Globals,
intermod_directories, LegacyDirs),
Dirs = ProposedDirs ++ LegacyDirs
;
SearchAuthPrivateDirs =
private_auth_c_include_dirs(CInclExt, Globals),
globals.get_ext_dirs_maps(Globals, ExtDirsMaps),
CInclDirsMap = ExtDirsMaps ^ edm_c_incl,
map.lookup(CInclDirsMap, CInclExt, ProposedDirs),
globals.lookup_accumulating_option(Globals,
c_include_directories, LegacyDirs),
Dirs = ProposedDirs ++ LegacyDirs
;
SearchAuthPrivateDirs =
private_auth_options_file_dirs(OptionTable),
% Since options files are never installed, the difference
% between the Proposed vs Legacy library install directory
% structures does not affect this kind of lookup.
getopt.lookup_accumulating_option(OptionTable,
options_search_directories, Dirs)
;
SearchAuthPrivateDirs = private_auth_lib_dirs(LibExt, Globals),
globals.get_ext_dirs_maps(Globals, ExtDirsMaps),
LibDirsMap = ExtDirsMaps ^ edm_lib,
map.lookup(LibDirsMap, LibExt, ProposedDirs),
globals.get_grade_dir(Globals, GradeDir),
globals.lookup_accumulating_option(Globals,
mercury_library_directories, LibDirs),
LegacyDirs =
list.map((func(LibDir) = LibDir / "lib" / GradeDir), LibDirs),
Dirs = ProposedDirs ++ LegacyDirs
;
SearchAuthPrivateDirs =
private_auth_stdlib_dirs(StdLibExt, Globals),
globals.get_ext_dirs_maps(Globals, ExtDirsMaps),
StdLibDirsMap = ExtDirsMaps ^ edm_stdlib,
map.lookup(StdLibDirsMap, StdLibExt, ProposedDirs),
(
StdLibExt = sle_init,
globals.lookup_accumulating_option(Globals,
init_file_directories, LegacyDirs)
;
( StdLibExt = sle_jar
; StdLibExt = sle_dll
),
globals.get_grade_dir(Globals, GradeDir),
globals.lookup_accumulating_option(Globals,
mercury_library_directories, LibDirs),
LegacyDirs =
list.map((func(LibDir) = LibDir / "lib" / GradeDir),
LibDirs)
),
Dirs = ProposedDirs ++ LegacyDirs
)
).
%---------------------------------------------------------------------------%
:- end_module parse_tree.find_module.
%---------------------------------------------------------------------------%