Files
mercury/compiler/make.m
Julien Fischer 87fb88961c Minor cleanups for mmc --make. There are no algorithmic
Estimated hours taken: 0.5
Branches: main

Minor cleanups for mmc --make.  There are no algorithmic
changes.

compiler/make.m:
compiler/make.dependencies.m:
compiler/make.module_dep_file.m:
compiler/make.module_target.m:
compiler/make.program_target.m:
compiler/process_util.m:
	Bring these modules into line with our current coding
	standard.
2005-04-26 04:32:49 +00:00

426 lines
14 KiB
Mathematica

%-----------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%-----------------------------------------------------------------------------%
% Copyright (C) 2002-2005 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'
% - 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.
:- include_module make__util.
:- import_module make__options_file.
:- import_module mdbcomp.
:- import_module mdbcomp__prim_data.
:- import_module parse_tree.
:- import_module parse_tree__modules.
:- import_module parse_tree__prog_io.
:- import_module io.
:- import_module list.
%-----------------------------------------------------------------------------%
% make__process_args(OptionArgs, NonOptionArgs).
%
:- pred make__process_args(options_variables::in, list(string)::in,
list(file_name)::in, io::di, io::uo) is det.
:- pred make__write_module_dep_file(module_imports::in,
io::di, io::uo) is det.
:- func make__module_dep_file_extension = string.
:- type make_info.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
:- include_module make__dependencies.
:- include_module make__module_dep_file.
:- include_module make__module_target.
:- include_module make__program_target.
:- import_module hlds.
:- import_module libs.
:- import_module backend_libs.
:- import_module top_level. % XXX unwanted dependency
:- import_module make__dependencies.
:- import_module make__module_dep_file.
:- import_module make__module_target.
:- import_module make__program_target.
:- import_module make__util.
:- import_module backend_libs__compile_target_code.
:- import_module libs__globals.
:- import_module libs__handle_options.
:- import_module libs__options.
:- import_module libs__process_util.
:- import_module libs__timestamp.
:- import_module parse_tree__error_util.
:- import_module parse_tree__mercury_to_mercury.
:- import_module parse_tree__prog_data.
:- import_module parse_tree__prog_foreign.
:- import_module parse_tree__prog_io_util.
:- import_module parse_tree__prog_out.
:- import_module top_level__mercury_compile. % XXX unwanted dependency
:- import_module assoc_list.
:- import_module bool.
:- import_module char.
:- import_module dir.
:- import_module exception.
:- import_module getopt_io.
:- import_module int.
:- import_module map.
:- import_module parser.
:- import_module require.
:- import_module set.
:- import_module std_util.
:- import_module string.
:- import_module term.
:- import_module 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),
% Used for reporting which module imported
% a nonexistent module.
importing_module :: maybe(module_name),
% Targets specified on the command line.
command_line_targets :: set(pair(module_name, target_type))
).
:- 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)
% The `pic' argument is only used for
% `--target c' and `--target asm'.
; target_code_to_object_code(pic)
; foreign_code_to_object_code(pic, foreign_language)
; fact_table_code_to_object_code(pic, file_name).
:- 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_header_type)
; c_code
; il_code
; il_asm
; java_code
; asm_code(pic)
; object_code(pic)
; foreign_il_asm(foreign_language)
; foreign_object(pic, foreign_language)
; fact_table_object(pic, file_name).
:- type c_header_type
---> mh % For `:- pragma export' declarations.
; mih. % Declarations for hlc grades, for compiler use only.
% :- type linked_target_type in compile_target_code.m.
:- type misc_target_type
---> clean
; realclean
; build_all(module_target_type)
; build_library
; 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, !IO) :-
make__module_dep_file__write_module_dep_file(Imports, !IO).
make__module_dep_file_extension = ".module_dep".
make__process_args(Variables, OptionArgs, Targets0, !IO) :-
(
Targets0 = [],
lookup_main_target(Variables, MaybeMAIN_TARGET, !IO),
(
MaybeMAIN_TARGET = yes(Targets),
(
Targets = [_ | _],
Continue = yes
;
Targets = [],
Continue = no,
io__write_string("** Error: no targets specified " ++
"and `MAIN_TARGET' not defined.\n", !IO)
)
;
MaybeMAIN_TARGET = no,
Targets = [],
Continue = no
)
;
Targets0 = [_ | _],
Continue = yes,
Targets = Targets0
),
(
Continue = no,
io__set_exit_status(1, !IO)
;
Continue = yes,
globals__io_lookup_bool_option(keep_going, KeepGoing, !IO),
globals__io_get_globals(Globals, !IO),
%
% Accept and ignore `.depend' targets.
% `mmc --make' does not need a separate
% make depend step. The dependencies for
% each module are regenerated on demand.
%
NonDependTargets = list__filter(
(pred(Target::in) is semidet :-
\+ string__remove_suffix(Target, ".depend", _)
), Targets),
%
% Classify the remaining targets.
%
list__map(classify_target(Globals), NonDependTargets,
ClassifiedTargets),
ShouldRebuildDeps = yes,
MakeInfo0 = make_info(map__init, map__init, OptionArgs, Variables,
map__init,
init_cached_direct_imports,
init_cached_transitive_dependencies,
ShouldRebuildDeps, KeepGoing,
set__init, no, set__list_to_set(ClassifiedTargets)),
%
% Build the targets, stopping on any errors if
% `--keep-going' was not set.
%
foldl2_maybe_stop_at_error(KeepGoing, make_target,
ClassifiedTargets, Success, MakeInfo0, _MakeInfo, !IO),
(
Success = no,
io__set_exit_status(1, !IO)
;
Success = yes
)
).
:- pred make_target(pair(module_name, target_type)::in, bool::out,
make_info::in, make_info::out, io::di, io::uo) is det.
make_target(Target, Success, !Info, !IO) :-
Target = ModuleName - TargetType,
(
TargetType = module_target(ModuleTargetType),
make_module_target(target(ModuleName - ModuleTargetType), Success,
!Info, !IO)
;
TargetType = linked_target(ProgramTargetType),
make_linked_target(ModuleName - ProgramTargetType, Success,
!Info, !IO)
;
TargetType = misc_target(MiscTargetType),
make_misc_target(ModuleName - MiscTargetType, Success, !Info, !IO)
).
%-----------------------------------------------------------------------------%
:- type target_type
---> module_target(module_target_type)
; linked_target(linked_target_type)
; misc_target(misc_target_type).
:- pred classify_target(globals::in, string::in,
pair(module_name, target_type)::out) is det.
classify_target(Globals, FileName, ModuleName - TargetType) :-
(
string__length(FileName, NameLength),
search_backwards_for_dot(FileName, NameLength - 1, DotLocn),
string__split(FileName, DotLocn, ModuleNameStr0, Suffix),
solutions(classify_target_2(Globals, ModuleNameStr0, Suffix),
TargetFiles),
TargetFiles = [TargetFile]
->
TargetFile = ModuleName - TargetType
;
string__append("lib", ModuleNameStr, FileName)
->
TargetType = misc_target(build_library),
file_name_to_module_name(ModuleNameStr, ModuleName)
;
TargetType = linked_target(executable),
file_name_to_module_name(FileName, ModuleName)
).
:- pred classify_target_2(globals::in, string::in, string::in,
pair(module_name, target_type)::out) is nondet.
classify_target_2(Globals, ModuleNameStr0, Suffix, ModuleName - TargetType) :-
(
yes(Suffix) = target_extension(Globals, ModuleTargetType)
->
ModuleNameStr = ModuleNameStr0,
TargetType = module_target(ModuleTargetType)
;
globals__lookup_string_option(Globals, library_extension, Suffix),
string__append("lib", ModuleNameStr1, ModuleNameStr0)
->
ModuleNameStr = ModuleNameStr1,
TargetType = linked_target(static_library)
;
globals__lookup_string_option(Globals, shared_library_extension,
Suffix),
string__append("lib", ModuleNameStr1, ModuleNameStr0)
->
ModuleNameStr = ModuleNameStr1,
TargetType = linked_target(shared_library)
;
globals__lookup_string_option(Globals, executable_file_extension,
Suffix)
->
ModuleNameStr = ModuleNameStr0,
TargetType = linked_target(executable)
;
string__append(Suffix1, "s", Suffix),
yes(Suffix1) = target_extension(Globals, ModuleTargetType),
% Not yet implemented. `build_all' targets are only used by
% tools/bootcheck, so it doesn't really matter.
ModuleTargetType \= c_header(_)
->
ModuleNameStr = ModuleNameStr0,
TargetType = misc_target(build_all(ModuleTargetType))
;
Suffix = ".check"
->
ModuleNameStr = ModuleNameStr0,
TargetType = misc_target(build_all(errors))
;
Suffix = ".clean"
->
ModuleNameStr = ModuleNameStr0,
TargetType = misc_target(clean)
;
Suffix = ".realclean"
->
ModuleNameStr = ModuleNameStr0,
TargetType = misc_target(realclean)
;
Suffix = ".install",
string__append("lib", ModuleNameStr1, ModuleNameStr0)
->
ModuleNameStr = ModuleNameStr1,
TargetType = misc_target(install_library)
;
fail
),
file_name_to_module_name(ModuleNameStr, 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)
).
%-----------------------------------------------------------------------------%
:- end_module make.
%-----------------------------------------------------------------------------%