mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-13 21:04:00 +00:00
Estimated hours taken: 3 Branches: main Clean up the conversion of targets to file names by `mmc --make'. Don't assume that every target can be converted simply by adding an extension -- this isn't true for object files for foreign code or fact tables. compiler/make.m: compiler/make.*.m: s/factt_object/fact_table_object/ Instead of having one fact_table_object target for each module, have one for each fact table file. Previously it wasn't possible to identify a fact_table_object target with a target file without additional information. compiler/make.util.m: compiler/make.*.m: make_util.target_extension now returns a `maybe' type, since foreign code and fact table targets can't be converted to file names by adding an extension. Add predicates module_target_to_file_name and module_target_to_search_file_name which are like module_name_to_file_name, but which handle the special cases for foreign code and fact tables correctly.
1052 lines
34 KiB
Mathematica
1052 lines
34 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 2002-2003 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.program_target.m
|
|
% Main author: stayl
|
|
%
|
|
% Build targets which relate to whole programs or libraries.
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module make__program_target.
|
|
|
|
:- interface.
|
|
|
|
% make_linked_target(Target, Success, Info0, Info).
|
|
%
|
|
% Build a library or an executable.
|
|
:- pred make_linked_target(linked_target_file::in, bool::out,
|
|
make_info::in, make_info::out,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
% make_misc_target(Target, Success, Info0, Info).
|
|
%
|
|
% Handle miscellaneous target types, including clean-up, library
|
|
% installation, and building all files of a given type for all
|
|
% modules in the program.
|
|
:- pred make_misc_target(pair(module_name, misc_target_type)::in,
|
|
bool::out, make_info::in, make_info::out,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
:- implementation.
|
|
|
|
:- import_module hlds__passes_aux.
|
|
|
|
make_linked_target(MainModuleName - FileType, Succeeded, Info0, Info) -->
|
|
{ ExtraOptions =
|
|
( if FileType = shared_library then ["--compile-to-shared-lib"]
|
|
else []
|
|
) },
|
|
build_with_module_options(MainModuleName, ExtraOptions,
|
|
make_linked_target_2(MainModuleName - FileType),
|
|
Succeeded, Info0, Info).
|
|
|
|
:- pred make_linked_target_2(linked_target_file::in, list(string)::in,
|
|
bool::out, make_info::in, make_info::out,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
make_linked_target_2(MainModuleName - FileType, _, Succeeded, !Info) -->
|
|
find_reachable_local_modules(MainModuleName, DepsSuccess,
|
|
AllModules, !Info),
|
|
globals__io_lookup_bool_option(keep_going, KeepGoing),
|
|
( { DepsSuccess = no, KeepGoing = no } ->
|
|
{ Succeeded = no }
|
|
;
|
|
get_object_code_type(FileType, PIC),
|
|
|
|
%
|
|
% Build the `.c' files first so that errors are
|
|
% reported as soon as possible.
|
|
%
|
|
globals__io_get_target(CompilationTarget),
|
|
{
|
|
CompilationTarget = c,
|
|
IntermediateTargetType = c_code,
|
|
ObjectTargetType = object_code(PIC)
|
|
;
|
|
CompilationTarget = asm,
|
|
IntermediateTargetType = asm_code(PIC),
|
|
ObjectTargetType = object_code(PIC)
|
|
;
|
|
CompilationTarget = il,
|
|
IntermediateTargetType = il_code,
|
|
ObjectTargetType = il_asm
|
|
;
|
|
CompilationTarget = java,
|
|
IntermediateTargetType = java_code,
|
|
% XXX Whoever finishes the Java backend can fill this in.
|
|
ObjectTargetType = object_code(non_pic)
|
|
},
|
|
|
|
get_target_modules(IntermediateTargetType,
|
|
set__to_sorted_list(AllModules), ObjModules, !Info),
|
|
{ IntermediateTargets = make_dependency_list(ObjModules,
|
|
IntermediateTargetType) },
|
|
{ ObjTargets = make_dependency_list(ObjModules, ObjectTargetType) },
|
|
|
|
list__map_foldl2(get_foreign_object_targets(PIC),
|
|
ObjModules, ForeignObjTargetsList, !Info),
|
|
{ ForeignObjTargets = list__condense(ForeignObjTargetsList) },
|
|
|
|
foldl2_maybe_stop_at_error(KeepGoing,
|
|
foldl2_maybe_stop_at_error(KeepGoing, make_module_target),
|
|
[IntermediateTargets, ObjTargets, ForeignObjTargets],
|
|
BuildDepsSucceeded, !Info),
|
|
|
|
linked_target_file_name(MainModuleName, FileType, OutputFileName),
|
|
get_file_timestamp([dir__this_directory], OutputFileName,
|
|
MaybeTimestamp, !Info),
|
|
check_dependencies(OutputFileName, MaybeTimestamp, BuildDepsSucceeded,
|
|
ObjTargets, BuildDepsResult, !Info),
|
|
|
|
(
|
|
{ DepsSuccess = yes },
|
|
{ BuildDepsResult \= error }
|
|
->
|
|
build_with_check_for_interrupt(
|
|
build_with_output_redirect(MainModuleName,
|
|
build_linked_target(MainModuleName, FileType,
|
|
OutputFileName, MaybeTimestamp, AllModules,
|
|
ObjModules, CompilationTarget,
|
|
PIC, DepsSuccess, BuildDepsResult)),
|
|
linked_target_cleanup(MainModuleName, FileType, OutputFileName,
|
|
CompilationTarget),
|
|
Succeeded, !Info)
|
|
;
|
|
{ Succeeded = no }
|
|
)
|
|
).
|
|
|
|
:- pred get_target_modules(module_target_type::in, list(module_name)::in,
|
|
list(module_name)::out, make_info::in, make_info::out,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
get_target_modules(TargetType, AllModules, TargetModules, Info0, Info) -->
|
|
globals__io_get_target(CompilationTarget),
|
|
(
|
|
{
|
|
TargetType = errors
|
|
;
|
|
CompilationTarget = asm,
|
|
( TargetType = asm_code(_)
|
|
; TargetType = object_code(_)
|
|
)
|
|
}
|
|
->
|
|
% `.err' and `.s' files are only produced for the
|
|
% top-level module in each source file.
|
|
list__foldl3(
|
|
(pred(ModuleName::in, TargetModules0::in, TargetModules1::out,
|
|
MInfo0::in, MInfo::out, di, uo) is det -->
|
|
get_module_dependencies(ModuleName, MaybeImports,
|
|
MInfo0, MInfo),
|
|
{
|
|
MaybeImports = yes(Imports),
|
|
ModuleName = Imports ^ source_file_module_name
|
|
->
|
|
TargetModules1 = [ModuleName | TargetModules0]
|
|
;
|
|
TargetModules1 = TargetModules0
|
|
}
|
|
),
|
|
AllModules, [], TargetModules, Info0, Info)
|
|
;
|
|
{ Info = Info0 },
|
|
{ TargetModules = AllModules }
|
|
).
|
|
|
|
:- pred get_foreign_object_targets(pic::in,
|
|
module_name::in, list(dependency_file)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
get_foreign_object_targets(PIC, ModuleName, ObjectTargets, !Info) -->
|
|
%
|
|
% Find externally compiled foreign code files for
|
|
% `:- pragma foreign_proc' declarations.
|
|
%
|
|
globals__io_get_target(CompilationTarget),
|
|
get_module_dependencies(ModuleName, MaybeImports, !Info),
|
|
{ MaybeImports = yes(Imports)
|
|
; MaybeImports = no,
|
|
unexpected(this_file, "unknown imports")
|
|
},
|
|
(
|
|
{ CompilationTarget = asm },
|
|
{ Imports ^ foreign_code = contains_foreign_code(Langs) },
|
|
{ set__member(c, Langs) }
|
|
->
|
|
{ ForeignObjectTargets = [
|
|
target(ModuleName - foreign_object(PIC, c))] }
|
|
;
|
|
{ CompilationTarget = il },
|
|
{ Imports ^ foreign_code = contains_foreign_code(Langs) }
|
|
->
|
|
{ ForeignObjectTargets = list__map(
|
|
(func(L) =
|
|
target(ModuleName - foreign_il_asm(L))
|
|
), set__to_sorted_list(Langs)) }
|
|
;
|
|
{ ForeignObjectTargets = [] }
|
|
),
|
|
|
|
%
|
|
% Find out if any externally compiled foreign code files for fact
|
|
% tables exist.
|
|
%
|
|
( { CompilationTarget = c ; CompilationTarget = asm } ->
|
|
{ FactObjectTargets = list__map(
|
|
(func(FactFile) =
|
|
target(ModuleName -
|
|
fact_table_object(PIC, FactFile))
|
|
),
|
|
Imports ^ fact_table_deps) },
|
|
{ ObjectTargets = FactObjectTargets ++ ForeignObjectTargets }
|
|
;
|
|
{ ObjectTargets = ForeignObjectTargets }
|
|
).
|
|
|
|
|
|
:- pred build_linked_target(module_name::in, linked_target_type::in,
|
|
file_name::in, maybe_error(timestamp)::in, set(module_name)::in,
|
|
list(module_name)::in, compilation_target::in, pic::in,
|
|
bool::in, dependencies_result::in, io__output_stream::in,
|
|
bool::out, make_info::in, make_info::out,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
build_linked_target(MainModuleName, FileType, OutputFileName, MaybeTimestamp,
|
|
AllModules, ObjModules, CompilationTarget, PIC,
|
|
DepsSuccess, BuildDepsResult, ErrorStream, Succeeded,
|
|
Info0, Info) -->
|
|
globals__io_lookup_maybe_string_option(pre_link_command,
|
|
MaybePreLinkCommand),
|
|
( { MaybePreLinkCommand = yes(PreLinkCommand) } ->
|
|
make_all_module_command(PreLinkCommand, MainModuleName,
|
|
to_sorted_list(AllModules), CommandString),
|
|
invoke_system_command(ErrorStream, verbose,
|
|
CommandString, PreLinkSucceeded)
|
|
;
|
|
{ PreLinkSucceeded = yes }
|
|
),
|
|
|
|
( { PreLinkSucceeded = yes } ->
|
|
build_linked_target_2(MainModuleName, FileType, OutputFileName,
|
|
MaybeTimestamp, AllModules, ObjModules,
|
|
CompilationTarget, PIC, DepsSuccess,
|
|
BuildDepsResult, ErrorStream, Succeeded,
|
|
Info0, Info)
|
|
;
|
|
{ Succeeded = no },
|
|
{ Info = Info0 }
|
|
).
|
|
|
|
:- pred build_linked_target_2(module_name::in, linked_target_type::in,
|
|
file_name::in, maybe_error(timestamp)::in, set(module_name)::in,
|
|
list(module_name)::in, compilation_target::in, pic::in,
|
|
bool::in, dependencies_result::in, io__output_stream::in, bool::out,
|
|
make_info::in, make_info::out, io__state::di, io__state::uo) is det.
|
|
|
|
build_linked_target_2(MainModuleName, FileType, OutputFileName, MaybeTimestamp,
|
|
AllModules, ObjModules, CompilationTarget, PIC,
|
|
DepsSuccess, BuildDepsResult, ErrorStream, Succeeded,
|
|
Info0, Info) -->
|
|
globals__io_lookup_accumulating_option(link_objects, LinkObjects),
|
|
|
|
% Clear the option -- we'll pass the list of files directly.
|
|
globals__io_set_option(link_objects, accumulating([])),
|
|
|
|
%
|
|
% Remake the `_init.o' file.
|
|
% XXX We should probably make a `_init.o' file for shared
|
|
% libraries linked using dlopen().
|
|
%
|
|
{ AllModulesList = set__to_sorted_list(AllModules) },
|
|
(
|
|
{ FileType = executable },
|
|
{ CompilationTarget = c ; CompilationTarget = asm }
|
|
->
|
|
compile_target_code__make_init_obj_file(ErrorStream,
|
|
MainModuleName, AllModulesList, InitObjectResult),
|
|
(
|
|
{ InitObjectResult = yes(InitObject) },
|
|
|
|
% We may need to update the timestamp
|
|
% of the `_init.o' file.
|
|
{ Info1 = Info0 ^ file_timestamps :=
|
|
map__delete(Info0 ^ file_timestamps,
|
|
InitObject) },
|
|
{ InitObjects = [InitObject] },
|
|
{ DepsResult2 = BuildDepsResult }
|
|
;
|
|
{ InitObjectResult = no },
|
|
{ Info1 = Info0 },
|
|
{ DepsResult2 = error },
|
|
{ InitObjects = [] }
|
|
)
|
|
;
|
|
{ DepsResult2 = BuildDepsResult },
|
|
{ Info1 = Info0 },
|
|
{ InitObjects = [] }
|
|
),
|
|
|
|
{ ObjectsToCheck = InitObjects ++ LinkObjects },
|
|
|
|
%
|
|
% Report errors if any of the extra objects aren't present.
|
|
%
|
|
list__map_foldl2(dependency_status,
|
|
list__map((func(F) = file(F, no)), ObjectsToCheck),
|
|
ExtraObjStatus, Info1, Info2),
|
|
|
|
{ DepsResult3 =
|
|
( list__member(error, ExtraObjStatus) -> error ; DepsResult2 ) },
|
|
{ BuildDepsSuccess = ( DepsResult3 \= error -> yes ; no ) },
|
|
list__map_foldl2(get_file_timestamp([dir__this_directory]),
|
|
ObjectsToCheck, ExtraObjectTimestamps, Info2, Info3),
|
|
check_dependency_timestamps(OutputFileName, MaybeTimestamp,
|
|
BuildDepsSuccess, ObjectsToCheck, io__write,
|
|
ExtraObjectTimestamps, ExtraObjectDepsResult),
|
|
|
|
{ DepsResult4 = ( DepsSuccess = yes -> DepsResult3 ; error ) },
|
|
{ DepsResult4 = error, DepsResult = DepsResult4
|
|
; DepsResult4 = out_of_date, DepsResult = DepsResult4
|
|
; DepsResult4 = up_to_date, DepsResult = ExtraObjectDepsResult
|
|
},
|
|
(
|
|
{ DepsResult = error },
|
|
file_error(OutputFileName),
|
|
{ Succeeded = no },
|
|
{ Info = Info3 }
|
|
;
|
|
{ DepsResult = up_to_date },
|
|
maybe_warn_up_to_date_target(
|
|
MainModuleName - linked_target(FileType),
|
|
Info3, Info),
|
|
{ Succeeded = yes }
|
|
;
|
|
{ DepsResult = out_of_date },
|
|
maybe_make_linked_target_message(OutputFileName),
|
|
|
|
%
|
|
% Find the extra object files for externally compiled
|
|
% foreign procedures and fact tables. We don't need
|
|
% to include these in the timestamp checking above --
|
|
% they will have been checked when the module's object
|
|
% file was built.
|
|
%
|
|
list__map_foldl2(
|
|
(pred(ModuleName::in, ForeignFiles::out,
|
|
MakeInfo0::in, MakeInfo::out, di, uo) is det -->
|
|
get_module_dependencies(ModuleName, MaybeImports,
|
|
MakeInfo0, MakeInfo),
|
|
(
|
|
{ MaybeImports = yes(Imports) },
|
|
external_foreign_code_files(PIC,
|
|
Imports, ForeignFiles)
|
|
;
|
|
{ MaybeImports = no },
|
|
% This error should have been detected earlier.
|
|
{ error(
|
|
"build_linked_target: error in dependencies") }
|
|
)
|
|
), AllModulesList, ExtraForeignFiles, Info3, Info4),
|
|
{ ForeignObjects = list__map(
|
|
(func(foreign_code_file(_, _, ObjFile)) = ObjFile),
|
|
list__condense(ExtraForeignFiles)) },
|
|
|
|
maybe_pic_object_file_extension(PIC, ObjExtToUse),
|
|
list__map_foldl(
|
|
(pred(ObjModule::in, ObjToLink::out, di, uo) is det -->
|
|
module_name_to_file_name(ObjModule,
|
|
ObjExtToUse, no, ObjToLink)
|
|
), ObjModules, ObjList),
|
|
|
|
% LinkObjects may contain `.a' files which must come
|
|
% after all the object files on the linker command line.
|
|
{ AllObjects = InitObjects ++ ObjList ++
|
|
ForeignObjects ++ LinkObjects },
|
|
|
|
(
|
|
{ CompilationTarget = c },
|
|
% Run the link in a separate process so it can
|
|
% be killed if an interrupt is received.
|
|
call_in_forked_process(
|
|
compile_target_code__link(ErrorStream,
|
|
FileType, MainModuleName, AllObjects),
|
|
Succeeded)
|
|
;
|
|
{ CompilationTarget = asm },
|
|
% Run the link in a separate process so it can
|
|
% be killed if an interrupt is received.
|
|
call_in_forked_process(
|
|
compile_target_code__link(ErrorStream,
|
|
FileType, MainModuleName, AllObjects),
|
|
Succeeded)
|
|
;
|
|
{ CompilationTarget = il },
|
|
{ Succeeded = yes }
|
|
;
|
|
{ CompilationTarget = java },
|
|
{ Succeeded = no },
|
|
io__write_string(
|
|
"Sorry, not implemented, linking for `--target java'")
|
|
),
|
|
|
|
{ Info5 = Info4 ^ command_line_targets :=
|
|
set__delete(Info4 ^ command_line_targets,
|
|
MainModuleName - linked_target(FileType)) },
|
|
( { Succeeded = yes } ->
|
|
{ Info = Info5 ^ file_timestamps :=
|
|
map__delete(Info5 ^ file_timestamps,
|
|
OutputFileName) }
|
|
;
|
|
file_error(OutputFileName),
|
|
{ Info = Info5 }
|
|
)
|
|
),
|
|
globals__io_set_option(link_objects, accumulating(LinkObjects)).
|
|
|
|
:- pred linked_target_cleanup(module_name::in, linked_target_type::in,
|
|
file_name::in, compilation_target::in, make_info::in, make_info::out,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
linked_target_cleanup(MainModuleName, FileType, OutputFileName,
|
|
CompilationTarget, Info0, Info) -->
|
|
remove_file(OutputFileName, Info0, Info1),
|
|
(
|
|
{ FileType = executable },
|
|
{ CompilationTarget = c
|
|
; CompilationTarget = asm
|
|
}
|
|
->
|
|
remove_init_files(MainModuleName, Info1, Info)
|
|
;
|
|
{ Info = Info1 }
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
make_misc_target(MainModuleName - TargetType, Succeeded, Info0, Info) -->
|
|
build_with_module_options(MainModuleName, [],
|
|
make_misc_target(MainModuleName - TargetType),
|
|
Succeeded, Info0, Info).
|
|
|
|
:- pred make_misc_target(pair(module_name, misc_target_type)::in,
|
|
list(string)::in, bool::out, make_info::in, make_info::out,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
make_misc_target(MainModuleName - TargetType, _, Succeeded, Info0, Info) -->
|
|
% Don't rebuild dependencies when cleaning up.
|
|
{ RebuildDeps = Info0 ^ rebuild_dependencies },
|
|
{ ( TargetType = clean ; TargetType = realclean ) ->
|
|
Info1 = Info0 ^ rebuild_dependencies := no
|
|
;
|
|
Info1 = Info0
|
|
},
|
|
find_reachable_local_modules(MainModuleName, Succeeded0,
|
|
AllModules0, Info1, Info2),
|
|
{ Info3 = Info2 ^ rebuild_dependencies := RebuildDeps },
|
|
|
|
{ AllModules = set__to_sorted_list(AllModules0) },
|
|
(
|
|
{ TargetType = clean },
|
|
{ Succeeded = yes },
|
|
list__foldl2(make_module_clean, AllModules, Info3, Info4),
|
|
remove_init_files(MainModuleName, Info4, Info)
|
|
;
|
|
{ TargetType = realclean },
|
|
{ Succeeded = yes },
|
|
make_main_module_realclean(MainModuleName, Info3, Info4),
|
|
list__foldl2(make_module_realclean, AllModules, Info4, Info)
|
|
;
|
|
{ TargetType = build_all(ModuleTargetType) },
|
|
get_target_modules(ModuleTargetType, AllModules,
|
|
TargetModules, Info3, Info4),
|
|
globals__io_lookup_bool_option(keep_going, KeepGoing),
|
|
( { Succeeded0 = no, KeepGoing = no } ->
|
|
{ Info = Info4 },
|
|
{ Succeeded = no }
|
|
;
|
|
foldl2_maybe_stop_at_error(KeepGoing,
|
|
make_module_target,
|
|
make_dependency_list(TargetModules,
|
|
ModuleTargetType),
|
|
Succeeded1, Info4, Info),
|
|
{ Succeeded = Succeeded0 `and` Succeeded1 }
|
|
)
|
|
;
|
|
{ TargetType = build_library },
|
|
{ ShortInts = make_dependency_list(AllModules,
|
|
unqualified_short_interface) },
|
|
{ LongInts = make_dependency_list(AllModules,
|
|
long_interface) },
|
|
globals__io_lookup_bool_option(intermodule_optimization,
|
|
Intermod),
|
|
{ Intermod = yes ->
|
|
OptFiles = make_dependency_list(AllModules,
|
|
intermodule_interface)
|
|
;
|
|
OptFiles = []
|
|
},
|
|
globals__io_lookup_bool_option(keep_going, KeepGoing),
|
|
foldl2_maybe_stop_at_error(KeepGoing,
|
|
foldl2_maybe_stop_at_error(KeepGoing,
|
|
make_module_target),
|
|
[ShortInts, LongInts, OptFiles],
|
|
IntSucceeded, Info3, Info4),
|
|
( { IntSucceeded = yes } ->
|
|
% Errors while making the `.init' file should be very rare.
|
|
io__output_stream(ErrorStream),
|
|
compile_target_code__make_init_file(ErrorStream,
|
|
MainModuleName, AllModules, InitSucceeded),
|
|
( { InitSucceeded = yes } ->
|
|
make_linked_target(MainModuleName - static_library,
|
|
StaticSucceeded, Info4, Info5),
|
|
( { StaticSucceeded = yes } ->
|
|
make_linked_target(
|
|
MainModuleName - shared_library,
|
|
Succeeded, Info5, Info)
|
|
;
|
|
{ Succeeded = no },
|
|
{ Info = Info5 }
|
|
)
|
|
;
|
|
{ Succeeded = no },
|
|
{ Info = Info4 }
|
|
)
|
|
;
|
|
{ Succeeded = no },
|
|
{ Info = Info4 }
|
|
)
|
|
;
|
|
{ TargetType = install_library },
|
|
make_misc_target(MainModuleName - build_library,
|
|
LibSucceeded, Info3, Info4),
|
|
( { LibSucceeded = yes } ->
|
|
install_library(MainModuleName, Succeeded, Info4, Info)
|
|
;
|
|
{ Info = Info4 },
|
|
{ Succeeded = no }
|
|
)
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred install_library(module_name::in, bool::out,
|
|
make_info::in, make_info::out, io__state::di, io__state::uo) is det.
|
|
|
|
install_library(MainModuleName, Succeeded, Info0, Info) -->
|
|
find_reachable_local_modules(MainModuleName, DepsSuccess,
|
|
AllModules0, Info0, Info1),
|
|
{ AllModules = set__to_sorted_list(AllModules0) },
|
|
make_install_dirs(DirSucceeded, LinkSucceeded),
|
|
( { DepsSuccess = yes, DirSucceeded = yes } ->
|
|
globals__io_lookup_string_option(install_prefix, Prefix),
|
|
|
|
{ ModulesDir = Prefix/"lib"/"mercury"/"modules" },
|
|
module_name_to_file_name(MainModuleName, ".init", no, InitFileName),
|
|
install_file(InitFileName, ModulesDir, InitSucceded),
|
|
|
|
list__map_foldl2(install_ints_and_headers(LinkSucceeded), AllModules,
|
|
IntsSucceeded, Info1, Info2),
|
|
|
|
globals__io_get_globals(Globals),
|
|
{ grade_directory_component(Globals, Grade) },
|
|
install_library_grade_files(LinkSucceeded, Grade, MainModuleName,
|
|
AllModules, GradeSucceeded, Info2, Info3),
|
|
(
|
|
{ InitSucceded = yes },
|
|
{ bool__and_list(IntsSucceeded) = yes },
|
|
{ GradeSucceeded = yes }
|
|
->
|
|
% XXX With Mmake, LIBGRADES is target-specific.
|
|
globals__io_lookup_accumulating_option(libgrades, LibGrades0),
|
|
globals__io_lookup_bool_option(keep_going, KeepGoing),
|
|
{ LibGrades = list__delete_all(LibGrades0, Grade) },
|
|
foldl2_maybe_stop_at_error(KeepGoing,
|
|
install_library_grade(LinkSucceeded,
|
|
MainModuleName, AllModules),
|
|
LibGrades, Succeeded, Info3, Info)
|
|
;
|
|
{ Info = Info3 },
|
|
{ Succeeded = no }
|
|
)
|
|
;
|
|
{ Info = Info1 },
|
|
{ Succeeded = no }
|
|
).
|
|
|
|
:- pred install_ints_and_headers(bool::in, module_name::in, bool::out,
|
|
make_info::in, make_info::out, io__state::di, io__state::uo) is det.
|
|
|
|
install_ints_and_headers(SubdirLinkSucceeded, ModuleName,
|
|
Succeeded, Info0, Info) -->
|
|
get_module_dependencies(ModuleName, MaybeImports, Info0, Info),
|
|
(
|
|
{ MaybeImports = yes(Imports) },
|
|
globals__io_lookup_bool_option(intermodule_optimization, Intermod),
|
|
{ Intermod = yes ->
|
|
% `.int0' files are imported by `.opt' files.
|
|
Exts =
|
|
( Imports ^ children \= [] -> ["int0", "opt"] ; ["opt"] )
|
|
;
|
|
Exts = []
|
|
},
|
|
|
|
globals__io_lookup_string_option(install_prefix, Prefix),
|
|
{ LibDir = Prefix/"lib"/"mercury" },
|
|
list__map_foldl(
|
|
install_subdir_file(SubdirLinkSucceeded,
|
|
LibDir/"ints", ModuleName),
|
|
["int", "int2", "int3", "module_dep" | Exts],
|
|
Results),
|
|
|
|
globals__io_get_target(Target),
|
|
(
|
|
% `.mh' files are only generated for modules containing
|
|
% `:- pragma export' declarations.
|
|
{ Target = c ; Target = asm },
|
|
{ Imports ^ contains_foreign_export = contains_foreign_export }
|
|
->
|
|
install_subdir_file(SubdirLinkSucceeded, LibDir/"inc",
|
|
ModuleName, "mh", HeaderSucceded1),
|
|
|
|
% This is needed so that the file will be
|
|
% found in Mmake's VPATH.
|
|
install_subdir_file(SubdirLinkSucceeded, LibDir/"ints",
|
|
ModuleName, "mh", HeaderSucceded2),
|
|
|
|
{ HeaderSucceded = HeaderSucceded1 `and` HeaderSucceded2 }
|
|
;
|
|
{ HeaderSucceded = yes }
|
|
),
|
|
{ Succeeded = bool__and_list([HeaderSucceded | Results]) }
|
|
;
|
|
{ MaybeImports = no },
|
|
{ Succeeded = no }
|
|
).
|
|
|
|
:- pred install_library_grade(bool::in, module_name::in, list(module_name)::in,
|
|
string::in, bool::out, make_info::in, make_info::out,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
install_library_grade(LinkSucceeded0, ModuleName, AllModules, Grade,
|
|
Succeeded, Info0, Info) -->
|
|
%
|
|
% Building the library in the new grade is done in a separate
|
|
% process to make it easier to stop and clean up on an interrupt.
|
|
%
|
|
{ Cleanup = make_grade_clean(ModuleName, AllModules) },
|
|
build_with_check_for_interrupt(
|
|
(pred(GradeSuccess::out, MInfo::in, MInfo::out, di, uo) is det -->
|
|
call_in_forked_process(
|
|
(pred(GradeSuccess0::out, di, uo) is det -->
|
|
install_library_grade_2(LinkSucceeded0,
|
|
Grade, ModuleName, AllModules,
|
|
MInfo, GradeSuccess0)
|
|
), GradeSuccess)
|
|
), Cleanup, Succeeded, Info0, Info).
|
|
|
|
:- pred install_library_grade_2(bool::in, string::in, module_name::in,
|
|
list(module_name)::in, make_info::in,
|
|
bool::out, io__state::di, io__state::uo) is det.
|
|
|
|
install_library_grade_2(LinkSucceeded0, Grade, ModuleName, AllModules,
|
|
Info0, Succeeded) -->
|
|
globals__io_get_globals(Globals),
|
|
|
|
%
|
|
% Set up so that grade-dependent files for the current grade
|
|
% don't overwrite the files for the default grade.
|
|
%
|
|
{ OptionArgs0 = Info0 ^ option_args },
|
|
{ OptionArgs = OptionArgs0 ++
|
|
["--grade", Grade, "--use-grade-subdirs"] },
|
|
|
|
verbose_msg(
|
|
(pred(di, uo) is det -->
|
|
io__write_string("Installing grade "),
|
|
io__write_string(Grade),
|
|
io__nl
|
|
)),
|
|
|
|
lookup_mmc_options(Info0 ^ options_variables, MaybeMCFlags),
|
|
(
|
|
{ MaybeMCFlags = yes(MCFlags) },
|
|
handle_options(MCFlags ++ OptionArgs, OptionsError, _, _, _)
|
|
;
|
|
{ MaybeMCFlags = no },
|
|
% Errors should have been caught before.
|
|
{ error("install_library_grade: bad DEFAULT_MCFLAGS") }
|
|
),
|
|
|
|
(
|
|
{ OptionsError = yes(OptionsMessage) },
|
|
usage_error(OptionsMessage),
|
|
{ Succeeded = no }
|
|
;
|
|
{ OptionsError = no },
|
|
%
|
|
% Remove the grade-dependent targets from the status map
|
|
% (we need to rebuild them in the new grade).
|
|
%
|
|
{ StatusMap0 = Info0 ^ dependency_status },
|
|
{ StatusMap = map__from_assoc_list(list__filter(
|
|
(pred((File - _)::in) is semidet :-
|
|
\+ (
|
|
File = target(_ - Target),
|
|
target_is_grade_or_arch_dependent(Target)
|
|
)
|
|
),
|
|
map__to_assoc_list(StatusMap0))) },
|
|
{ Info1 = (Info0 ^ dependency_status := StatusMap)
|
|
^ option_args := OptionArgs },
|
|
|
|
make_misc_target(ModuleName - build_library,
|
|
LibSucceeded, Info1, Info2),
|
|
( { LibSucceeded = yes } ->
|
|
install_library_grade_files(LinkSucceeded0,
|
|
Grade, ModuleName, AllModules,
|
|
Succeeded, Info2, Info3),
|
|
|
|
make_grade_clean(ModuleName, AllModules,
|
|
Info3, _)
|
|
;
|
|
{ Succeeded = no }
|
|
)
|
|
),
|
|
globals__io_set_globals(unsafe_promise_unique(Globals)).
|
|
|
|
% Install the `.a', `.so, `.opt' and `.mih' files
|
|
% for the current grade.
|
|
:- pred install_library_grade_files(bool::in, string::in, module_name::in,
|
|
list(module_name)::in, bool::out, make_info::in, make_info::out,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
install_library_grade_files(LinkSucceeded0, Grade, ModuleName, AllModules,
|
|
Succeeded, Info0, Info) -->
|
|
make_grade_install_dirs(Grade, DirResult, LinkSucceeded1),
|
|
{ LinkSucceeded = LinkSucceeded0 `and` LinkSucceeded1 },
|
|
( { DirResult = yes } ->
|
|
linked_target_file_name(ModuleName, static_library, LibFileName),
|
|
linked_target_file_name(ModuleName, shared_library, SharedLibFileName),
|
|
|
|
globals__io_lookup_string_option(install_prefix, Prefix),
|
|
globals__io_lookup_string_option(fullarch, FullArch),
|
|
{ GradeLibDir = Prefix/"lib"/"mercury"/"lib"/Grade/FullArch },
|
|
|
|
install_file(LibFileName, GradeLibDir, LibSucceded),
|
|
install_file(SharedLibFileName, GradeLibDir, SharedLibSucceded),
|
|
|
|
list__map_foldl2(install_grade_ints_and_headers(LinkSucceeded, Grade),
|
|
AllModules, IntsHeadersSucceded, Info0, Info),
|
|
{ Succeeded = bool__and_list(
|
|
[LibSucceded, SharedLibSucceded | IntsHeadersSucceded]) }
|
|
;
|
|
{ Succeeded = no },
|
|
{ Info = Info0 }
|
|
).
|
|
|
|
% Install the `.opt' and `.mih' files for the current grade.
|
|
:- pred install_grade_ints_and_headers(bool::in, string::in, module_name::in,
|
|
bool::out, make_info::in, make_info::out,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
install_grade_ints_and_headers(LinkSucceeded, Grade, ModuleName,
|
|
Succeeded, Info0, Info) -->
|
|
get_module_dependencies(ModuleName, MaybeImports, Info0, Info),
|
|
(
|
|
{ MaybeImports = yes(Imports) },
|
|
globals__io_lookup_string_option(install_prefix, Prefix),
|
|
globals__io_lookup_string_option(fullarch, FullArch),
|
|
{ LibDir = Prefix/"lib"/"mercury" },
|
|
|
|
globals__io_get_target(Target),
|
|
globals__io_lookup_bool_option(highlevel_code, HighLevelCode),
|
|
(
|
|
{ Target = c, HighLevelCode = yes
|
|
; Target = asm,
|
|
Imports ^ foreign_code = contains_foreign_code(_)
|
|
}
|
|
->
|
|
{ GradeIncDir = LibDir/"lib"/Grade/FullArch/"inc" },
|
|
install_subdir_file(LinkSucceeded, GradeIncDir,
|
|
ModuleName, "mih", HeaderSucceded1),
|
|
|
|
% This is needed so that the file will be
|
|
% found in Mmake's VPATH.
|
|
{ IntDir = LibDir/"int" },
|
|
install_subdir_file(LinkSucceeded, IntDir,
|
|
ModuleName, "mih", HeaderSucceded2),
|
|
|
|
{ HeaderSucceded = HeaderSucceded1 `and` HeaderSucceded2 }
|
|
;
|
|
{ HeaderSucceded = yes }
|
|
),
|
|
|
|
globals__io_lookup_bool_option(intermodule_optimization, Intermod),
|
|
( { Intermod = yes } ->
|
|
{ GradeIntDir = LibDir/"ints"/Grade },
|
|
install_subdir_file(LinkSucceeded, GradeIntDir,
|
|
ModuleName, "opt", OptSucceded)
|
|
;
|
|
{ OptSucceded = yes }
|
|
),
|
|
{ Succeeded = HeaderSucceded `and` OptSucceded }
|
|
;
|
|
{ MaybeImports = no },
|
|
{ Succeeded = no }
|
|
).
|
|
|
|
% Install a file in the given directory, and in
|
|
% directory/Mercury/exts if the symlinks for the
|
|
% subdirectories couldn't be created (e.g. on Windows).
|
|
:- pred install_subdir_file(bool::in, dir_name::in, module_name::in,
|
|
string::in, bool::out, io__state::di, io__state::uo) is det.
|
|
|
|
install_subdir_file(SubdirLinkSucceeded, InstallDir,
|
|
ModuleName, Ext, Succeeded) -->
|
|
module_name_to_file_name(ModuleName, "." ++ Ext, no, FileName),
|
|
install_file(FileName, InstallDir, Succeeded1),
|
|
( { SubdirLinkSucceeded = no } ->
|
|
install_file(FileName, InstallDir/"Mercury"/(Ext ++ "s"),
|
|
Succeeded2),
|
|
{ Succeeded = Succeeded1 `and` Succeeded2 }
|
|
;
|
|
{ Succeeded = Succeeded1 }
|
|
).
|
|
|
|
:- pred install_file(file_name::in, dir_name::in, bool::out,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
install_file(FileName, InstallDir, Succeeded) -->
|
|
verbose_msg(
|
|
(pred(di, uo) is det -->
|
|
io__write_string("Installing file "),
|
|
io__write_string(FileName),
|
|
io__write_string(" in "),
|
|
io__write_string(InstallDir),
|
|
io__nl
|
|
)),
|
|
globals__io_lookup_string_option(install_command, InstallCommand),
|
|
{ Command = string__join_list(" ", list__map(quote_arg,
|
|
[InstallCommand, FileName, InstallDir])) },
|
|
io__output_stream(OutputStream),
|
|
invoke_system_command(OutputStream, verbose, Command, Succeeded).
|
|
|
|
:- pred make_install_dirs(bool::out, bool::out,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
make_install_dirs(Result, LinkResult) -->
|
|
globals__io_lookup_string_option(install_prefix, Prefix),
|
|
{ LibDir = Prefix/"lib"/"mercury" },
|
|
make_directory(LibDir/"inc", Result1),
|
|
make_directory(LibDir/"modules", Result2),
|
|
|
|
{ IntsSubdir = LibDir/"ints"/"Mercury" },
|
|
make_directory(IntsSubdir, Result3),
|
|
{ Results0 = [Result1, Result2, Result3] },
|
|
|
|
{ Subdirs = ["int0", "int", "int2", "int3",
|
|
"opt", "trans_opt", "module_dep"] },
|
|
list__map_foldl(make_install_symlink(IntsSubdir),
|
|
Subdirs, LinkResults),
|
|
{ LinkResult = bool__and_list(LinkResults) },
|
|
( { LinkResult = yes } ->
|
|
{ Results = Results0 }
|
|
;
|
|
list__map_foldl(
|
|
(pred(Ext::in, MkDirResult::out, di, uo) is det -->
|
|
make_directory(IntsSubdir/(Ext ++ "s"),
|
|
MkDirResult)
|
|
), Subdirs, MkDirResults),
|
|
{ Results = Results0 ++ MkDirResults }
|
|
),
|
|
print_mkdir_errors(Results, Result).
|
|
|
|
:- pred make_grade_install_dirs(string::in, bool::out, bool::out,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
make_grade_install_dirs(Grade, Result, LinkResult) -->
|
|
globals__io_lookup_string_option(install_prefix, Prefix),
|
|
globals__io_lookup_string_option(fullarch, FullArch),
|
|
{ LibDir = Prefix/"lib"/"mercury" },
|
|
|
|
{ GradeIntsSubdir = LibDir/"ints"/Grade/"Mercury" },
|
|
make_directory(GradeIntsSubdir, Result1),
|
|
|
|
{ GradeIncSubdir = LibDir/"lib"/Grade/FullArch/"inc"/"Mercury" },
|
|
make_directory(GradeIncSubdir, Result2),
|
|
|
|
{ Results0 = [Result1, Result2] },
|
|
|
|
make_install_symlink(GradeIncSubdir, "mih", LinkResult0),
|
|
list__map_foldl(make_install_symlink(GradeIntsSubdir),
|
|
["opt", "trans_opt"], LinkResults),
|
|
{ LinkResult = bool__and_list([LinkResult0 | LinkResults]) },
|
|
( { LinkResult = yes } ->
|
|
{ Results = Results0 }
|
|
;
|
|
make_directory(GradeIncSubdir/"mih", Result4),
|
|
make_directory(GradeIntsSubdir/"opts", Result5),
|
|
make_directory(GradeIntsSubdir/"trans_opts",
|
|
Result6),
|
|
{ Results = [Result4, Result5, Result6 | Results0] }
|
|
),
|
|
print_mkdir_errors(Results, Result).
|
|
|
|
:- pred print_mkdir_errors(list(io__res)::in, bool::out,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
print_mkdir_errors([], yes) --> [].
|
|
print_mkdir_errors([ok | Rest], Succeeded) -->
|
|
print_mkdir_errors(Rest, Succeeded).
|
|
print_mkdir_errors([error(Error) | Rest], no) -->
|
|
io__write_string("Error creating installation directories: "),
|
|
io__write_string(io__error_message(Error)),
|
|
io__nl,
|
|
print_mkdir_errors(Rest, _).
|
|
|
|
:- pred make_install_symlink(string::in, string::in, bool::out,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
make_install_symlink(Subdir, Ext, Succeeded) -->
|
|
{ LinkName = Subdir/(Ext ++ "s") },
|
|
maybe_make_symlink("..", LinkName, Succeeded).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Clean up grade-dependent files.
|
|
:- pred make_grade_clean(module_name::in, list(module_name)::in,
|
|
make_info::in, make_info::out, io__state::di, io__state::uo) is det.
|
|
|
|
make_grade_clean(ModuleName, AllModules, Info0, Info) -->
|
|
make_main_module_realclean(ModuleName, Info0, Info1),
|
|
list__foldl2(make_module_clean, AllModules, Info1, Info).
|
|
|
|
:- pred make_main_module_realclean(module_name::in,
|
|
make_info::in, make_info::out,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
make_main_module_realclean(ModuleName, Info0, Info) -->
|
|
linked_target_file_name(ModuleName, executable, ExeFileName),
|
|
linked_target_file_name(ModuleName, static_library, LibFileName),
|
|
linked_target_file_name(ModuleName, shared_library, SharedLibFileName),
|
|
|
|
% Remove the symlinks created for `--use-grade-subdirs'.
|
|
globals__io_lookup_bool_option(use_grade_subdirs, UseGradeSubdirs),
|
|
globals__io_set_option(use_grade_subdirs, bool(no)),
|
|
linked_target_file_name(ModuleName, executable, ThisDirExeFileName),
|
|
linked_target_file_name(ModuleName, static_library,
|
|
ThisDirLibFileName),
|
|
linked_target_file_name(ModuleName, shared_library,
|
|
ThisDirSharedLibFileName),
|
|
globals__io_set_option(use_grade_subdirs, bool(UseGradeSubdirs)),
|
|
|
|
list__foldl2(remove_file,
|
|
[ExeFileName, LibFileName, SharedLibFileName,
|
|
ThisDirExeFileName, ThisDirLibFileName,
|
|
ThisDirSharedLibFileName],
|
|
Info0, Info1),
|
|
remove_file(ModuleName, ".init", Info1, Info2),
|
|
remove_init_files(ModuleName, Info2, Info).
|
|
|
|
:- pred remove_init_files(module_name::in, make_info::in, make_info::out,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
remove_init_files(ModuleName, Info0, Info) -->
|
|
globals__io_lookup_string_option(object_file_extension, ObjExt),
|
|
globals__io_lookup_string_option(pic_object_file_extension, PicObjExt),
|
|
globals__io_lookup_string_option(link_with_pic_object_file_extension,
|
|
LinkWithPicObjExt),
|
|
list__foldl2(remove_file(ModuleName), ["_init.c", "_init" ++ ObjExt,
|
|
"_init" ++ PicObjExt, "_init" ++ LinkWithPicObjExt],
|
|
Info0, Info).
|
|
|
|
:- pred make_module_clean(module_name::in, make_info::in, make_info::out,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
make_module_clean(ModuleName, !Info) -->
|
|
list__foldl2(remove_target_file(ModuleName),
|
|
[errors, c_code, c_header(mih), il_code, java_code],
|
|
!Info),
|
|
|
|
list__foldl2(remove_file(ModuleName),
|
|
[".used", ".prof", ".derived_schema", ".base_schema"],
|
|
!Info),
|
|
|
|
get_module_dependencies(ModuleName, MaybeImports,
|
|
!Info),
|
|
{
|
|
MaybeImports = yes(Imports),
|
|
FactTableFiles = Imports ^ fact_table_deps
|
|
;
|
|
MaybeImports = no,
|
|
FactTableFiles = []
|
|
},
|
|
|
|
list__foldl2(
|
|
(pred(FactTableFile::in, !.Info::in, !:Info::out,
|
|
di, uo) is det -->
|
|
fact_table_file_name(ModuleName, FactTableFile,
|
|
".c", no, FactTableCFile),
|
|
remove_file(FactTableCFile, !Info)
|
|
), FactTableFiles, !Info),
|
|
|
|
{ CCodeModule = foreign_language_module_name(ModuleName, c) },
|
|
remove_target_file(CCodeModule, c_code, !Info),
|
|
|
|
%
|
|
% Remove object and assembler files.
|
|
%
|
|
list__foldl2(
|
|
(pred(PIC::in, !.Info::in, !:Info::out, di, uo) is det -->
|
|
remove_target_file(ModuleName, object_code(PIC), !Info),
|
|
remove_target_file(ModuleName, asm_code(PIC), !Info),
|
|
remove_target_file(ModuleName, foreign_object(PIC, c), !Info),
|
|
list__foldl2(
|
|
(pred(FactTableFile::in, !.Info::in, !:Info::out,
|
|
di, uo) is det -->
|
|
remove_target_file(ModuleName,
|
|
fact_table_object(PIC, FactTableFile), !Info)
|
|
), FactTableFiles, !Info)
|
|
),
|
|
[pic, link_with_pic, non_pic], !Info),
|
|
|
|
%
|
|
% Remove IL foreign code files.
|
|
%
|
|
{ CSharpModule = foreign_language_module_name(ModuleName, csharp) },
|
|
remove_file(CSharpModule, foreign_language_file_extension(csharp),
|
|
!Info),
|
|
remove_target_file(CSharpModule, foreign_il_asm(csharp), !Info),
|
|
|
|
{ McppModule = foreign_language_module_name(ModuleName,
|
|
managed_cplusplus) },
|
|
remove_file(McppModule,
|
|
foreign_language_file_extension(managed_cplusplus),
|
|
!Info),
|
|
remove_target_file(McppModule, foreign_il_asm(managed_cplusplus),
|
|
!Info).
|
|
|
|
:- pred make_module_realclean(module_name::in, make_info::in, make_info::out,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
make_module_realclean(ModuleName, Info0, Info) -->
|
|
make_module_clean(ModuleName, Info0, Info1),
|
|
list__foldl2(remove_target_file(ModuleName),
|
|
[private_interface, long_interface, short_interface,
|
|
unqualified_short_interface, intermodule_interface,
|
|
aditi_code, c_header(mh)
|
|
],
|
|
Info1, Info2),
|
|
remove_file(ModuleName, module_dep_file_extension, Info2, Info).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- func this_file = string.
|
|
this_file = "make.program_target.m".
|
|
|
|
%-----------------------------------------------------------------------------%
|