mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-16 09:53:36 +00:00
compiler/error_spec.m:
This new module contains the part of the old error_util.m that defines
the error_spec type, and some functions that can help construct pieces
of error_specs. Most modules of the compiler that deal with errors
will need to import only this part of the old error_util.m.
This change also renames the format_component type to format_piece,
which matches our long-standing naming convention for variables containing
(lists of) values of this type.
compiler/write_error_spec.m:
This new module contains the part of the old error_util.m that
writes out error specs, and converts them to strings.
This diff marks as obsolete the versions of predicates that
write out error specs to the current output stream, without
*explicitly* specifying the intended stream.
compiler/error_sort.m:
This new module contains the part of the old error_util.m that
sorts lists of error specs and error msgs.
compiler/error_type_util.m:
This new module contains the part of the old error_util.m that
convert types to format_pieces that generate readable output.
compiler/parse_tree.m:
compiler/notes/compiler_design.html:
Include and document the new modules.
compiler/error_util.m:
The code remaining in the original error_util.m consists of
general utility predicates and functions that don't fit into
any of the modules above.
Delete an unneeded pair of I/O states from the argument list
of a predicate.
compiler/file_util.m:
Move the unable_to_open_file predicate here from error_util.m,
since it belongs here. Mark another predicate that writes
to the current output stream as obsolete.
compiler/hlds_error_util.m:
Mark two predicates that wrote out error_spec to the current output
stream as obsolete, and add versions that take an explicit output stream.
compiler/Mercury.options:
Compile the modules that call the newly obsoleted predicates
with --no-warn-obsolete, for the time being.
compiler/*.m:
Conform to the changes above, mostly by updating import_module
declarations, and renaming format_component to format_piece.
417 lines
16 KiB
Mathematica
417 lines
16 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 2008-2009 The University of Melbourne.
|
|
% Copyright (C) 2015-2016, 2019 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 checks if all the Mercury libraries needed to build a target
|
|
% are installed in the required grade.
|
|
%
|
|
% XXX The maybe_check_libraries_are_installed predicate has always been
|
|
% in this module, while the other exported predicates and their supporting
|
|
% code have been moved here relatively recently. It should be possible
|
|
% to factor out code that is common to both of these halves of this module,
|
|
% but this has not yet been done.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module libs.check_libgrades.
|
|
:- interface.
|
|
|
|
:- import_module libs.globals.
|
|
:- import_module make.
|
|
:- import_module make.options_file.
|
|
:- import_module parse_tree.
|
|
:- import_module parse_tree.error_spec.
|
|
:- import_module parse_tree.maybe_error.
|
|
|
|
:- import_module io.
|
|
:- import_module list.
|
|
:- import_module set.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred maybe_detect_stdlib_grades(globals::in, options_variables::in,
|
|
maybe1(set(string))::out, list(string)::out, io::di, io::uo) is det.
|
|
|
|
% Where is the Mercury standard library?
|
|
%
|
|
% NOTE: A standard library directory specified on the command line
|
|
% overrides one set using the MERCURY_STDLIB_DIR variable.
|
|
%
|
|
:- pred find_mercury_stdlib(globals::in, options_variables::in,
|
|
maybe1(string)::out, io::di, io::uo) is det.
|
|
|
|
:- pred do_detect_libgrades(string::in, set(string)::out,
|
|
io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% If --libgrade-install-check is enabled, then check that all Mercury
|
|
% libraries required by the target are installed in the selected grade.
|
|
% Always succeeds if --libgrade-install-check is *not* enabled.
|
|
%
|
|
:- pred maybe_check_libraries_are_installed(globals::in, list(error_spec)::out,
|
|
io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module libs.compute_grade.
|
|
:- import_module libs.file_util.
|
|
:- import_module libs.options.
|
|
:- import_module parse_tree.find_module.
|
|
|
|
:- import_module bool.
|
|
:- import_module dir.
|
|
:- import_module io.file.
|
|
:- import_module maybe.
|
|
:- import_module string.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
maybe_detect_stdlib_grades(Globals, Variables,
|
|
MaybeStdlibGrades, StdlibGradeOpts, !IO) :-
|
|
% Enable the compile-time trace flag "debug-detect-libgrades" to enable
|
|
% debugging messages for library grade detection in the very verbose
|
|
% output.
|
|
globals.lookup_bool_option(Globals, detect_libgrades, Detect),
|
|
(
|
|
Detect = yes,
|
|
io.stdout_stream(StdOut, !IO),
|
|
globals.lookup_bool_option(Globals, verbose, Verbose),
|
|
trace [io(!TIO), compile_time(flag("debug-detect-libgrades"))] (
|
|
maybe_write_string(StdOut, Verbose,
|
|
"% Detecting library grades ...\n", !TIO)
|
|
),
|
|
find_mercury_stdlib(Globals, Variables, MaybeMerStdLibDir, !IO),
|
|
% If we cannot find the Mercury standard library directory,
|
|
% we return the error message(s) explaining the reason for that
|
|
% in MaybeStdlibGrades, which one our caller pays attention to,
|
|
% but NOT in StdlibGradeOpts, which is for another of our callers.
|
|
(
|
|
MaybeMerStdLibDir = ok1(MerStdLibDir),
|
|
do_detect_libgrades(MerStdLibDir, StdlibGrades, !IO),
|
|
MaybeStdlibGrades = ok1(StdlibGrades)
|
|
;
|
|
MaybeMerStdLibDir = error1(Specs),
|
|
MaybeStdlibGrades = error1(Specs),
|
|
set.init(StdlibGrades)
|
|
),
|
|
trace [io(!TIO), compile_time(flag("debug-detect-libgrades"))] (
|
|
(
|
|
Verbose = yes,
|
|
set.fold(report_detected_libgrade(StdOut),
|
|
StdlibGrades, !TIO),
|
|
io.write_string(StdOut, "% done.\n", !TIO)
|
|
;
|
|
Verbose = no
|
|
)
|
|
)
|
|
;
|
|
Detect = no,
|
|
set.init(StdlibGrades),
|
|
MaybeStdlibGrades = ok1(StdlibGrades)
|
|
),
|
|
GradeToOpts = (func(Grade) = ["--libgrade", Grade]),
|
|
StdlibGradeOptionPairs =
|
|
list.map(GradeToOpts, set.to_sorted_list(StdlibGrades)),
|
|
list.condense(StdlibGradeOptionPairs, StdlibGradeOpts).
|
|
|
|
find_mercury_stdlib(Globals, Variables, MaybeMerStdLibDir, !IO) :-
|
|
( if
|
|
% Was the standard library directory set on the command line?
|
|
globals.lookup_maybe_string_option(Globals,
|
|
mercury_standard_library_directory, MaybeStdLibDir),
|
|
MaybeStdLibDir = yes(MerStdLibDir)
|
|
then
|
|
can_you_read_dir(MerStdLibDir, MaybeMerStdLibDir, !IO)
|
|
else
|
|
% Was the standard library directory set using the
|
|
% MERCURY_STDLIB_DIR variable?
|
|
lookup_mercury_stdlib_dir(Variables, MaybeConfigMerStdLibDir),
|
|
(
|
|
MaybeConfigMerStdLibDir = ok1(MerStdLibDirs),
|
|
(
|
|
MerStdLibDirs = [MerStdLibDir],
|
|
can_you_read_dir(MerStdLibDir, MaybeMerStdLibDir, !IO)
|
|
;
|
|
MerStdLibDirs = [],
|
|
Pieces = [words("Error: the location of the directory"),
|
|
words("that holds the Mercury standard library"),
|
|
words("is not specified either by the value of any"),
|
|
quote("--mercury-stdlib-dir"), words("option"),
|
|
words("to the compiler, nor by any definition of the"),
|
|
quote("MERCURY_STDLIB_DIR"), words("variable in the"),
|
|
quote("Mercury.config"), words("file."), nl],
|
|
Spec = simplest_no_context_spec($pred, severity_error,
|
|
phase_options, Pieces),
|
|
MaybeMerStdLibDir = error1([Spec])
|
|
;
|
|
MerStdLibDirs = [_, _ | _],
|
|
Pieces = [words("Error: the definition of the"),
|
|
quote("MERCURY_STDLIB_DIR"), words("variable in the"),
|
|
quote("Mercury.config"), words("file"),
|
|
words("contains more than one string."), nl],
|
|
Spec = simplest_no_context_spec($pred, severity_error,
|
|
phase_options, Pieces),
|
|
MaybeMerStdLibDir = error1([Spec])
|
|
)
|
|
;
|
|
MaybeConfigMerStdLibDir = error1(Specs),
|
|
MaybeMerStdLibDir = error1(Specs)
|
|
)
|
|
).
|
|
|
|
:- pred can_you_read_dir(string::in, maybe1(string)::out, io::di, io::uo)
|
|
is det.
|
|
|
|
can_you_read_dir(MerStdLibDir, MaybeMerStdLibDir, !IO) :-
|
|
io.file.check_file_accessibility(MerStdLibDir, [read], CanRead, !IO),
|
|
(
|
|
CanRead = ok,
|
|
MaybeMerStdLibDir = ok1(MerStdLibDir)
|
|
;
|
|
CanRead = error(ReadError),
|
|
io.error_message(ReadError, ReadErrorMsg),
|
|
Pieces = [words("Error:"), fixed(MerStdLibDir), suffix(":"), nl,
|
|
words(ReadErrorMsg), suffix("."), nl],
|
|
Spec = simplest_no_context_spec($pred, severity_error,
|
|
phase_options, Pieces),
|
|
MaybeMerStdLibDir = error1([Spec])
|
|
).
|
|
|
|
do_detect_libgrades(StdLibDir, Grades, !IO) :-
|
|
ModulesDir = StdLibDir / "modules",
|
|
dir.foldl2(do_detect_libgrade_using_init_file, ModulesDir,
|
|
set.init, MaybeGrades0, !IO),
|
|
(
|
|
MaybeGrades0 = ok(Grades0),
|
|
LibsDir = StdLibDir / "lib",
|
|
dir.foldl2(do_detect_libgrade_using_lib_file, LibsDir,
|
|
Grades0, MaybeGrades, !IO),
|
|
(
|
|
MaybeGrades = ok(Grades)
|
|
;
|
|
MaybeGrades = error(_, _),
|
|
set.init(Grades)
|
|
)
|
|
;
|
|
MaybeGrades0 = error(_, _),
|
|
set.init(Grades)
|
|
).
|
|
|
|
% Test for the presence of an installed grade by looking for mer_std.init.
|
|
% This works for all grades except the C# and Java grades.
|
|
%
|
|
:- pred do_detect_libgrade_using_init_file(string::in, string::in,
|
|
io.file_type::in, bool::out, set(string)::in, set(string)::out,
|
|
io::di, io::uo) is det.
|
|
|
|
do_detect_libgrade_using_init_file(DirName, GradeFileName,
|
|
GradeFileType, Continue, !Grades, !IO) :-
|
|
(
|
|
GradeFileType = directory,
|
|
InitFile = DirName / GradeFileName / "mer_std.init",
|
|
io.file.check_file_accessibility(InitFile, [read], Result, !IO),
|
|
(
|
|
Result = ok,
|
|
set.insert(GradeFileName, !Grades)
|
|
;
|
|
Result = error(_)
|
|
)
|
|
;
|
|
( GradeFileType = regular_file
|
|
; GradeFileType = symbolic_link
|
|
; GradeFileType = named_pipe
|
|
; GradeFileType = socket
|
|
; GradeFileType = character_device
|
|
; GradeFileType = block_device
|
|
; GradeFileType = message_queue
|
|
; GradeFileType = semaphore
|
|
; GradeFileType = shared_memory
|
|
; GradeFileType = unknown
|
|
)
|
|
),
|
|
Continue = yes.
|
|
|
|
% Test for the presence of installed Java and C# grades by looking for
|
|
% the standard library JAR or assembly respectively.
|
|
%
|
|
:- pred do_detect_libgrade_using_lib_file(string::in, string::in,
|
|
io.file_type::in, bool::out, set(string)::in, set(string)::out,
|
|
io::di, io::uo) is det.
|
|
|
|
do_detect_libgrade_using_lib_file(DirName, GradeFileName, GradeFileType,
|
|
Continue, !Grades, !IO) :-
|
|
(
|
|
GradeFileType = directory,
|
|
( if
|
|
csharp_or_java_libgrade_target(GradeFileName, LibFile)
|
|
then
|
|
TargetFile = DirName / GradeFileName / LibFile,
|
|
io.file.check_file_accessibility(TargetFile, [read], Result, !IO),
|
|
(
|
|
Result = ok,
|
|
set.insert(GradeFileName, !Grades)
|
|
;
|
|
Result = error(_)
|
|
)
|
|
else
|
|
true
|
|
)
|
|
;
|
|
( GradeFileType = regular_file
|
|
; GradeFileType = symbolic_link
|
|
; GradeFileType = named_pipe
|
|
; GradeFileType = socket
|
|
; GradeFileType = character_device
|
|
; GradeFileType = block_device
|
|
; GradeFileType = message_queue
|
|
; GradeFileType = semaphore
|
|
; GradeFileType = shared_memory
|
|
; GradeFileType = unknown
|
|
)
|
|
),
|
|
Continue = yes.
|
|
|
|
:- pred csharp_or_java_libgrade_target(string::in, string::out) is semidet.
|
|
|
|
csharp_or_java_libgrade_target(GradeFileName, LibFile) :-
|
|
( if string.prefix(GradeFileName, "csharp") then
|
|
LibFile = "mer_std.dll"
|
|
else if string.prefix(GradeFileName, "java") then
|
|
LibFile = "mer_std.jar"
|
|
else
|
|
false
|
|
).
|
|
|
|
:- pred report_detected_libgrade(io.text_output_stream::in, string::in,
|
|
io::di, io::uo) is det.
|
|
|
|
report_detected_libgrade(Stream, Grade, !IO) :-
|
|
io.format(Stream, "%% Detected library grade: %s\n", [s(Grade)], !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
maybe_check_libraries_are_installed(Globals, !:Specs, !IO) :-
|
|
globals.lookup_bool_option(Globals, libgrade_install_check,
|
|
LibgradeCheck),
|
|
(
|
|
LibgradeCheck = yes,
|
|
globals.lookup_accumulating_option(Globals, mercury_libraries, Libs),
|
|
grade_directory_component(Globals, GradeDirName),
|
|
!:Specs = [],
|
|
check_stdlib_is_installed(Globals, GradeDirName, !Specs, !IO),
|
|
list.foldl2(check_library_is_installed(Globals, GradeDirName), Libs,
|
|
!Specs, !IO)
|
|
;
|
|
LibgradeCheck = no,
|
|
!:Specs = []
|
|
).
|
|
|
|
:- pred check_stdlib_is_installed(globals::in, string::in,
|
|
list(error_spec)::in, list(error_spec)::out, io::di, io::uo) is det.
|
|
|
|
check_stdlib_is_installed(Globals, GradeDirName, !Specs, !IO) :-
|
|
globals.lookup_maybe_string_option(Globals,
|
|
mercury_standard_library_directory, MaybeStdLibDir),
|
|
(
|
|
MaybeStdLibDir = yes(StdLibDir),
|
|
globals.get_target(Globals, Target),
|
|
(
|
|
Target = target_c,
|
|
% In C grades, check for the presence of mer_std.init in the
|
|
% required grade. Unless the installation is broken, this implies
|
|
% the presence of the other standard library files in that grade.
|
|
StdLibCheckFile =
|
|
StdLibDir / "modules" / GradeDirName / "mer_std.init"
|
|
;
|
|
% Java grades do not use .init files, so check for the presence of
|
|
% the standard library JAR.
|
|
Target = target_java,
|
|
StdLibCheckFile = StdLibDir / "lib" / GradeDirName / "mer_std.jar"
|
|
;
|
|
% C# grades do not use .init files, so check for the presence of
|
|
% the standard library DLL.
|
|
Target = target_csharp,
|
|
StdLibCheckFile = StdLibDir / "lib" / GradeDirName / "mer_std.dll"
|
|
),
|
|
io.open_input(StdLibCheckFile, StdLibCheckFileResult, !IO),
|
|
(
|
|
StdLibCheckFileResult = ok(StdLibCheckFileStream),
|
|
io.close_input(StdLibCheckFileStream, !IO)
|
|
;
|
|
StdLibCheckFileResult = error(_),
|
|
% XXX It would be better for our *caller* to print this kind of
|
|
% message, since it may know a more appropriate target stream
|
|
% than stderr.
|
|
io.progname_base("mercury_compile", ProgName, !IO),
|
|
Pieces = [fixed(ProgName), suffix(":"), words("error:"),
|
|
words("the Mercury standard library cannot be found"),
|
|
words("in grade"), quote(GradeDirName), suffix("."), nl],
|
|
Spec = simplest_no_context_spec($pred, severity_error,
|
|
phase_check_libs, Pieces),
|
|
!:Specs = [Spec | !.Specs]
|
|
)
|
|
;
|
|
MaybeStdLibDir = no
|
|
).
|
|
|
|
:- pred check_library_is_installed(globals::in, string::in, string::in,
|
|
list(error_spec)::in, list(error_spec)::out, io::di, io::uo) is det.
|
|
|
|
check_library_is_installed(Globals, GradeDirName, LibName, !Specs, !IO) :-
|
|
globals.get_target(Globals, Target),
|
|
(
|
|
% In C grades, check for the presence of a library by seeing
|
|
% if its .init files exists.
|
|
Target = target_c,
|
|
CheckFileName = LibName ++ ".init",
|
|
% NOTE: we don't look up the value of the option init_files here
|
|
% because that may include .init files other than those associated with
|
|
% any libraries.
|
|
globals.lookup_accumulating_option(Globals, init_file_directories,
|
|
SearchDirs)
|
|
;
|
|
(
|
|
% In Java grades, check for the presence of the JAR for library.
|
|
Target = target_java,
|
|
CheckFileName = LibName ++ ".jar"
|
|
;
|
|
% In C# grades, check for the presence of the DLL for the library.
|
|
Target = target_csharp,
|
|
CheckFileName = LibName ++ ".dll"
|
|
),
|
|
globals.lookup_accumulating_option(Globals,
|
|
mercury_library_directories, MercuryLibDirs),
|
|
grade_directory_component(Globals, GradeDirNameDir),
|
|
SearchDirs = list.map(
|
|
(func(LibDir) = LibDir / "lib" / GradeDirNameDir),
|
|
MercuryLibDirs)
|
|
),
|
|
search_for_file_returning_dir(SearchDirs, CheckFileName, MaybeDirName,
|
|
!IO),
|
|
(
|
|
MaybeDirName = ok(_)
|
|
;
|
|
MaybeDirName = error(_),
|
|
io.progname_base("mercury_compile", ProgName, !IO),
|
|
Pieces = [fixed(ProgName), suffix(":"), words("error:"),
|
|
words("the library"), quote(LibName), words("cannot be found"),
|
|
words("in grade"), quote(GradeDirName), suffix("."), nl],
|
|
Spec = simplest_no_context_spec($pred, severity_error,
|
|
phase_check_libs, Pieces),
|
|
!:Specs = [Spec | !.Specs]
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module libs.check_libgrades.
|
|
%---------------------------------------------------------------------------%
|