mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-16 06:14:59 +00:00
The main aim of this change is to make the overall, high-level structure of the compiler clearer, and to encourage better encapsulation of the major components. compiler/libs.m: compiler/backend_libs.m: compiler/parse_tree.m: compiler/hlds.m: compiler/check_hlds.m: compiler/transform_hlds.m: compiler/bytecode_backend.m: compiler/aditi_backend.m: compiler/ml_backend.m: compiler/ll_backend.m: compiler/top_level.m: New files. One module for each of the major components of the Mercury compiler. These modules contain (as separate sub-modules) all the other modules in the Mercury compiler, except gcc.m and mlds_to_gcc.m. Mmakefile: compiler/Mmakefile: Handle the fact that the top-level module is now `top_level', not `mercury_compile' (since `mercury_compile' is a sub-module of `top_level'). compiler/Mmakefile: Update settings of *FLAGS-<modulename> to use the appropriate nested module names. compiler/recompilation_check.m: compiler/recompilation_version.m: compiler/recompilation_usage.m: compiler/recompilation.check.m: compiler/recompilation.version.m: compiler/recompilation.version.m: Convert the `recompilation_*' modules into sub-modules of the `recompilation' module. compiler/*.m: compiler/*.pp: Module-qualify the module names in `:- module', `:- import_module', and `:- use_module' declarations. compiler/base_type_info.m: compiler/base_type_layout.m: Deleted these unused empty modules. compiler/prog_data.m: compiler/globals.m: Move the `foreign_language' type from prog_data to globals. compiler/mlds.m: compiler/ml_util.m: compiler/mlds_to_il.m: Import `globals', for `foreign_language'. Mmake.common.in: trace/Mmakefile: runtime/Mmakefile: Rename the %.check.c targets as %.check_hdr.c, to avoid conflicts with compiler/recompilation.check.c.
390 lines
11 KiB
Mathematica
390 lines
11 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 2002 The University of Melbourne.
|
|
% 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.m
|
|
% Main author: stayl
|
|
%
|
|
% A builtin Mercury-specific make replacement.
|
|
%
|
|
% TODO:
|
|
% - `--split-c-files'
|
|
% - fix `--target il'
|
|
% - check commands for compilation of foreign code files
|
|
% in mercury_compile.m
|
|
% - fix handling of the `.exe' file
|
|
% - library installation
|
|
% - transitive inter-module optimization (probably won't bother since
|
|
% that is being rewritten anyway)
|
|
% - parallel/distributed builds
|
|
%
|
|
%-----------------------------------------------------------------------------%
|
|
:- module make.
|
|
|
|
:- interface.
|
|
|
|
:- include_module make__options_file.
|
|
|
|
:- import_module parse_tree.
|
|
|
|
:- import_module make__options_file, parse_tree__modules, parse_tree__prog_io.
|
|
:- import_module io, list.
|
|
|
|
% make__process_args(OptionArgs, NonOptionArgs).
|
|
:- pred make__process_args(list(string)::in, list(file_name)::in,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
:- pred make__write_module_dep_file(module_imports::in,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
:- func make__module_dep_file_extension = string.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
:- implementation.
|
|
|
|
:- include_module make__dependencies, make__module_dep_file.
|
|
:- include_module make__module_target, make__program_target, make__util.
|
|
|
|
:- import_module hlds, libs, backend_libs.
|
|
:- import_module top_level. % XXX unwanted dependency
|
|
|
|
:- import_module make__dependencies, make__module_dep_file.
|
|
:- import_module make__module_target, make__program_target, make__util.
|
|
|
|
:- import_module parse_tree__prog_data, parse_tree__prog_io.
|
|
:- import_module parse_tree__modules, parse_tree__mercury_to_mercury.
|
|
:- import_module parse_tree__prog_out, parse_tree__prog_io_util.
|
|
:- import_module backend_libs__foreign, backend_libs__compile_target_code.
|
|
:- import_module libs__timestamp, libs__process_util.
|
|
:- import_module libs__globals, libs__options, libs__handle_options.
|
|
:- import_module top_level__mercury_compile. % XXX unwanted dependency
|
|
|
|
:- import_module assoc_list, bool, char, dir, exception, getopt, int, list.
|
|
:- import_module map, parser, require, set, std_util, string, term, term_io.
|
|
|
|
:- type make_info
|
|
---> make_info(
|
|
% The items field of each module_imports
|
|
% structure should be empty -- we're not
|
|
% trying to cache the items here.
|
|
module_dependencies :: map(module_name, maybe(module_imports)),
|
|
|
|
file_timestamps :: file_timestamps,
|
|
|
|
% The original set of options passed to mmc,
|
|
% not including the targets to be made.
|
|
option_args :: list(string),
|
|
|
|
% The contents of the Mercury.options file.
|
|
options_variables :: options_variables,
|
|
|
|
dependency_status :: map(dependency_file, dependency_status),
|
|
|
|
% For each module, the set of modules for
|
|
% which the `.int' files are read, excluding
|
|
% those read as a result of reading `.opt' files.
|
|
% The bool records whether there was an error
|
|
% in the dependencies.
|
|
% XXX Use a better representation for the sets.
|
|
cached_direct_imports :: cached_direct_imports,
|
|
|
|
% The boolean is `yes' if the result is complete.
|
|
% XXX Use a better representation for the sets.
|
|
cached_transitive_dependencies ::
|
|
cached_transitive_dependencies,
|
|
|
|
% Should the `.module_dep' files be rebuilt.
|
|
% Set to `no' for `mmc --make clean'.
|
|
rebuild_dependencies :: bool,
|
|
|
|
keep_going :: bool,
|
|
|
|
% Modules for which we have redirected output
|
|
% to a `.err' file during this invocation of mmc.
|
|
error_file_modules :: set(module_name)
|
|
).
|
|
|
|
:- type make_error
|
|
---> target_error(target_file)
|
|
; dependencies_error(module_name)
|
|
; other(string)
|
|
.
|
|
|
|
:- type compilation_task == pair(compilation_task_type, module_name).
|
|
|
|
:- type compilation_task_type
|
|
---> process_module(module_compilation_task_type)
|
|
; target_code_to_object_code
|
|
.
|
|
|
|
:- type module_compilation_task_type
|
|
---> errorcheck
|
|
; make_short_interface
|
|
; make_interface
|
|
; make_private_interface
|
|
; make_optimization_interface
|
|
; make_transitive_optimization_interface
|
|
; compile_to_target_code
|
|
.
|
|
|
|
:- type module_target_type
|
|
---> source
|
|
; errors
|
|
; private_interface
|
|
; long_interface
|
|
; short_interface
|
|
; unqualified_short_interface
|
|
; intermodule_interface
|
|
; aditi_code
|
|
; c_header
|
|
; c_code
|
|
; il_code
|
|
; il_asm
|
|
; java_code
|
|
; asm_code(pic)
|
|
; object_code(pic)
|
|
.
|
|
|
|
% Are we generating position indepedent code (for use in a
|
|
% shared library)? On some architectures, pic and non-pic
|
|
% code is incompatible, so we need to generate `.o' and `.pic_o'
|
|
% files.
|
|
:- type pic
|
|
---> pic
|
|
; non_pic
|
|
.
|
|
|
|
% :- type linked_target_type in mercury_compile.m.
|
|
|
|
:- type misc_target_type
|
|
---> clean
|
|
; realclean
|
|
; check
|
|
; install_library
|
|
.
|
|
|
|
:- type file_timestamps == map(string, maybe_error(timestamp)).
|
|
|
|
:- type dependency_status
|
|
---> not_considered
|
|
; being_built
|
|
; up_to_date
|
|
; error
|
|
.
|
|
|
|
:- type target_file == pair(module_name, module_target_type).
|
|
:- type linked_target_file == pair(module_name, linked_target_type).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
make__write_module_dep_file(Imports) -->
|
|
make__module_dep_file__write_module_dep_file(Imports).
|
|
|
|
make__module_dep_file_extension = ".module_dep".
|
|
|
|
make__process_args(OptionArgs, Targets0) -->
|
|
read_options_files(MaybeVariables),
|
|
(
|
|
{ MaybeVariables = yes(Variables) },
|
|
% Look up the MCFLAGS and GRADEFLAGS from the options file.
|
|
lookup_mmc_options(Variables, MaybeMCFlags),
|
|
(
|
|
{ MaybeMCFlags = yes(MCFlags) },
|
|
handle_options(MCFlags ++ OptionArgs, MaybeError,
|
|
_, _, _),
|
|
(
|
|
{ MaybeError = yes(OptionsError) },
|
|
usage_error(OptionsError),
|
|
{ Continue0 = no }
|
|
;
|
|
{ MaybeError = no },
|
|
{ Continue0 = yes }
|
|
)
|
|
;
|
|
{ MaybeMCFlags = no },
|
|
{ Continue0 = no }
|
|
)
|
|
;
|
|
{ MaybeVariables = no },
|
|
{ Variables = options_variables_init },
|
|
{ Continue0 = no }
|
|
),
|
|
(
|
|
{ Continue0 = yes },
|
|
{ Targets0 = [] }
|
|
->
|
|
lookup_main_target(Variables, MaybeMAIN_TARGET),
|
|
(
|
|
{ MaybeMAIN_TARGET = yes(Targets) },
|
|
(
|
|
{ Targets = [_ | _] },
|
|
{ Continue = yes }
|
|
;
|
|
{ Targets = [] },
|
|
{ Continue = no },
|
|
io__write_string(
|
|
"** Error: no targets specified and `MAIN_TARGET' not defined.\n")
|
|
)
|
|
;
|
|
{ MaybeMAIN_TARGET = no },
|
|
{ Targets = [] },
|
|
{ Continue = no }
|
|
)
|
|
;
|
|
{ Continue = Continue0 },
|
|
{ Targets = Targets0 }
|
|
),
|
|
( { Continue = no } ->
|
|
io__set_exit_status(1)
|
|
;
|
|
{ ShouldRebuildDeps = yes },
|
|
globals__io_lookup_bool_option(keep_going, KeepGoing),
|
|
{ MakeInfo0 = make_info(map__init, map__init,
|
|
OptionArgs, Variables, map__init,
|
|
init_cached_direct_imports,
|
|
init_cached_transitive_dependencies,
|
|
ShouldRebuildDeps, KeepGoing, set__init) },
|
|
|
|
globals__io_get_globals(Globals),
|
|
foldl2_maybe_stop_at_error(KeepGoing,
|
|
(pred(TargetStr::in, Success0::out,
|
|
Info0::in, Info::out, di, uo) is det -->
|
|
(
|
|
{ target_file(Globals, TargetStr,
|
|
ModuleName, TargetType) }
|
|
->
|
|
(
|
|
{ TargetType = module_target(ModuleTargetType) },
|
|
make_module_target(
|
|
target(ModuleName - ModuleTargetType),
|
|
Success0, Info0, Info)
|
|
;
|
|
{ TargetType = linked_target(ProgramTargetType) },
|
|
make_linked_target(
|
|
ModuleName - ProgramTargetType, Success0,
|
|
Info0, Info)
|
|
;
|
|
{ TargetType = misc_target(MiscTargetType) },
|
|
make_misc_target(ModuleName - MiscTargetType,
|
|
Success0, Info0, Info)
|
|
)
|
|
;
|
|
% Accept and ignore `.depend' targets.
|
|
% `mmc --make' does not need a separate
|
|
% make depend step. The dependencies for
|
|
% each module are regenerated on demand.
|
|
{ string__length(TargetStr, NameLength) },
|
|
{ search_backwards_for_dot(TargetStr,
|
|
NameLength - 1, DotLocn) },
|
|
{ string__split(TargetStr, DotLocn, _, ".depend") }
|
|
->
|
|
{ Success0 = yes },
|
|
{ Info = Info0 }
|
|
;
|
|
{ Info = Info0 },
|
|
{ Success0 = no },
|
|
io__write_string("** Unknown target: "),
|
|
io__write_string(TargetStr),
|
|
io__write_string(".\n")
|
|
)
|
|
), Targets, Success, MakeInfo0, _MakeInfo),
|
|
|
|
( { Success = no } ->
|
|
io__set_exit_status(1)
|
|
;
|
|
[]
|
|
)
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- type target_type
|
|
---> module_target(module_target_type)
|
|
; linked_target(linked_target_type)
|
|
; misc_target(misc_target_type)
|
|
.
|
|
|
|
:- pred target_file(globals::in, string::in,
|
|
module_name::out, target_type::out) is semidet.
|
|
|
|
target_file(Globals, FileName, ModuleName, TargetType) :-
|
|
(
|
|
string__length(FileName, NameLength),
|
|
search_backwards_for_dot(FileName, NameLength - 1, DotLocn),
|
|
string__split(FileName, DotLocn, ModuleNameStr0, Suffix),
|
|
solutions(
|
|
(pred(TargetFile0::out) is nondet :-
|
|
(
|
|
Suffix = target_extension(Globals,
|
|
ModuleTargetType)
|
|
->
|
|
ModuleNameStr = ModuleNameStr0,
|
|
TargetType0 = module_target(ModuleTargetType)
|
|
;
|
|
globals__lookup_string_option(Globals,
|
|
library_extension, Suffix),
|
|
string__append("lib", ModuleNameStr1, ModuleNameStr0)
|
|
->
|
|
ModuleNameStr = ModuleNameStr1,
|
|
TargetType0 = linked_target(static_library)
|
|
;
|
|
globals__lookup_string_option(Globals,
|
|
shared_library_extension, Suffix),
|
|
string__append("lib", ModuleNameStr1, ModuleNameStr0)
|
|
->
|
|
ModuleNameStr = ModuleNameStr1,
|
|
TargetType0 = linked_target(shared_library)
|
|
;
|
|
globals__lookup_string_option(Globals,
|
|
executable_file_extension, Suffix)
|
|
->
|
|
ModuleNameStr = ModuleNameStr0,
|
|
TargetType0 = linked_target(executable)
|
|
;
|
|
Suffix = ".check"
|
|
->
|
|
ModuleNameStr = ModuleNameStr0,
|
|
TargetType0 = misc_target(check)
|
|
;
|
|
Suffix = ".clean"
|
|
->
|
|
ModuleNameStr = ModuleNameStr0,
|
|
TargetType0 = misc_target(clean)
|
|
;
|
|
Suffix = ".realclean"
|
|
->
|
|
ModuleNameStr = ModuleNameStr0,
|
|
TargetType0 = misc_target(realclean)
|
|
;
|
|
Suffix = ".install"
|
|
->
|
|
ModuleNameStr = ModuleNameStr0,
|
|
TargetType0 = misc_target(install_library)
|
|
;
|
|
fail
|
|
),
|
|
file_name_to_module_name(ModuleNameStr, ModuleName0),
|
|
TargetFile0 = ModuleName0 - TargetType0
|
|
), TargetFiles),
|
|
TargetFiles = [TargetFile]
|
|
->
|
|
TargetFile = ModuleName - TargetType
|
|
;
|
|
globals__lookup_string_option(Globals, executable_file_extension, ""),
|
|
TargetType = linked_target(executable),
|
|
file_name_to_module_name(FileName, ModuleName)
|
|
).
|
|
|
|
:- pred search_backwards_for_dot(string::in, int::in, int::out) is semidet.
|
|
|
|
search_backwards_for_dot(String, Index, DotIndex) :-
|
|
Index >= 0,
|
|
( string__index_det(String, Index, '.') ->
|
|
DotIndex = Index
|
|
;
|
|
search_backwards_for_dot(String, Index - 1, DotIndex)
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|