mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-16 18:03:36 +00:00
When writing out dependency files, the compiler would call
module_name_to_file_name often for the same pairs of module name and
file extension. Caching the results of those calls saves on
constructing temporary strings.
This change reduces the time to make dependencies in the compiler
directory from 2.40 seconds to 2.15 seconds on my machine.
compiler/write_deps_file.m:
Add a predicate make_module_file_name that caches calls to
module_name_to_file_name.
Thread the cache map through the predicates in this module.
Replace calls to module_name_to_file_name with calls to
make_module_file_name when appropriate.
2746 lines
120 KiB
Mathematica
2746 lines
120 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 2008-2011 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: write_deps_file.m.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module parse_tree.write_deps_file.
|
|
:- interface.
|
|
|
|
:- import_module libs.
|
|
:- import_module libs.file_util.
|
|
:- import_module libs.globals.
|
|
:- import_module mdbcomp.
|
|
:- import_module mdbcomp.sym_name.
|
|
:- import_module parse_tree.deps_map.
|
|
:- import_module parse_tree.file_names.
|
|
:- import_module parse_tree.module_baggage.
|
|
:- import_module parse_tree.module_deps_graph.
|
|
|
|
:- import_module bool.
|
|
:- import_module io.
|
|
:- import_module list.
|
|
:- import_module set.
|
|
|
|
:- type maybe_intermod_deps
|
|
---> no_intermod_deps
|
|
; intermod_deps(
|
|
id_int_deps :: set(module_name),
|
|
id_imp_deps :: set(module_name),
|
|
id_indirect_deps :: set(module_name),
|
|
id_fim_deps :: set(module_name),
|
|
% id_trans_opt_deps is the set of modules whose .trans_opt
|
|
% files that we may want to read when *making* this module's
|
|
% .trans_opt file. However, it still may need to be reduced
|
|
% further to prevent circularities in trans_opt_deps mmake
|
|
% rules.
|
|
id_trans_opt_deps :: set(module_name)
|
|
).
|
|
|
|
:- type maybe_include_trans_opt_rule
|
|
---> do_not_include_trans_opt_rule
|
|
; include_trans_opt_rule(trans_opt_rule_info).
|
|
|
|
% The set of trans-opt dependencies can come from two sources:
|
|
% - from a topological sort of the trans-opt dependency graph
|
|
% if we built the graph; or
|
|
% - from a trans_opt_deps rule in a .d file.
|
|
%
|
|
:- type trans_opt_rule_info
|
|
---> trans_opt_deps_from_order(set(module_name))
|
|
; trans_opt_deps_from_d_file(set(module_name)).
|
|
|
|
% write_dependency_file(Globals, BurdenedAugCompUnit, MaybeIntermodDeps,
|
|
% AllDeps, MaybeInclTransOptRule, !IO):
|
|
%
|
|
% Write out the per-module makefile dependencies (`.d') file for the
|
|
% specified module. AllDeps is the set of all module names which the
|
|
% generated code for this module might depend on, i.e. all that have been
|
|
% used or imported, directly or indirectly, into this module, including
|
|
% via .opt or .trans_opt files, and including parent modules of nested
|
|
% modules. MaybeInclTransOptRule controls whether to include a
|
|
% trans_opt_deps rule in the file, and if so, what the rule should say.
|
|
%
|
|
% XXX The MaybeIntermodDeps allows generate_dependencies_write_d_file
|
|
% to supply some information derived from the overall dependency graph
|
|
% that is intended to override the values of some of the fields in
|
|
% BurdenedAugCompUnit. These used to be passed in a ModuleAndImports
|
|
% argument itself (the predecessor of BurdenedAugCompUnit), but they
|
|
% do not actually belong there, since the overridden fields are
|
|
% supposed to be *solely* from the main module in BurdenedAugCompUnit.
|
|
% As to *why* this overriding is desirable, I (zs) don't know, and
|
|
% I am pretty sure that the original author (fjh) does not know anymore
|
|
% either :-(
|
|
%
|
|
:- pred write_dependency_file(globals::in, burdened_aug_comp_unit::in,
|
|
maybe_intermod_deps::in, set(module_name)::in,
|
|
maybe_include_trans_opt_rule::in,
|
|
io::di, io::uo) is det.
|
|
|
|
% generate_dependencies_write_d_files(Globals, Modules,
|
|
% IntDepsGraph, ImplDepsGraph, IndirectDepsGraph, IndirectOptDepsGraph,
|
|
% TransOptDepsGraph, TransOptOrder, DepsMap, !IO):
|
|
%
|
|
% This predicate writes out the .d files for all the modules in the
|
|
% Modules list.
|
|
% IntDepsGraph gives the interface dependency graph.
|
|
% ImplDepsGraph gives the implementation dependency graph.
|
|
% IndirectDepsGraph gives the indirect dependency graph
|
|
% (this includes dependencies on `*.int2' files).
|
|
% IndirectOptDepsGraph gives the indirect optimization dependencies
|
|
% (this includes dependencies via `.opt' and `.trans_opt' files).
|
|
% These are all computed from the DepsMap.
|
|
%
|
|
% TransOptDepsGraph gives the trans-opt dependency graph for the
|
|
% purpose of making `.trans_opt' files.
|
|
% TransOptOrder gives the ordering that is used to determine
|
|
% which other modules the .trans_opt files may depend on.
|
|
%
|
|
:- pred generate_dependencies_write_d_files(globals::in, list(deps)::in,
|
|
deps_graph::in, deps_graph::in, deps_graph::in, deps_graph::in,
|
|
deps_graph::in, list(module_name)::in, deps_map::in, io::di, io::uo)
|
|
is det.
|
|
|
|
% Write out the `.dv' file, using the information collected in the
|
|
% deps_map data structure.
|
|
%
|
|
:- pred generate_dependencies_write_dv_file(globals::in, file_name::in,
|
|
module_name::in, deps_map::in, io::di, io::uo) is det.
|
|
|
|
% Write out the `.dep' file, using the information collected in the
|
|
% deps_map data structure.
|
|
%
|
|
:- pred generate_dependencies_write_dep_file(globals::in, file_name::in,
|
|
module_name::in, deps_map::in, io::di, io::uo) is det.
|
|
|
|
:- pred output_module_order(globals::in, module_name::in, other_ext::in,
|
|
list(set(module_name))::in, io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% For each dependency, search intermod_directories for a file with
|
|
% the given extension, filtering out those for which the search fails.
|
|
% If --use-opt-files is set, only look for `.opt' files,
|
|
% not `.m' files.
|
|
% XXX This won't find nested submodules.
|
|
% XXX Use `mmc --make' if that matters.
|
|
%
|
|
% This predicate must operate on lists, not sets, of module names,
|
|
% because it needs to preserve the chosen trans_opt deps ordering,
|
|
% which is derived from the dependency graph between modules,
|
|
% and not just the modules' names.
|
|
%
|
|
:- pred get_opt_deps(globals::in, bool::in, list(string)::in, other_ext::in,
|
|
list(module_name)::in, list(module_name)::out, io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module libs.mmakefiles.
|
|
:- import_module libs.options.
|
|
:- import_module parse_tree.find_module. % XXX undesirable dependency
|
|
:- import_module parse_tree.get_dependencies.
|
|
:- import_module parse_tree.module_cmds.
|
|
:- import_module parse_tree.parse_error.
|
|
:- import_module parse_tree.prog_data.
|
|
:- import_module parse_tree.prog_data_foreign.
|
|
:- import_module parse_tree.prog_foreign.
|
|
:- import_module parse_tree.prog_item.
|
|
:- import_module parse_tree.prog_out.
|
|
:- import_module parse_tree.source_file_map.
|
|
|
|
:- import_module assoc_list.
|
|
:- import_module cord.
|
|
:- import_module digraph.
|
|
:- import_module dir.
|
|
:- import_module io.file.
|
|
:- import_module library.
|
|
:- import_module map.
|
|
:- import_module maybe.
|
|
:- import_module one_or_more.
|
|
:- import_module one_or_more_map.
|
|
:- import_module pair.
|
|
:- import_module require.
|
|
:- import_module sparse_bitset.
|
|
:- import_module string.
|
|
|
|
:- type module_file_name_cache == map(module_name_and_ext, file_name).
|
|
|
|
:- type module_name_and_ext
|
|
---> module_name_and_ext(module_name, other_ext).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
write_dependency_file(Globals, BurdenedAugCompUnit, IntermodDeps, AllDeps,
|
|
MaybeInclTransOptRule, !IO) :-
|
|
map.init(Cache0),
|
|
write_dependency_file_fn_cache(Globals, BurdenedAugCompUnit, IntermodDeps,
|
|
AllDeps, MaybeInclTransOptRule, Cache0, _Cache, !IO).
|
|
|
|
:- pred write_dependency_file_fn_cache(globals::in,
|
|
burdened_aug_comp_unit::in, maybe_intermod_deps::in, set(module_name)::in,
|
|
maybe_include_trans_opt_rule::in,
|
|
module_file_name_cache::in, module_file_name_cache::out,
|
|
io::di, io::uo) is det.
|
|
|
|
write_dependency_file_fn_cache(Globals, BurdenedAugCompUnit, IntermodDeps,
|
|
AllDeps, MaybeInclTransOptRule, !Cache, !IO) :-
|
|
% To avoid problems with concurrent updates of `.d' files during
|
|
% parallel makes, we first create the file with a temporary name,
|
|
% and then rename it to the desired name when we have finished.
|
|
BurdenedAugCompUnit = burdened_aug_comp_unit(_, AugCompUnit),
|
|
ParseTreeModuleSrc = AugCompUnit ^ acu_module_src,
|
|
ModuleName = ParseTreeModuleSrc ^ ptms_module_name,
|
|
module_name_to_file_name(Globals, $pred, do_create_dirs,
|
|
ext_other(other_ext(".d")), ModuleName, DependencyFileName, !IO),
|
|
io.file.make_temp_file(dir.dirname(DependencyFileName), "tmp_d", "",
|
|
TmpDependencyFileNameRes, !IO),
|
|
get_error_output_stream(Globals, ModuleName, ErrorStream, !IO),
|
|
get_progress_output_stream(Globals, ModuleName, ProgressStream, !IO),
|
|
(
|
|
TmpDependencyFileNameRes = error(Error),
|
|
Message = "Could not create temporary file: " ++ error_message(Error),
|
|
report_error(ErrorStream, Message, !IO)
|
|
;
|
|
TmpDependencyFileNameRes = ok(TmpDependencyFileName),
|
|
globals.lookup_bool_option(Globals, verbose, Verbose),
|
|
(
|
|
Verbose = no
|
|
;
|
|
Verbose = yes,
|
|
io.format(ProgressStream,
|
|
"%% Writing auto-dependency file `%s'...",
|
|
[s(DependencyFileName)], !IO),
|
|
io.flush_output(ProgressStream, !IO)
|
|
),
|
|
io.open_output(TmpDependencyFileName, Result, !IO),
|
|
(
|
|
Result = error(IOError),
|
|
maybe_write_string(ProgressStream, Verbose, " failed.\n", !IO),
|
|
maybe_flush_output(ProgressStream, Verbose, !IO),
|
|
io.error_message(IOError, IOErrorMessage),
|
|
string.format("error opening temporary file `%s' for output: %s",
|
|
[s(TmpDependencyFileName), s(IOErrorMessage)], Message),
|
|
report_error(ErrorStream, Message, !IO)
|
|
;
|
|
Result = ok(DepStream),
|
|
generate_d_file(Globals, BurdenedAugCompUnit, IntermodDeps,
|
|
AllDeps, MaybeInclTransOptRule, MmakeFile, !Cache, !IO),
|
|
write_mmakefile(DepStream, MmakeFile, !IO),
|
|
io.close_output(DepStream, !IO),
|
|
|
|
io.file.rename_file(TmpDependencyFileName, DependencyFileName,
|
|
FirstRenameResult, !IO),
|
|
(
|
|
FirstRenameResult = error(_),
|
|
% On some systems, we need to remove the existing file first,
|
|
% if any. So try again that way.
|
|
io.file.remove_file(DependencyFileName, RemoveResult, !IO),
|
|
(
|
|
RemoveResult = error(Error4),
|
|
maybe_write_string(ProgressStream, Verbose,
|
|
" failed.\n", !IO),
|
|
maybe_flush_output(ProgressStream, Verbose, !IO),
|
|
io.error_message(Error4, ErrorMsg),
|
|
string.format("can't remove file `%s': %s",
|
|
[s(DependencyFileName), s(ErrorMsg)], Message),
|
|
report_error(ErrorStream, Message, !IO)
|
|
;
|
|
RemoveResult = ok,
|
|
io.file.rename_file(TmpDependencyFileName,
|
|
DependencyFileName, SecondRenameResult, !IO),
|
|
(
|
|
SecondRenameResult = error(Error5),
|
|
maybe_write_string(ProgressStream, Verbose,
|
|
" failed.\n", !IO),
|
|
maybe_flush_output(ProgressStream, Verbose, !IO),
|
|
io.error_message(Error5, ErrorMsg),
|
|
string.format("can't rename file `%s' as `%s': %s",
|
|
[s(TmpDependencyFileName), s(DependencyFileName),
|
|
s(ErrorMsg)], Message),
|
|
report_error(ErrorStream, Message, !IO)
|
|
;
|
|
SecondRenameResult = ok,
|
|
maybe_write_string(ProgressStream, Verbose,
|
|
" done.\n", !IO)
|
|
)
|
|
)
|
|
;
|
|
FirstRenameResult = ok,
|
|
maybe_write_string(ProgressStream, Verbose, " done.\n", !IO)
|
|
)
|
|
)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Generate the contents of the module's .d file.
|
|
%
|
|
% The mmake rules we construct treat C differently from Java and C#.
|
|
% The reason is that we support using mmake when targeting C, but require
|
|
% the use of --use-mmc-make when targeting Java and C#.
|
|
%
|
|
% Initially, when the only target language was C, the only build system
|
|
% we had was mmake, so the mmake rules we generate here can do everything
|
|
% that one wants to do when targeting C. When we added the ability to
|
|
% target C# and Erlang, we implemented it for --use-mmc-make only,
|
|
% *not* for mmake, so the entries we generate for C# and Erlang
|
|
% mostly just forward the work to --use-mmc-make. Java is in between;
|
|
% there are more mmake rules for it than for C# or Erlang, but far from
|
|
% enough for full functionality. In an email to m-rev on 2020 may 25,
|
|
% Julien said: "IIRC, most of the mmake rules for Java that are not
|
|
% required by --use-mmc-make are long obsolete". Unfortunately,
|
|
% apparently there is no documentation of *which* mmake rules for Java
|
|
% are required by --use-mmc-make.
|
|
%
|
|
:- pred generate_d_file(globals::in, burdened_aug_comp_unit::in,
|
|
maybe_intermod_deps::in,
|
|
set(module_name)::in, maybe_include_trans_opt_rule::in,
|
|
mmakefile::out, module_file_name_cache::in, module_file_name_cache::out,
|
|
io::di, io::uo) is det.
|
|
|
|
generate_d_file(Globals, BurdenedAugCompUnit, IntermodDeps,
|
|
AllDeps, MaybeInclTransOptRule, !:MmakeFile, !Cache, !IO) :-
|
|
BurdenedAugCompUnit = burdened_aug_comp_unit(Baggage, AugCompUnit),
|
|
SourceFileName = Baggage ^ mb_source_file_name,
|
|
SourceFileModuleName = Baggage ^ mb_source_file_module_name,
|
|
MaybeTopModule = Baggage ^ mb_maybe_top_module,
|
|
ParseTreeModuleSrc = AugCompUnit ^ acu_module_src,
|
|
ModuleName = ParseTreeModuleSrc ^ ptms_module_name,
|
|
ModuleNameString = sym_name_to_string(ModuleName),
|
|
Ancestors = get_ancestors_set(ModuleName),
|
|
(
|
|
IntermodDeps = no_intermod_deps,
|
|
map.keys_as_set(ParseTreeModuleSrc ^ ptms_import_use_map, LongDeps0),
|
|
IndirectIntSpecs = AugCompUnit ^ acu_indirect_int2_specs,
|
|
map.keys_as_set(IndirectIntSpecs, IndirectDeps)
|
|
;
|
|
IntermodDeps = intermod_deps(IntDeps, ImpDeps, IndirectDeps, _FIMDeps,
|
|
_TransOptDeps),
|
|
set.union(IntDeps, ImpDeps, LongDeps0)
|
|
),
|
|
PublicChildrenMap = ParseTreeModuleSrc ^ ptms_int_includes,
|
|
one_or_more_map.keys_as_set(PublicChildrenMap, PublicChildren),
|
|
get_fact_tables(ParseTreeModuleSrc, FactTableFileNamesSet),
|
|
get_foreign_include_file_infos(ParseTreeModuleSrc, ForeignIncludeFiles),
|
|
|
|
library.version(Version, FullArch),
|
|
|
|
MmakeStartComment = mmake_start_comment("module dependencies",
|
|
ModuleNameString, SourceFileName, Version, FullArch),
|
|
|
|
module_name_to_make_var_name(ModuleName, ModuleMakeVarName),
|
|
|
|
set.delete(ModuleName, LongDeps0, LongDeps),
|
|
ShortDeps0 = IndirectDeps,
|
|
set.difference(ShortDeps0, LongDeps, ShortDeps1),
|
|
set.delete(ModuleName, ShortDeps1, ShortDeps),
|
|
|
|
make_module_file_name(Globals, $pred,
|
|
ext_other(other_ext(".trans_opt_date")),
|
|
ModuleName, TransOptDateFileName, !Cache, !IO),
|
|
construct_trans_opt_deps_rule(Globals, MaybeInclTransOptRule, IntermodDeps,
|
|
TransOptDateFileName, MmakeRulesTransOpt, !Cache, !IO),
|
|
|
|
construct_fact_tables_entries(ModuleMakeVarName,
|
|
SourceFileName, ObjFileName, FactTableFileNamesSet,
|
|
MmakeVarsFactTables, FactTableSourceGroups, MmakeRulesFactTables),
|
|
|
|
( if string.remove_suffix(SourceFileName, ".m", SourceFileBase) then
|
|
ErrFileName = SourceFileBase ++ ".err"
|
|
else
|
|
unexpected($pred, "source file name doesn't end in `.m'")
|
|
),
|
|
|
|
make_module_file_name(Globals, $pred,
|
|
ext_other(other_ext(".optdate")), ModuleName, OptDateFileName,
|
|
!Cache, !IO),
|
|
make_module_file_name(Globals, $pred,
|
|
ext_other(other_ext(".c_date")), ModuleName, CDateFileName,
|
|
!Cache, !IO),
|
|
make_module_file_name(Globals, $pred,
|
|
ext_other(other_ext(".$O")), ModuleName, ObjFileName, !Cache, !IO),
|
|
make_module_file_name(Globals, $pred,
|
|
ext_other(other_ext(".java_date")), ModuleName, JavaDateFileName,
|
|
!Cache, !IO),
|
|
% XXX Why is the extension hardcoded to .pic_o here? That looks wrong.
|
|
% It should probably be .$(EXT_FOR_PIC_OBJECT) - juliensf.
|
|
make_module_file_name(Globals, $pred,
|
|
ext_other(other_ext(".pic_o")), ModuleName, PicObjFileName,
|
|
!Cache, !IO),
|
|
make_module_file_name(Globals, $pred,
|
|
ext_other(other_ext(".int0")), ModuleName, Int0FileName, !Cache, !IO),
|
|
|
|
construct_date_file_deps_rule(Globals, ModuleName, SourceFileName,
|
|
Ancestors, LongDeps, ShortDeps, PublicChildren, Int0FileName,
|
|
OptDateFileName, TransOptDateFileName, ForeignIncludeFiles,
|
|
CDateFileName, JavaDateFileName, ErrFileName,
|
|
FactTableSourceGroups, MmakeRuleDateFileDeps, !Cache, !IO),
|
|
|
|
construct_build_nested_children_first_rule(Globals,
|
|
ModuleName, MaybeTopModule, MmakeRulesNestedDeps, !Cache, !IO),
|
|
|
|
construct_intermod_rules(Globals, ModuleName, LongDeps, AllDeps,
|
|
ErrFileName, TransOptDateFileName, CDateFileName, JavaDateFileName,
|
|
ObjFileName, MmakeRulesIntermod, !Cache, !IO),
|
|
|
|
make_module_file_name(Globals, $pred,
|
|
ext_other(other_ext(".c")), ModuleName, CFileName, !Cache, !IO),
|
|
construct_c_header_rules(Globals, ModuleName, AllDeps,
|
|
CFileName, ObjFileName, PicObjFileName, MmakeRulesCHeaders,
|
|
!Cache, !IO),
|
|
|
|
construct_module_dep_fragment(Globals, ModuleName, CFileName,
|
|
MmakeFragmentModuleDep, !Cache, !IO),
|
|
|
|
make_module_file_name(Globals, $pred,
|
|
ext_other(other_ext(".date")), ModuleName, DateFileName, !Cache, !IO),
|
|
make_module_file_name(Globals, $pred,
|
|
ext_other(other_ext(".date0")), ModuleName, Date0FileName,
|
|
!Cache, !IO),
|
|
construct_self_and_parent_date_date0_rules(Globals, SourceFileName,
|
|
Date0FileName, DateFileName, Ancestors, LongDeps, ShortDeps,
|
|
MmakeRulesParentDates, !Cache, !IO),
|
|
|
|
construct_foreign_import_rules(Globals, AugCompUnit, IntermodDeps,
|
|
SourceFileModuleName, ObjFileName, PicObjFileName,
|
|
MmakeRulesForeignImports, !Cache, !IO),
|
|
|
|
make_module_file_name(Globals, $pred,
|
|
ext_other(other_ext(".date3")), ModuleName, Date3FileName,
|
|
!Cache, !IO),
|
|
construct_install_shadow_rules(Globals, ModuleName,
|
|
Int0FileName, Date0FileName, DateFileName, Date3FileName,
|
|
OptDateFileName, TransOptDateFileName,
|
|
MmakeRulesInstallShadows, !Cache, !IO),
|
|
|
|
construct_subdir_short_rules(Globals, ModuleName,
|
|
MmakeRulesSubDirShorthand, !Cache, !IO),
|
|
|
|
have_source_file_map(HaveMap, !IO),
|
|
construct_any_needed_pattern_rules(HaveMap,
|
|
ModuleName, SourceFileModuleName, SourceFileName,
|
|
Date0FileName, DateFileName, Date3FileName,
|
|
OptDateFileName, TransOptDateFileName, CDateFileName, JavaDateFileName,
|
|
MmakeRulesPatterns),
|
|
|
|
start_mmakefile(!:MmakeFile),
|
|
add_mmake_entry(MmakeStartComment, !MmakeFile),
|
|
add_mmake_entries(MmakeRulesTransOpt, !MmakeFile),
|
|
add_mmake_entries(MmakeVarsFactTables, !MmakeFile),
|
|
add_mmake_entry(MmakeRuleDateFileDeps, !MmakeFile),
|
|
add_mmake_entries(MmakeRulesFactTables, !MmakeFile),
|
|
add_mmake_entries(MmakeRulesNestedDeps, !MmakeFile),
|
|
add_mmake_entries(MmakeRulesIntermod, !MmakeFile),
|
|
add_mmake_entries(MmakeRulesCHeaders, !MmakeFile),
|
|
add_mmake_fragment(MmakeFragmentModuleDep, !MmakeFile),
|
|
add_mmake_entries(MmakeRulesParentDates, !MmakeFile),
|
|
add_mmake_entries(MmakeRulesForeignImports, !MmakeFile),
|
|
add_mmake_entries(MmakeRulesInstallShadows, !MmakeFile),
|
|
add_mmake_entries(MmakeRulesSubDirShorthand, !MmakeFile),
|
|
add_mmake_entries(MmakeRulesPatterns, !MmakeFile).
|
|
|
|
%---------------------%
|
|
|
|
:- pred construct_trans_opt_deps_rule(globals::in,
|
|
maybe_include_trans_opt_rule::in, maybe_intermod_deps::in,
|
|
string::in, list(mmake_entry)::out,
|
|
module_file_name_cache::in, module_file_name_cache::out,
|
|
io::di, io::uo) is det.
|
|
|
|
construct_trans_opt_deps_rule(Globals, MaybeInclTransOptRule, IntermodDeps,
|
|
TransOptDateFileName, MmakeRulesTransOpt, !Cache, !IO) :-
|
|
(
|
|
MaybeInclTransOptRule = include_trans_opt_rule(TransOptRuleInfo),
|
|
% There are two cases when we will write a trans_opt_deps rule.
|
|
(
|
|
TransOptRuleInfo = trans_opt_deps_from_order(TransOptOrder),
|
|
% We reach this case when explicitly generating dependencies.
|
|
%
|
|
% TransOptDeps0 are the dependencies taken from the trans-opt
|
|
% dependency graph (which may have edges deleted by the user).
|
|
%
|
|
% TransOptOrder contains the list of modules that occur later
|
|
% than the current module in a topological ordering of the
|
|
% trans-opt dependency graph.
|
|
%
|
|
% We take the intersection of TransOptOrder and TransOptDeps0
|
|
% to eliminate any circularities that might arise in the
|
|
% trans_opt_deps rules if we were to use TransOptDeps0 as-is.
|
|
(
|
|
IntermodDeps = intermod_deps(_, _, _, _, TransOptDeps0),
|
|
set.intersect(TransOptOrder, TransOptDeps0, TransOptDeps)
|
|
;
|
|
IntermodDeps = no_intermod_deps,
|
|
unexpected($pred, "no_intermod_deps")
|
|
)
|
|
;
|
|
TransOptRuleInfo = trans_opt_deps_from_d_file(DFileTransOptDeps),
|
|
% We reach this case when the `.d' file is being automatically
|
|
% rewritten after producing target code, etc. We will not have
|
|
% computed the trans-opt dependency graph, and we will not have
|
|
% read the trans-opt-deps-spec file.
|
|
%
|
|
% What we can do is write the new `.d' file with the same trans-opt
|
|
% dependencies as the old `.d' file. As source files are modified,
|
|
% the trans-opt dependencies listed in the `.d' file may become out
|
|
% of date, so the user will need to explicitly regenerate
|
|
% dependencies.
|
|
%
|
|
% Note: we used to take the intersection with LongDeps (in the
|
|
% caller), but this case was not separated from the previous case
|
|
% and it greatly reduces the set of dependencies, so I'm not sure
|
|
% if it was intentional. --pw
|
|
TransOptDeps = DFileTransOptDeps
|
|
),
|
|
% Note that maybe_read_dependency_file searches for
|
|
% this exact pattern.
|
|
make_module_file_names_with_suffix(Globals,
|
|
ext_other(other_ext(".trans_opt")),
|
|
set.to_sorted_list(TransOptDeps), TransOptDepsFileNames,
|
|
!Cache, !IO),
|
|
MmakeRuleTransOpt = mmake_simple_rule("trans_opt_deps",
|
|
mmake_rule_is_not_phony,
|
|
TransOptDateFileName,
|
|
TransOptDepsFileNames,
|
|
[]),
|
|
MmakeRulesTransOpt = [MmakeRuleTransOpt]
|
|
;
|
|
MaybeInclTransOptRule = do_not_include_trans_opt_rule,
|
|
MmakeRulesTransOpt = []
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
:- pred construct_fact_tables_entries(string::in, string::in, string::in,
|
|
set(string)::in,
|
|
list(mmake_entry)::out, list(mmake_file_name_group)::out,
|
|
list(mmake_entry)::out) is det.
|
|
|
|
construct_fact_tables_entries(ModuleMakeVarName, SourceFileName, ObjFileName,
|
|
FactTableFileNamesSet, MmakeVarsFactTables, FactTableSourceGroups,
|
|
MmakeRulesFactTables) :-
|
|
FactTableFileNames = set.to_sorted_list(FactTableFileNamesSet),
|
|
(
|
|
FactTableFileNames = [_ | _],
|
|
MmakeVarFactTables = mmake_var_defn_list(
|
|
ModuleMakeVarName ++ ".fact_tables",
|
|
FactTableFileNames),
|
|
MmakeVarFactTablesOs = mmake_var_defn(
|
|
ModuleMakeVarName ++ ".fact_tables.os",
|
|
"$(" ++ ModuleMakeVarName ++ ".fact_tables:%=$(os_subdir)%.$O)"),
|
|
MmakeVarFactTablesAllOs = mmake_var_defn(
|
|
ModuleMakeVarName ++ ".fact_tables.all_os",
|
|
"$(" ++ ModuleMakeVarName ++ ".fact_tables:%=$(os_subdir)%.$O)"),
|
|
MmakeVarFactTablesCs = mmake_var_defn(
|
|
ModuleMakeVarName ++ ".fact_tables.cs",
|
|
"$(" ++ ModuleMakeVarName ++ ".fact_tables:%=$(cs_subdir)%.c)"),
|
|
MmakeVarFactTablesAllCs = mmake_var_defn(
|
|
ModuleMakeVarName ++ ".fact_tables.all_cs",
|
|
"$(" ++ ModuleMakeVarName ++ ".fact_tables:%=$(cs_subdir)%.c)"),
|
|
MmakeVarsFactTables =
|
|
[MmakeVarFactTables,
|
|
MmakeVarFactTablesOs, MmakeVarFactTablesAllOs,
|
|
MmakeVarFactTablesCs, MmakeVarFactTablesAllCs],
|
|
|
|
FactTableSourceGroup = mmake_file_name_group("fact tables",
|
|
one_or_more("$(" ++ ModuleMakeVarName ++ ".fact_tables)", [])),
|
|
FactTableSourceGroups = [FactTableSourceGroup],
|
|
|
|
% XXX These rules seem wrong to me. -zs
|
|
MmakeRuleFactOs = mmake_simple_rule("fact_table_os",
|
|
mmake_rule_is_not_phony,
|
|
"$(" ++ ModuleMakeVarName ++ ".fact_tables.os)",
|
|
["$(" ++ ModuleMakeVarName ++ ".fact_tables)", SourceFileName],
|
|
[]),
|
|
MmakeRuleFactCs = mmake_simple_rule("fact_table_cs",
|
|
mmake_rule_is_not_phony,
|
|
"$(" ++ ModuleMakeVarName ++ ".fact_tables.cs)",
|
|
[ObjFileName],
|
|
[]),
|
|
MmakeRulesFactTables = [MmakeRuleFactOs, MmakeRuleFactCs]
|
|
;
|
|
FactTableFileNames = [],
|
|
MmakeVarsFactTables = [],
|
|
FactTableSourceGroups = [],
|
|
MmakeRulesFactTables = []
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
:- pred construct_date_file_deps_rule(globals::in,
|
|
module_name::in, string::in,
|
|
set(module_name)::in, set(module_name)::in, set(module_name)::in,
|
|
set(module_name)::in, string::in, string::in, string::in,
|
|
set(foreign_include_file_info)::in, string::in, string::in, string::in,
|
|
list(mmake_file_name_group)::in,
|
|
mmake_entry::out,
|
|
module_file_name_cache::in, module_file_name_cache::out,
|
|
io::di, io::uo) is det.
|
|
|
|
construct_date_file_deps_rule(Globals, ModuleName, SourceFileName,
|
|
Ancestors, LongDeps, ShortDeps, PublicChildren, Int0FileName,
|
|
OptDateFileName, TransOptDateFileName, ForeignIncludeFilesSet,
|
|
CDateFileName, JavaDateFileName, ErrFileName,
|
|
FactTableSourceGroups, MmakeRuleDateFileDeps, !Cache, !IO) :-
|
|
% For the reason for why there is no mention of a date file for C# here,
|
|
% see the comment at the top of generate_d_file.
|
|
TargetGroup = mmake_file_name_group("dates_and_err",
|
|
one_or_more(OptDateFileName,
|
|
[TransOptDateFileName, ErrFileName,
|
|
CDateFileName, JavaDateFileName])),
|
|
TargetGroups = one_or_more(TargetGroup, []),
|
|
|
|
SourceFileNameGroup = [make_singleton_file_name_group(SourceFileName)],
|
|
% If the module contains nested submodules, then the `.int0' file
|
|
% must first be built.
|
|
( if set.is_empty(PublicChildren) then
|
|
Int0FileNameGroups = []
|
|
else
|
|
Int0FileNameGroups = [make_singleton_file_name_group(Int0FileName)]
|
|
),
|
|
make_module_file_name_group_with_suffix(Globals,
|
|
"ancestors", ext_other(other_ext(".int0")),
|
|
Ancestors, AncestorSourceGroups, !Cache, !IO),
|
|
make_module_file_name_group_with_suffix(Globals,
|
|
"long deps", ext_other(other_ext(".int")),
|
|
LongDeps, LongDepsSourceGroups, !Cache, !IO),
|
|
make_module_file_name_group_with_suffix(Globals,
|
|
"short deps", ext_other(other_ext(".int2")),
|
|
ShortDeps, ShortDepsSourceGroups, !Cache, !IO),
|
|
make_module_file_name_group_with_suffix(Globals,
|
|
"type_repn self dep", ext_other(other_ext(".int")),
|
|
set.make_singleton_set(ModuleName), TypeRepnSelfDepGroups,
|
|
!Cache, !IO),
|
|
make_module_file_name_group_with_suffix(Globals,
|
|
"type_repn ancestor dep", ext_other(other_ext(".int")),
|
|
get_ancestors_set(ModuleName), TypeRepnAncestorsDepGroups,
|
|
!Cache, !IO),
|
|
ForeignIncludeFiles = set.to_sorted_list(ForeignIncludeFilesSet),
|
|
% This is conservative: a target file for foreign language A
|
|
% does not truly depend on a file included for foreign language B.
|
|
ForeignImportFileNames =
|
|
list.map(foreign_include_file_path_name(SourceFileName),
|
|
ForeignIncludeFiles),
|
|
ForeignImportFileNameGroup =
|
|
make_file_name_group("foreign imports", ForeignImportFileNames),
|
|
SourceGroups = SourceFileNameGroup ++
|
|
Int0FileNameGroups ++ AncestorSourceGroups ++
|
|
LongDepsSourceGroups ++ ShortDepsSourceGroups ++
|
|
TypeRepnSelfDepGroups ++ TypeRepnAncestorsDepGroups ++
|
|
ForeignImportFileNameGroup ++ FactTableSourceGroups,
|
|
MmakeRuleDateFileDeps = mmake_general_rule("date_file_deps",
|
|
mmake_rule_is_not_phony,
|
|
TargetGroups,
|
|
SourceGroups,
|
|
[]).
|
|
|
|
%---------------------%
|
|
|
|
% If a module contains nested submodules, then we need to build
|
|
% the nested children before attempting to build the parent module.
|
|
% Build rules that enforce this.
|
|
%
|
|
:- pred construct_build_nested_children_first_rule(globals::in,
|
|
module_name::in, maybe_top_module::in, list(mmake_entry)::out,
|
|
module_file_name_cache::in, module_file_name_cache::out,
|
|
io::di, io::uo) is det.
|
|
|
|
construct_build_nested_children_first_rule(Globals, ModuleName, MaybeTopModule,
|
|
MmakeRulesNestedDeps, !Cache, !IO) :-
|
|
NestedModuleNames = get_nested_children_list_of_top_module(MaybeTopModule),
|
|
(
|
|
NestedModuleNames = [],
|
|
MmakeRulesNestedDeps = []
|
|
;
|
|
NestedModuleNames = [_ | _],
|
|
NestedOtherExts = [
|
|
other_ext(".optdate"),
|
|
other_ext(".trans_opt_date"),
|
|
other_ext(".c_date"),
|
|
other_ext(".dir/*.$O"),
|
|
other_ext(".java_date")],
|
|
list.map_foldl2(
|
|
gather_nested_deps(Globals, ModuleName, NestedModuleNames),
|
|
NestedOtherExts, MmakeRulesNestedDeps, !Cache, !IO)
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
:- pred construct_intermod_rules(globals::in, module_name::in,
|
|
set(module_name)::in, set(module_name)::in,
|
|
string::in, string::in, string::in, string::in, string::in,
|
|
list(mmake_entry)::out,
|
|
module_file_name_cache::in, module_file_name_cache::out,
|
|
io::di, io::uo) is det.
|
|
|
|
construct_intermod_rules(Globals, ModuleName, LongDeps, AllDeps,
|
|
ErrFileName, TransOptDateFileName, CDateFileName, JavaDateFileName,
|
|
ObjFileName, MmakeRulesIntermod, !Cache, !IO) :-
|
|
% XXX Note that currently, due to a design problem, handle_option.m
|
|
% *always* sets use_opt_files to no.
|
|
globals.lookup_bool_option(Globals, use_opt_files, UseOptFiles),
|
|
globals.lookup_bool_option(Globals, intermodule_optimization,
|
|
Intermod),
|
|
globals.lookup_accumulating_option(Globals, intermod_directories,
|
|
IntermodDirs),
|
|
|
|
% If intermodule_optimization is enabled, then all the .mh files
|
|
% must exist, because it is possible that the .c file imports them
|
|
% directly or indirectly.
|
|
(
|
|
Intermod = yes,
|
|
make_module_file_names_with_suffix(Globals,
|
|
ext_other(other_ext(".mh")),
|
|
set.to_sorted_list(AllDeps), AllDepsFileNames, !Cache, !IO),
|
|
MmakeRuleMhDeps = mmake_simple_rule("machine_dependent_header_deps",
|
|
mmake_rule_is_not_phony,
|
|
ObjFileName,
|
|
AllDepsFileNames,
|
|
[]),
|
|
MmakeRulesMhDeps = [MmakeRuleMhDeps]
|
|
;
|
|
Intermod = no,
|
|
MmakeRulesMhDeps = []
|
|
),
|
|
( if
|
|
( Intermod = yes
|
|
; UseOptFiles = yes
|
|
)
|
|
then
|
|
Targets = one_or_more(TransOptDateFileName,
|
|
[ErrFileName, CDateFileName, JavaDateFileName]),
|
|
|
|
% The target (e.g. C) file only depends on the .opt files from the
|
|
% current directory, so that inter-module optimization works when
|
|
% the .opt files for the library are unavailable. This is only
|
|
% necessary because make doesn't allow conditional dependencies.
|
|
% The dependency on the current module's .opt file is to make sure
|
|
% the module gets type-checked without having the definitions
|
|
% of abstract types from other modules.
|
|
%
|
|
% XXX The code here doesn't correctly handle dependencies
|
|
% on `.int' and `.int2' files needed by the `.opt' files.
|
|
globals.lookup_bool_option(Globals, transitive_optimization, TransOpt),
|
|
globals.lookup_bool_option(Globals, use_trans_opt_files,
|
|
UseTransOpt),
|
|
|
|
bool.not(UseTransOpt, BuildOptFiles),
|
|
( if
|
|
( TransOpt = yes
|
|
; UseTransOpt = yes
|
|
)
|
|
then
|
|
get_both_opt_deps(Globals, BuildOptFiles, IntermodDirs,
|
|
[ModuleName | set.to_sorted_list(LongDeps)],
|
|
OptDeps, TransOptDeps1, !Cache, !IO),
|
|
MaybeTransOptDeps1 = yes(TransOptDeps1)
|
|
else
|
|
get_opt_deps(Globals, BuildOptFiles, IntermodDirs,
|
|
other_ext(".opt"),
|
|
[ModuleName | set.to_sorted_list(LongDeps)],
|
|
OptDeps, !IO),
|
|
MaybeTransOptDeps1 = no
|
|
),
|
|
|
|
OptInt0Deps = set.union_list(list.map(get_ancestors_set, OptDeps)),
|
|
make_module_file_names_with_suffix(Globals,
|
|
ext_other(other_ext(".opt")),
|
|
OptDeps, OptDepsFileNames, !Cache, !IO),
|
|
make_module_file_names_with_suffix(Globals,
|
|
ext_other(other_ext(".int0")),
|
|
set.to_sorted_list(OptInt0Deps), OptInt0DepsFileNames, !Cache, !IO),
|
|
MmakeRuleDateOptInt0Deps = mmake_flat_rule("dates_on_opts_and_int0s",
|
|
mmake_rule_is_not_phony,
|
|
Targets,
|
|
OptDepsFileNames ++ OptInt0DepsFileNames,
|
|
[]),
|
|
|
|
(
|
|
MaybeTransOptDeps1 = yes(TransOptDeps2),
|
|
ErrDateTargets = one_or_more(ErrFileName,
|
|
[CDateFileName, JavaDateFileName]),
|
|
make_module_file_names_with_suffix(Globals,
|
|
ext_other(other_ext(".trans_opt")),
|
|
TransOptDeps2, TransOptDepsOptFileNames, !Cache, !IO),
|
|
MmakeRuleTransOptOpts = mmake_flat_rule("dates_on_trans_opts",
|
|
mmake_rule_is_not_phony,
|
|
ErrDateTargets,
|
|
TransOptDepsOptFileNames,
|
|
[]),
|
|
MmakeRulesIntermod = MmakeRulesMhDeps ++
|
|
[MmakeRuleDateOptInt0Deps, MmakeRuleTransOptOpts]
|
|
;
|
|
MaybeTransOptDeps1 = no,
|
|
MmakeRulesIntermod = MmakeRulesMhDeps ++ [MmakeRuleDateOptInt0Deps]
|
|
)
|
|
else
|
|
MmakeRulesIntermod = MmakeRulesMhDeps
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
:- pred construct_c_header_rules(globals::in, module_name::in,
|
|
set(module_name)::in, string::in, string::in, string::in,
|
|
list(mmake_entry)::out,
|
|
module_file_name_cache::in, module_file_name_cache::out,
|
|
io::di, io::uo) is det.
|
|
|
|
construct_c_header_rules(Globals, ModuleName, AllDeps,
|
|
CFileName, ObjFileName, PicObjFileName, MmakeRulesCHeaders,
|
|
!Cache, !IO) :-
|
|
globals.lookup_bool_option(Globals, highlevel_code, HighLevelCode),
|
|
globals.get_target(Globals, CompilationTarget),
|
|
( if
|
|
HighLevelCode = yes,
|
|
CompilationTarget = target_c
|
|
then
|
|
% For --high-level-code with --target c, we need to make sure that
|
|
% we generate the header files for imported modules before compiling
|
|
% the C files, since the generated C files #include those header files.
|
|
Targets = one_or_more(PicObjFileName, [ObjFileName]),
|
|
make_module_file_names_with_suffix(Globals,
|
|
ext_other(other_ext(".mih")),
|
|
set.to_sorted_list(AllDeps), AllDepsFileNames, !Cache, !IO),
|
|
MmakeRuleObjOnMihs = mmake_flat_rule("objs_on_mihs",
|
|
mmake_rule_is_not_phony,
|
|
Targets,
|
|
AllDepsFileNames,
|
|
[]),
|
|
MmakeRulesObjOnMihs = [MmakeRuleObjOnMihs]
|
|
else
|
|
MmakeRulesObjOnMihs = []
|
|
),
|
|
|
|
% We need to tell make how to make the header files. The header files
|
|
% are actually built by the same command that creates the .c or .s file,
|
|
% so we just make them depend on the .c or .s files. This is needed
|
|
% for the --high-level-code rule above, and for the rules introduced for
|
|
% `:- pragma foreign_import_module' declarations. In some grades the header
|
|
% file won't actually be built (e.g. LLDS grades for modules not containing
|
|
% `:- pragma export' declarations), but this rule won't do any harm.
|
|
make_module_file_name(Globals, $pred,
|
|
ext_other(other_ext(".mh")), ModuleName, MhHeaderFileName,
|
|
!Cache, !IO),
|
|
make_module_file_name(Globals, $pred,
|
|
ext_other(other_ext(".mih")), ModuleName, MihHeaderFileName,
|
|
!Cache, !IO),
|
|
MmakeRuleMhMihOnC = mmake_flat_rule("mh_and_mih_on_c",
|
|
mmake_rule_is_not_phony,
|
|
one_or_more(MhHeaderFileName, [MihHeaderFileName]),
|
|
[CFileName],
|
|
[]),
|
|
MmakeRulesCHeaders = MmakeRulesObjOnMihs ++ [MmakeRuleMhMihOnC].
|
|
|
|
%---------------------%
|
|
|
|
% The `.module_dep' file is made as a side effect of
|
|
% creating the `.c' or `.java'.
|
|
% XXX What about C#?
|
|
% (See the main comment on generate_d_file above.
|
|
%
|
|
:- pred construct_module_dep_fragment(globals::in, module_name::in,
|
|
string::in, mmake_fragment::out,
|
|
module_file_name_cache::in, module_file_name_cache::out,
|
|
io::di, io::uo) is det.
|
|
|
|
construct_module_dep_fragment(Globals, ModuleName, CFileName,
|
|
MmakeFragmentModuleDep, !Cache, !IO) :-
|
|
make_module_file_name(Globals, $pred,
|
|
ext_other(other_ext(".java")), ModuleName, JavaFileName, !Cache, !IO),
|
|
make_module_file_name(Globals, $pred,
|
|
ext_other(make_module_dep_file_extension),
|
|
ModuleName, ModuleDepFileName, !Cache, !IO),
|
|
MmakeFragmentModuleDep = mmf_conditional_entry(
|
|
mmake_cond_grade_has_component("java"),
|
|
mmake_simple_rule("module_dep_on_java",
|
|
mmake_rule_is_not_phony,
|
|
ModuleDepFileName,
|
|
[JavaFileName],
|
|
[]),
|
|
mmake_simple_rule("module_dep_on_c",
|
|
mmake_rule_is_not_phony,
|
|
ModuleDepFileName,
|
|
[CFileName],
|
|
[])
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
% The .date and .date0 files depend on the .int0 files for the parent
|
|
% modules, and the .int3 files for the directly and indirectly imported
|
|
% modules.
|
|
%
|
|
% For nested submodules, the `.date' files for the parent modules
|
|
% also depend on the same things as the `.date' files for this module,
|
|
% since all the `.date' files will get produced by a single mmc command.
|
|
% Similarly for `.date0' files, except these don't depend on the `.int0'
|
|
% files, because when doing the `--make-private-interface' for nested
|
|
% modules, mmc will process the modules in outermost to innermost order
|
|
% so as to produce each `.int0' file before it is needed.
|
|
%
|
|
:- pred construct_self_and_parent_date_date0_rules(globals::in,
|
|
string::in, string::in, string::in,
|
|
set(module_name)::in, set(module_name)::in, set(module_name)::in,
|
|
list(mmake_entry)::out,
|
|
module_file_name_cache::in, module_file_name_cache::out,
|
|
io::di, io::uo) is det.
|
|
|
|
construct_self_and_parent_date_date0_rules(Globals, SourceFileName,
|
|
Date0FileName, DateFileName, Ancestors, LongDeps, ShortDeps,
|
|
MmakeRulesParentDates, !Cache, !IO) :-
|
|
make_module_file_names_with_suffix(Globals,
|
|
ext_other(other_ext(".date")),
|
|
set.to_sorted_list(Ancestors), AncestorDateFileNames, !Cache, !IO),
|
|
make_module_file_names_with_suffix(Globals,
|
|
ext_other(other_ext(".int0")),
|
|
set.to_sorted_list(Ancestors), AncestorInt0FileNames, !Cache, !IO),
|
|
make_module_file_names_with_suffix(Globals,
|
|
ext_other(other_ext(".int3")),
|
|
set.to_sorted_list(LongDeps), LongDepInt3FileNames, !Cache, !IO),
|
|
make_module_file_names_with_suffix(Globals,
|
|
ext_other(other_ext(".int3")),
|
|
set.to_sorted_list(ShortDeps), ShortDepInt3FileNames, !Cache, !IO),
|
|
|
|
MmakeRuleParentDates = mmake_general_rule("self_and_parent_date_deps",
|
|
mmake_rule_is_not_phony,
|
|
one_or_more(
|
|
mmake_file_name_group("",
|
|
one_or_more(DateFileName,
|
|
[Date0FileName | AncestorDateFileNames])),
|
|
[]),
|
|
[make_singleton_file_name_group(SourceFileName)] ++
|
|
make_file_name_group("ancestor int0", AncestorInt0FileNames) ++
|
|
make_file_name_group("long dep int3s", LongDepInt3FileNames) ++
|
|
make_file_name_group("short dep int3s", ShortDepInt3FileNames),
|
|
[]),
|
|
make_module_file_names_with_suffix(Globals,
|
|
ext_other(other_ext(".date0")),
|
|
set.to_sorted_list(Ancestors), AncestorDate0FileNames, !Cache, !IO),
|
|
MmakeRuleParentDate0s = mmake_general_rule("self_and_parent_date0_deps",
|
|
mmake_rule_is_not_phony,
|
|
one_or_more(
|
|
mmake_file_name_group("date0s",
|
|
one_or_more(Date0FileName, AncestorDate0FileNames)),
|
|
[]),
|
|
[make_singleton_file_name_group(SourceFileName)] ++
|
|
make_file_name_group("long dep int3s", LongDepInt3FileNames) ++
|
|
make_file_name_group("short dep int3s", ShortDepInt3FileNames),
|
|
[]),
|
|
MmakeRulesParentDates = [MmakeRuleParentDates, MmakeRuleParentDate0s].
|
|
|
|
%---------------------%
|
|
|
|
% Handle dependencies introduced by
|
|
% `:- pragma foreign_import_module' declarations.
|
|
%
|
|
:- pred construct_foreign_import_rules(globals::in, aug_compilation_unit::in,
|
|
maybe_intermod_deps::in, module_name::in, string::in, string::in,
|
|
list(mmake_entry)::out,
|
|
module_file_name_cache::in, module_file_name_cache::out,
|
|
io::di, io::uo) is det.
|
|
|
|
construct_foreign_import_rules(Globals, AugCompUnit, IntermodDeps,
|
|
SourceFileModuleName, ObjFileName, PicObjFileName,
|
|
MmakeRulesForeignImports, !Cache, !IO) :-
|
|
AugCompUnit = aug_compilation_unit(ParseTreeModuleSrc,
|
|
AncestorIntSpecs, DirectInt1Specs, IndirectInt2Specs,
|
|
PlainOpts, _TransOpts, IntForOptSpecs, _TypeRepnSpecs,
|
|
_ModuleVersionNumber),
|
|
ModuleName = ParseTreeModuleSrc ^ ptms_module_name,
|
|
(
|
|
IntermodDeps = intermod_deps(_, _, _, ForeignImportedModuleNamesSet, _)
|
|
;
|
|
IntermodDeps = no_intermod_deps,
|
|
some [!FIMSpecs] (
|
|
get_fim_specs(ParseTreeModuleSrc, !:FIMSpecs),
|
|
map.foldl_values(gather_fim_specs_in_ancestor_int_spec,
|
|
AncestorIntSpecs, !FIMSpecs),
|
|
map.foldl_values(gather_fim_specs_in_direct_int1_spec,
|
|
DirectInt1Specs, !FIMSpecs),
|
|
map.foldl_values(gather_fim_specs_in_indirect_int2_spec,
|
|
IndirectInt2Specs, !FIMSpecs),
|
|
map.foldl_values(gather_fim_specs_in_parse_tree_plain_opt,
|
|
PlainOpts, !FIMSpecs),
|
|
% .trans_opt files cannot contain FIMs.
|
|
map.foldl_values(gather_fim_specs_in_int_for_opt_spec,
|
|
IntForOptSpecs, !FIMSpecs),
|
|
% Any FIMs in type_repn_specs are ignored.
|
|
|
|
% We restrict the set of FIMs to those that are valid
|
|
% for the current backend. This preserves old behavior,
|
|
% and makes sense in that the code below generates mmake rules
|
|
% only for the current backend, but it would be nice if we
|
|
% could generate dependency rules for *all* the backends.
|
|
globals.get_backend_foreign_languages(Globals, BackendLangs),
|
|
IsBackendFIM =
|
|
( pred(FIMSpec::in) is semidet :-
|
|
list.member(FIMSpec ^ fimspec_lang, BackendLangs)
|
|
),
|
|
set.filter(IsBackendFIM, !.FIMSpecs, FIMSpecs)
|
|
),
|
|
set.filter_map(
|
|
( pred(ForeignImportMod::in, ImportModuleName::out) is semidet :-
|
|
ImportModuleName = fim_spec_module_name_from_module(
|
|
ForeignImportMod, SourceFileModuleName),
|
|
% XXX We can't include mercury.dll as mmake can't find it,
|
|
% but we know that it exists.
|
|
ImportModuleName \= unqualified("mercury")
|
|
), FIMSpecs, ForeignImportedModuleNamesSet)
|
|
),
|
|
|
|
ForeignImportedModuleNames =
|
|
set.to_sorted_list(ForeignImportedModuleNamesSet),
|
|
(
|
|
ForeignImportedModuleNames = [],
|
|
MmakeRulesForeignImports = []
|
|
;
|
|
ForeignImportedModuleNames = [_ | _],
|
|
globals.get_target(Globals, Target),
|
|
(
|
|
Target = target_c,
|
|
% NOTE: for C the possible targets might be a .o file _or_ a
|
|
% .pic_o file. We need to include dependencies for the latter
|
|
% otherwise invoking mmake with a <module>.pic_o target will break.
|
|
ForeignImportTargets = one_or_more(ObjFileName, [PicObjFileName]),
|
|
ForeignImportOtherExt = other_ext(".mh"),
|
|
gather_foreign_import_deps(Globals, ForeignImportOtherExt,
|
|
ForeignImportTargets, ForeignImportedModuleNames,
|
|
MmakeRuleForeignImports, !Cache, !IO),
|
|
MmakeRulesForeignImports = [MmakeRuleForeignImports]
|
|
;
|
|
Target = target_java,
|
|
make_module_file_name(Globals, $pred,
|
|
ext_other(other_ext(".class")),
|
|
ModuleName, ClassFileName, !Cache, !IO),
|
|
ForeignImportTargets = one_or_more(ClassFileName, []),
|
|
ForeignImportOtherExt = other_ext(".java"),
|
|
gather_foreign_import_deps(Globals, ForeignImportOtherExt,
|
|
ForeignImportTargets, ForeignImportedModuleNames,
|
|
MmakeRuleForeignImports, !Cache, !IO),
|
|
MmakeRulesForeignImports = [MmakeRuleForeignImports]
|
|
;
|
|
Target = target_csharp,
|
|
% XXX We don't implement mmake rules for C#.
|
|
MmakeRulesForeignImports = []
|
|
)
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
% We add some extra dependencies to the generated `.d' files, so that
|
|
% local `.int', `.opt', etc. files shadow the installed versions properly
|
|
% (e.g. for when you are trying to build a new version of an installed
|
|
% library). This saves the user from having to add these explicitly
|
|
% if they have multiple libraries installed in the same installation
|
|
% hierarchy which aren't independent (e.g. one uses another). These extra
|
|
% dependencies are necessary due to the way the combination of search paths
|
|
% and pattern rules works in Make.
|
|
%
|
|
:- pred construct_install_shadow_rules(globals::in, module_name::in,
|
|
string::in, string::in, string::in, string::in, string::in, string::in,
|
|
list(mmake_entry)::out,
|
|
module_file_name_cache::in, module_file_name_cache::out,
|
|
io::di, io::uo) is det.
|
|
|
|
construct_install_shadow_rules(Globals, ModuleName,
|
|
Int0FileName, Date0FileName, DateFileName, Date3FileName,
|
|
OptDateFileName, TransOptDateFileName,
|
|
MmakeRulesInstallShadows, !Cache, !IO) :-
|
|
make_module_file_name(Globals, $pred,
|
|
ext_other(other_ext(".int")), ModuleName, IntFileName, !Cache, !IO),
|
|
make_module_file_name(Globals, $pred,
|
|
ext_other(other_ext(".int2")), ModuleName, Int2FileName, !Cache, !IO),
|
|
make_module_file_name(Globals, $pred,
|
|
ext_other(other_ext(".int3")), ModuleName, Int3FileName, !Cache, !IO),
|
|
make_module_file_name(Globals, $pred,
|
|
ext_other(other_ext(".opt")), ModuleName, OptFileName, !Cache, !IO),
|
|
make_module_file_name(Globals, $pred,
|
|
ext_other(other_ext(".trans_opt")), ModuleName, TransOptFileName,
|
|
!Cache, !IO),
|
|
|
|
MmakeRulesInstallShadows = [
|
|
mmake_simple_rule("int0_on_date0",
|
|
mmake_rule_is_not_phony,
|
|
Int0FileName, [Date0FileName], [silent_noop_action]),
|
|
mmake_simple_rule("int_on_date",
|
|
mmake_rule_is_not_phony,
|
|
IntFileName, [DateFileName], [silent_noop_action]),
|
|
mmake_simple_rule("int2_on_date",
|
|
mmake_rule_is_not_phony,
|
|
Int2FileName, [DateFileName], [silent_noop_action]),
|
|
mmake_simple_rule("int3_on_date3",
|
|
mmake_rule_is_not_phony,
|
|
Int3FileName, [Date3FileName], [silent_noop_action]),
|
|
mmake_simple_rule("opt_on_opt_date",
|
|
mmake_rule_is_not_phony,
|
|
OptFileName, [OptDateFileName], [silent_noop_action]),
|
|
mmake_simple_rule("trans_opt_on_trans_opt_date",
|
|
mmake_rule_is_not_phony,
|
|
TransOptFileName, [TransOptDateFileName], [silent_noop_action])
|
|
].
|
|
|
|
%---------------------%
|
|
|
|
:- pred construct_subdir_short_rules(globals::in, module_name::in,
|
|
list(mmake_entry)::out,
|
|
module_file_name_cache::in, module_file_name_cache::out,
|
|
io::di, io::uo) is det.
|
|
|
|
construct_subdir_short_rules(Globals, ModuleName,
|
|
MmakeRulesSubDirShorthand, !Cache, !IO) :-
|
|
globals.lookup_bool_option(Globals, use_subdirs, UseSubdirs),
|
|
(
|
|
UseSubdirs = yes,
|
|
SubDirShorthandOtherExts =
|
|
[other_ext(".c"), other_ext(".$O"), other_ext(".pic_o"),
|
|
other_ext(".java"), other_ext(".class"), other_ext(".dll")],
|
|
list.map_foldl2(
|
|
construct_subdirs_shorthand_rule(Globals, ModuleName),
|
|
SubDirShorthandOtherExts, MmakeRulesSubDirShorthand, !Cache, !IO)
|
|
;
|
|
UseSubdirs = no,
|
|
MmakeRulesSubDirShorthand = []
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
:- pred construct_any_needed_pattern_rules(bool::in,
|
|
module_name::in, module_name::in, string::in,
|
|
string::in, string::in, string::in,
|
|
string::in, string::in, string::in, string::in,
|
|
list(mmake_entry)::out) is det.
|
|
|
|
construct_any_needed_pattern_rules(HaveMap,
|
|
ModuleName ,SourceFileModuleName, SourceFileName,
|
|
Date0FileName, DateFileName, Date3FileName,
|
|
OptDateFileName, TransOptDateFileName, CDateFileName, JavaDateFileName,
|
|
MmakeRulesPatterns) :-
|
|
% If we can pass the module name rather than the file name, then do so.
|
|
% `--smart-recompilation' doesn't work if the file name is passed
|
|
% and the module name doesn't match the file name.
|
|
(
|
|
HaveMap = yes,
|
|
module_name_to_file_name_stem(SourceFileModuleName, ModuleArg)
|
|
;
|
|
HaveMap = no,
|
|
ModuleArg = SourceFileName
|
|
),
|
|
( if SourceFileName = default_source_file_name(ModuleName) then
|
|
MmakeRulesPatterns = []
|
|
else
|
|
% The pattern rules in Mmake.rules won't work, since the source file
|
|
% name doesn't match the expected source file name for this module
|
|
% name. This can occur due to just the use of different source file
|
|
% names, or it can be due to the use of nested modules. So we need
|
|
% to output hard-coded rules in this case.
|
|
%
|
|
% The rules output below won't work in the case of nested modules
|
|
% with parallel makes, because it will end up invoking the same command
|
|
% twice (since it produces two output files) at the same time.
|
|
%
|
|
% Any changes here will require corresponding changes to
|
|
% scripts/Mmake.rules. See that file for documentation on these rules.
|
|
|
|
MmakeRulesPatterns = [
|
|
mmake_simple_rule("date0_on_src",
|
|
mmake_rule_is_not_phony,
|
|
Date0FileName, [SourceFileName],
|
|
["$(MCPI) $(ALL_GRADEFLAGS) $(ALL_MCPIFLAGS) " ++ ModuleArg]),
|
|
mmake_simple_rule("date_on_src",
|
|
mmake_rule_is_not_phony,
|
|
DateFileName, [SourceFileName],
|
|
["$(MCI) $(ALL_GRADEFLAGS) $(ALL_MCIFLAGS) " ++ ModuleArg]),
|
|
mmake_simple_rule("date3_on_src",
|
|
mmake_rule_is_not_phony,
|
|
Date3FileName, [SourceFileName],
|
|
["$(MCSI) $(ALL_GRADEFLAGS) $(ALL_MCSIFLAGS) " ++ ModuleArg]),
|
|
mmake_simple_rule("opt_date_on_src",
|
|
mmake_rule_is_not_phony,
|
|
OptDateFileName, [SourceFileName],
|
|
["$(MCOI) $(ALL_GRADEFLAGS) $(ALL_MCOIFLAGS) " ++ ModuleArg]),
|
|
mmake_simple_rule("trans_opt_date_on_src",
|
|
mmake_rule_is_not_phony,
|
|
TransOptDateFileName, [SourceFileName],
|
|
["$(MCTOI) $(ALL_GRADEFLAGS) $(ALL_MCTOIFLAGS) " ++
|
|
ModuleArg]),
|
|
mmake_simple_rule("c_date_on_src",
|
|
mmake_rule_is_not_phony,
|
|
CDateFileName, [SourceFileName],
|
|
["$(MCG) $(ALL_GRADEFLAGS) $(ALL_MCGFLAGS) " ++ ModuleArg ++
|
|
" $(ERR_REDIRECT)"]),
|
|
mmake_simple_rule("java_date_on_src",
|
|
mmake_rule_is_not_phony,
|
|
JavaDateFileName, [SourceFileName],
|
|
["$(MCG) $(ALL_GRADEFLAGS) $(ALL_MCGFLAGS) --java-only " ++
|
|
ModuleArg ++ " $(ERR_REDIRECT)"])
|
|
]
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred gather_fim_specs_in_ancestor_int_spec(ancestor_int_spec::in,
|
|
set(fim_spec)::in, set(fim_spec)::out) is det.
|
|
|
|
gather_fim_specs_in_ancestor_int_spec(AncestorIntSpec, !FIMSpecs) :-
|
|
AncestorIntSpec = ancestor_int0(ParseTreeInt0, _ReadWhy0),
|
|
gather_fim_specs_in_parse_tree_int0(ParseTreeInt0, !FIMSpecs).
|
|
|
|
:- pred gather_fim_specs_in_direct_int1_spec(direct_int1_spec::in,
|
|
set(fim_spec)::in, set(fim_spec)::out) is det.
|
|
|
|
gather_fim_specs_in_direct_int1_spec(DirectInt1Spec, !FIMSpecs) :-
|
|
DirectInt1Spec = direct_int1(ParseTreeInt1, _ReadWhy1),
|
|
gather_fim_specs_in_parse_tree_int1(ParseTreeInt1, !FIMSpecs).
|
|
|
|
:- pred gather_fim_specs_in_indirect_int2_spec(indirect_int2_spec::in,
|
|
set(fim_spec)::in, set(fim_spec)::out) is det.
|
|
|
|
gather_fim_specs_in_indirect_int2_spec(IndirectInt2Spec, !FIMSpecs) :-
|
|
IndirectInt2Spec = indirect_int2(ParseTreeInt2, _ReadWhy2),
|
|
gather_fim_specs_in_parse_tree_int2(ParseTreeInt2, !FIMSpecs).
|
|
|
|
:- pred gather_fim_specs_in_int_for_opt_spec(int_for_opt_spec::in,
|
|
set(fim_spec)::in, set(fim_spec)::out) is det.
|
|
|
|
gather_fim_specs_in_int_for_opt_spec(IntForOptSpec, !FIMSpecs) :-
|
|
(
|
|
IntForOptSpec = for_opt_int0(ParseTreeInt0, _ReadWhy0),
|
|
gather_fim_specs_in_parse_tree_int0(ParseTreeInt0, !FIMSpecs)
|
|
;
|
|
IntForOptSpec = for_opt_int1(ParseTreeInt1, _ReadWhy1),
|
|
gather_fim_specs_in_parse_tree_int1(ParseTreeInt1, !FIMSpecs)
|
|
;
|
|
IntForOptSpec = for_opt_int2(ParseTreeInt2, _ReadWhy2),
|
|
gather_fim_specs_in_parse_tree_int2(ParseTreeInt2, !FIMSpecs)
|
|
).
|
|
|
|
:- pred gather_fim_specs_in_parse_tree_int0(parse_tree_int0::in,
|
|
set(fim_spec)::in, set(fim_spec)::out) is det.
|
|
|
|
gather_fim_specs_in_parse_tree_int0(ParseTreeInt0, !FIMSpecs) :-
|
|
IntFIMS = ParseTreeInt0 ^ pti0_int_fims,
|
|
ImpFIMS = ParseTreeInt0 ^ pti0_imp_fims,
|
|
!:FIMSpecs = set.union_list([IntFIMS, ImpFIMS, !.FIMSpecs]).
|
|
|
|
:- pred gather_fim_specs_in_parse_tree_int1(parse_tree_int1::in,
|
|
set(fim_spec)::in, set(fim_spec)::out) is det.
|
|
|
|
gather_fim_specs_in_parse_tree_int1(ParseTreeInt1, !FIMSpecs) :-
|
|
IntFIMS = ParseTreeInt1 ^ pti1_int_fims,
|
|
ImpFIMS = ParseTreeInt1 ^ pti1_imp_fims,
|
|
!:FIMSpecs = set.union_list([IntFIMS, ImpFIMS, !.FIMSpecs]).
|
|
|
|
:- pred gather_fim_specs_in_parse_tree_int2(parse_tree_int2::in,
|
|
set(fim_spec)::in, set(fim_spec)::out) is det.
|
|
|
|
gather_fim_specs_in_parse_tree_int2(ParseTreeInt2, !FIMSpecs) :-
|
|
IntFIMS = ParseTreeInt2 ^ pti2_int_fims,
|
|
ImpFIMS = ParseTreeInt2 ^ pti2_imp_fims,
|
|
!:FIMSpecs = set.union_list([IntFIMS, ImpFIMS, !.FIMSpecs]).
|
|
|
|
:- pred gather_fim_specs_in_parse_tree_plain_opt(parse_tree_plain_opt::in,
|
|
set(fim_spec)::in, set(fim_spec)::out) is det.
|
|
|
|
gather_fim_specs_in_parse_tree_plain_opt(ParseTreePlainOpt, !FIMSpecs) :-
|
|
set.union(ParseTreePlainOpt ^ ptpo_fims, !FIMSpecs).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred gather_nested_deps(globals::in, module_name::in, list(module_name)::in,
|
|
other_ext::in, mmake_entry::out,
|
|
module_file_name_cache::in, module_file_name_cache::out,
|
|
io::di, io::uo) is det.
|
|
|
|
gather_nested_deps(Globals, ModuleName, NestedDeps, OtherExt,
|
|
MmakeRule, !Cache, !IO) :-
|
|
make_module_file_name(Globals, $pred,
|
|
ext_other(OtherExt), ModuleName, ModuleExtName, !Cache, !IO),
|
|
make_module_file_names_with_suffix(Globals,
|
|
ext_other(OtherExt), NestedDeps, NestedDepsFileNames, !Cache, !IO),
|
|
ExtStr = other_extension_to_string(OtherExt),
|
|
MmakeRule = mmake_simple_rule("nested_deps_for_" ++ ExtStr,
|
|
mmake_rule_is_not_phony,
|
|
ModuleExtName,
|
|
NestedDepsFileNames,
|
|
[]).
|
|
|
|
:- pred gather_foreign_import_deps(globals::in, other_ext::in,
|
|
one_or_more(string)::in, list(module_name)::in, mmake_entry::out,
|
|
module_file_name_cache::in, module_file_name_cache::out,
|
|
io::di, io::uo) is det.
|
|
|
|
gather_foreign_import_deps(Globals, ForeignImportOtherExt,
|
|
ForeignImportTargets, ForeignImportedModuleNames, MmakeRule,
|
|
!Cache, !IO) :-
|
|
make_module_file_names_with_suffix(Globals,
|
|
ext_other(ForeignImportOtherExt),
|
|
ForeignImportedModuleNames, ForeignImportedFileNames, !Cache, !IO),
|
|
ForeignImportExtStr = other_extension_to_string(ForeignImportOtherExt),
|
|
RuleName = "foreign_deps_for_" ++
|
|
string.remove_prefix_if_present(".", ForeignImportExtStr),
|
|
MmakeRule = mmake_flat_rule(RuleName,
|
|
mmake_rule_is_not_phony,
|
|
ForeignImportTargets,
|
|
ForeignImportedFileNames,
|
|
[]).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred make_module_file_name(globals::in, string::in, ext::in,
|
|
module_name::in, file_name::out,
|
|
module_file_name_cache::in, module_file_name_cache::out,
|
|
io::di, io::uo) is det.
|
|
|
|
make_module_file_name(Globals, From, Ext, ModuleName, FileName,
|
|
!Cache, !IO) :-
|
|
(
|
|
Ext = ext_src,
|
|
% No point caching these.
|
|
module_name_to_file_name(Globals, From, do_not_create_dirs,
|
|
Ext, ModuleName, FileName, !IO)
|
|
;
|
|
Ext = ext_other(OtherExt),
|
|
ModuleNameExt = module_name_and_ext(ModuleName, OtherExt),
|
|
( if map.search(!.Cache, ModuleNameExt, FileName0) then
|
|
FileName = FileName0
|
|
else
|
|
% The result of module_name_to_file_name is cached to save on
|
|
% temporary string constructions.
|
|
module_name_to_file_name(Globals, From, do_not_create_dirs,
|
|
Ext, ModuleName, FileName, !IO),
|
|
map.det_insert(ModuleNameExt, FileName, !Cache)
|
|
)
|
|
).
|
|
|
|
:- pred make_module_file_names_with_suffix(globals::in, ext::in,
|
|
list(module_name)::in, list(mmake_file_name)::out,
|
|
module_file_name_cache::in, module_file_name_cache::out,
|
|
io::di, io::uo) is det.
|
|
|
|
make_module_file_names_with_suffix(Globals, Ext, Modules, FileNames,
|
|
!Cache, !IO) :-
|
|
list.map_foldl2(make_module_file_name(Globals, $pred, Ext),
|
|
Modules, FileNames, !Cache, !IO).
|
|
|
|
:- pred make_module_file_name_group_with_suffix(globals::in, string::in,
|
|
ext::in, set(module_name)::in, list(mmake_file_name_group)::out,
|
|
module_file_name_cache::in, module_file_name_cache::out,
|
|
io::di, io::uo) is det.
|
|
|
|
make_module_file_name_group_with_suffix(Globals, GroupName, Ext,
|
|
Modules, Groups, !Cache, !IO) :-
|
|
list.map_foldl2(make_module_file_name(Globals, $pred, Ext),
|
|
set.to_sorted_list(Modules), FileNames, !Cache, !IO),
|
|
Groups = make_file_name_group(GroupName, FileNames).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- func foreign_include_file_path_name(file_name, foreign_include_file_info)
|
|
= string.
|
|
|
|
foreign_include_file_path_name(SourceFileName, IncludeFile) = IncludePath :-
|
|
IncludeFile = foreign_include_file_info(_Lang, IncludeFileName),
|
|
make_include_file_path(SourceFileName, IncludeFileName, IncludePath).
|
|
|
|
:- pred get_fact_table_dependencies(globals::in, other_ext::in,
|
|
list(file_name)::in, list(string)::out, io::di, io::uo) is det.
|
|
|
|
get_fact_table_dependencies(_, _, [], [], !IO).
|
|
get_fact_table_dependencies(Globals, OtherExt,
|
|
[ExtraLink | ExtraLinks], [FileName | FileNames], !IO) :-
|
|
fact_table_file_name(Globals, $pred, do_not_create_dirs, OtherExt,
|
|
ExtraLink, FileName, !IO),
|
|
get_fact_table_dependencies(Globals, OtherExt,
|
|
ExtraLinks, FileNames, !IO).
|
|
|
|
% With `--use-subdirs', allow users to type `mmake module.c'
|
|
% rather than `mmake Mercury/cs/module.c'.
|
|
%
|
|
:- pred construct_subdirs_shorthand_rule(globals::in, module_name::in,
|
|
other_ext::in, mmake_entry::out,
|
|
module_file_name_cache::in, module_file_name_cache::out,
|
|
io::di, io::uo) is det.
|
|
|
|
construct_subdirs_shorthand_rule(Globals, ModuleName, OtherExt,
|
|
MmakeRule, !Cache, !IO) :-
|
|
module_name_to_file_name_stem(ModuleName, ModuleStr),
|
|
make_module_file_name(Globals, $pred, ext_other(OtherExt), ModuleName,
|
|
Target, !Cache, !IO),
|
|
ExtStr = other_extension_to_string(OtherExt),
|
|
ShorthandTarget = ModuleStr ++ ExtStr,
|
|
MmakeRule = mmake_simple_rule("subdir_shorthand_for_" ++ ExtStr,
|
|
mmake_rule_is_phony, ShorthandTarget, [Target], []).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
generate_dependencies_write_d_files(Globals, Deps,
|
|
IntDepsGraph, ImpDepsGraph, IndirectDepsGraph, IndirectOptDepsGraph,
|
|
TransOptDepsGraph, TransOptOrder, DepsMap, !IO) :-
|
|
map.init(Cache0),
|
|
generate_dependencies_write_d_files_loop(Globals, Deps,
|
|
IntDepsGraph, ImpDepsGraph, IndirectDepsGraph, IndirectOptDepsGraph,
|
|
TransOptDepsGraph, TransOptOrder, DepsMap, Cache0, _Cache, !IO).
|
|
|
|
:- pred generate_dependencies_write_d_files_loop(globals::in, list(deps)::in,
|
|
deps_graph::in, deps_graph::in, deps_graph::in, deps_graph::in,
|
|
deps_graph::in, list(module_name)::in, deps_map::in,
|
|
module_file_name_cache::in, module_file_name_cache::out,
|
|
io::di, io::uo) is det.
|
|
|
|
generate_dependencies_write_d_files_loop(_, [], _, _, _, _, _, _, _, !Cache, !IO).
|
|
generate_dependencies_write_d_files_loop(Globals, [Dep | Deps],
|
|
IntDepsGraph, ImpDepsGraph, IndirectDepsGraph, IndirectOptDepsGraph,
|
|
TransOptDepsGraph, TransOptOrder, DepsMap, !Cache, !IO) :-
|
|
generate_dependencies_write_d_file(Globals, Dep,
|
|
IntDepsGraph, ImpDepsGraph, IndirectDepsGraph, IndirectOptDepsGraph,
|
|
TransOptDepsGraph, TransOptOrder, DepsMap, !Cache, !IO),
|
|
generate_dependencies_write_d_files_loop(Globals, Deps,
|
|
IntDepsGraph, ImpDepsGraph, IndirectDepsGraph, IndirectOptDepsGraph,
|
|
TransOptDepsGraph, TransOptOrder, DepsMap, !Cache, !IO).
|
|
|
|
:- pred generate_dependencies_write_d_file(globals::in, deps::in,
|
|
deps_graph::in, deps_graph::in, deps_graph::in, deps_graph::in,
|
|
deps_graph::in, list(module_name)::in, deps_map::in,
|
|
module_file_name_cache::in, module_file_name_cache::out,
|
|
io::di, io::uo) is det.
|
|
|
|
generate_dependencies_write_d_file(Globals, Dep,
|
|
IntDepsGraph, ImpDepsGraph, IndirectDepsGraph, IndirectOptDepsGraph,
|
|
TransOptDepsGraph, FullTransOptOrder, _DepsMap, !Cache, !IO) :-
|
|
% XXX The fact that _DepsMap is unused here may be a bug.
|
|
Dep = deps(_, BurdenedModule),
|
|
BurdenedModule = burdened_module(Baggage, ParseTreeModuleSrc),
|
|
|
|
% Look up the interface/implementation/indirect dependencies
|
|
% for this module from the respective dependency graphs,
|
|
% and save them in the module_and_imports structure.
|
|
|
|
ModuleName = ParseTreeModuleSrc ^ ptms_module_name,
|
|
get_dependencies_from_graph(IndirectOptDepsGraph, ModuleName,
|
|
IndirectOptDeps),
|
|
|
|
globals.lookup_bool_option(Globals, intermodule_optimization,
|
|
Intermod),
|
|
(
|
|
Intermod = yes,
|
|
% Be conservative with inter-module optimization -- assume a
|
|
% module depends on the `.int', `.int2' and `.opt' files
|
|
% for all transitively imported modules.
|
|
IntDeps = IndirectOptDeps,
|
|
ImpDeps = IndirectOptDeps,
|
|
IndirectDeps = IndirectOptDeps
|
|
;
|
|
Intermod = no,
|
|
get_dependencies_from_graph(IntDepsGraph, ModuleName, IntDeps),
|
|
get_dependencies_from_graph(ImpDepsGraph, ModuleName, ImpDeps),
|
|
get_dependencies_from_graph(IndirectDepsGraph, ModuleName,
|
|
IndirectDeps)
|
|
),
|
|
|
|
get_dependencies_from_graph(TransOptDepsGraph, ModuleName, TransOptDeps0),
|
|
set.delete(ModuleName, TransOptDeps0, TransOptDeps),
|
|
|
|
IntermodDeps = intermod_deps(IntDeps, ImpDeps, IndirectDeps,
|
|
IndirectOptDeps, TransOptDeps),
|
|
|
|
% Compute the maximum allowable trans-opt dependencies for this module.
|
|
% To avoid the possibility of cycles, each module is only allowed to depend
|
|
% on modules that occur after it in the FullTransOptOrder.
|
|
|
|
NotThisModule =
|
|
( pred(OtherModule::in) is semidet :-
|
|
ModuleName \= OtherModule
|
|
),
|
|
list.drop_while(NotThisModule, FullTransOptOrder, TailTransOptOrder),
|
|
( if TailTransOptOrder = [_ | TransOptOrderList] then
|
|
% The module was found in the list.
|
|
set.list_to_set(TransOptOrderList, TransOptOrder)
|
|
else
|
|
set.init(TransOptOrder)
|
|
),
|
|
TransOptRuleInfo = trans_opt_deps_from_order(TransOptOrder),
|
|
MaybeInclTransOptRule = include_trans_opt_rule(TransOptRuleInfo),
|
|
|
|
% Note that even if a fatal error occured for one of the files
|
|
% that the current Module depends on, a .d file is still produced,
|
|
% even though it probably contains incorrect information.
|
|
ModuleErrors = Baggage ^ mb_errors,
|
|
FatalErrors = ModuleErrors ^ rm_fatal_errors,
|
|
( if set.is_empty(FatalErrors) then
|
|
init_aug_compilation_unit(ParseTreeModuleSrc, AugCompUnit),
|
|
BurdenedAugCompUnit = burdened_aug_comp_unit(Baggage, AugCompUnit),
|
|
write_dependency_file_fn_cache(Globals, BurdenedAugCompUnit,
|
|
IntermodDeps, IndirectOptDeps, MaybeInclTransOptRule, !Cache, !IO)
|
|
else
|
|
true
|
|
).
|
|
|
|
:- pred get_dependencies_from_graph(deps_graph::in, module_name::in,
|
|
set(module_name)::out) is det.
|
|
|
|
get_dependencies_from_graph(DepsGraph, ModuleName, Dependencies) :-
|
|
( if digraph.search_key(DepsGraph, ModuleName, ModuleKey) then
|
|
digraph.lookup_key_set_from(DepsGraph, ModuleKey, DepsKeysSet),
|
|
AddKeyDep =
|
|
( pred(Key::in, Deps0::in, Deps::out) is det :-
|
|
digraph.lookup_vertex(DepsGraph, Key, Dep),
|
|
Deps = [Dep | Deps0]
|
|
),
|
|
sparse_bitset.foldr(AddKeyDep, DepsKeysSet, [], DependenciesList),
|
|
set.list_to_set(DependenciesList, Dependencies)
|
|
else
|
|
set.init(Dependencies)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
generate_dependencies_write_dv_file(Globals, SourceFileName, ModuleName,
|
|
DepsMap, !IO) :-
|
|
globals.lookup_bool_option(Globals, verbose, Verbose),
|
|
module_name_to_file_name(Globals, $pred, do_create_dirs,
|
|
ext_other(other_ext(".dv")), ModuleName, DvFileName, !IO),
|
|
get_progress_output_stream(Globals, ModuleName, ProgressStream, !IO),
|
|
string.format("%% Creating auto-dependency file `%s'...\n",
|
|
[s(DvFileName)], CreatingMsg),
|
|
maybe_write_string(ProgressStream, Verbose, CreatingMsg, !IO),
|
|
io.open_output(DvFileName, DvResult, !IO),
|
|
(
|
|
DvResult = ok(DvStream),
|
|
map.init(Cache0),
|
|
generate_dv_file(Globals, SourceFileName, ModuleName, DepsMap,
|
|
MmakeFile, Cache0, _Cache, !IO),
|
|
write_mmakefile(DvStream, MmakeFile, !IO),
|
|
io.close_output(DvStream, !IO),
|
|
maybe_write_string(ProgressStream, Verbose, "% done.\n", !IO)
|
|
;
|
|
DvResult = error(IOError),
|
|
maybe_write_string(ProgressStream, Verbose, " failed.\n", !IO),
|
|
maybe_flush_output(ProgressStream, Verbose, !IO),
|
|
get_error_output_stream(Globals, ModuleName, ErrorStream, !IO),
|
|
io.error_message(IOError, IOErrorMessage),
|
|
string.format("error opening file `%s' for output: %s",
|
|
[s(DvFileName), s(IOErrorMessage)], DepMessage),
|
|
report_error(ErrorStream, DepMessage, !IO)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred generate_dv_file(globals::in, file_name::in, module_name::in,
|
|
deps_map::in, mmakefile::out,
|
|
module_file_name_cache::in, module_file_name_cache::out,
|
|
io::di, io::uo) is det.
|
|
|
|
generate_dv_file(Globals, SourceFileName, ModuleName, DepsMap,
|
|
MmakeFile, !Cache, !IO) :-
|
|
ModuleNameString = sym_name_to_string(ModuleName),
|
|
library.version(Version, FullArch),
|
|
MmakeStartComment = mmake_start_comment("dependency variables",
|
|
ModuleNameString, SourceFileName, Version, FullArch),
|
|
|
|
map.keys(DepsMap, Modules0),
|
|
select_ok_modules(DepsMap, Modules0, Modules1),
|
|
list.sort(compare_module_names, Modules1, Modules),
|
|
|
|
module_name_to_make_var_name(ModuleName, ModuleMakeVarName),
|
|
list.map(get_source_file(DepsMap), Modules, SourceFiles0),
|
|
list.sort_and_remove_dups(SourceFiles0, SourceFiles),
|
|
|
|
MmakeVarModuleMs = mmake_var_defn_list(ModuleMakeVarName ++ ".ms",
|
|
list.map(add_suffix(".m"), SourceFiles)),
|
|
|
|
MmakeVarModuleErrs = mmake_var_defn_list(ModuleMakeVarName ++ ".errs",
|
|
list.map(add_suffix(".err"), SourceFiles)),
|
|
|
|
MmakeVarModuleDepErrs = mmake_var_defn_list(
|
|
ModuleMakeVarName ++ ".dep_errs",
|
|
list.map(add_suffix(".dep_err"), SourceFiles)),
|
|
|
|
make_module_file_names_with_suffix(Globals, ext_other(other_ext("")),
|
|
Modules, ModulesSourceFileNames, !Cache, !IO),
|
|
MmakeVarModuleMods = mmake_var_defn_list(ModuleMakeVarName ++ ".mods",
|
|
ModulesSourceFileNames),
|
|
|
|
% The modules for which we need to generate .int0 files.
|
|
ModulesWithSubModules = list.filter(
|
|
( pred(Module::in) is semidet :-
|
|
map.lookup(DepsMap, Module, deps(_, BurdenedModule)),
|
|
ParseTreeModuleSrc = BurdenedModule ^ bm_module,
|
|
IncludeMap = ParseTreeModuleSrc ^ ptms_include_map,
|
|
not map.is_empty(IncludeMap)
|
|
), Modules),
|
|
|
|
make_module_file_names_with_suffix(Globals, ext_other(other_ext("")),
|
|
ModulesWithSubModules, ModulesWithSubModulesSourceFileNames,
|
|
!Cache, !IO),
|
|
MmakeVarModuleParentMods = mmake_var_defn_list(
|
|
ModuleMakeVarName ++ ".parent_mods",
|
|
ModulesWithSubModulesSourceFileNames),
|
|
|
|
globals.get_target(Globals, Target),
|
|
(
|
|
( Target = target_c
|
|
; Target = target_csharp
|
|
; Target = target_java
|
|
),
|
|
ForeignModulesAndExts = []
|
|
),
|
|
ForeignModules = assoc_list.keys(ForeignModulesAndExts),
|
|
|
|
make_module_file_names_with_suffix(Globals, ext_other(other_ext("")),
|
|
ForeignModules, ForeignModulesFileNames, !Cache, !IO),
|
|
MmakeVarForeignModules =
|
|
mmake_var_defn_list(ModuleMakeVarName ++ ".foreign",
|
|
ForeignModulesFileNames),
|
|
|
|
MakeFileName =
|
|
( pred(M - E::in, F::out, IO0::di, IO::uo) is det :-
|
|
module_name_to_file_name(Globals, $pred, do_create_dirs, E, M, F0,
|
|
IO0, IO),
|
|
F = "$(os_subdir)" ++ F0
|
|
),
|
|
list.map_foldl(MakeFileName, ForeignModulesAndExts, ForeignFileNames, !IO),
|
|
|
|
% .foreign_cs are the source files which have had foreign code placed
|
|
% in them.
|
|
% XXX This rule looks wrong: why are we looking for (a) stuff with an
|
|
% unknown suffix in (b) the os_subdir, when we (c) refer to it
|
|
% using a make variable whose name ends in "_cs"?
|
|
% Of course, since ForeignModulesAndExts is always zero with our current
|
|
% set of target languages, this does not matter.
|
|
MmakeVarForeignFileNames =
|
|
mmake_var_defn_list(ModuleMakeVarName ++ ".foreign_cs",
|
|
ForeignFileNames),
|
|
|
|
% The dlls that contain the foreign_code.
|
|
MmakeVarForeignDlls = mmake_var_defn(ModuleMakeVarName ++ ".foreign_dlls",
|
|
string.format("$(%s.foreign:%%=$(dlls_subdir)%%.dll)",
|
|
[s(ModuleMakeVarName)])),
|
|
MmakeVarInitCs = mmake_var_defn(ModuleMakeVarName ++ ".init_cs",
|
|
string.format("$(%s.mods:%%=$(cs_subdir)%%.c)",
|
|
[s(ModuleMakeVarName)])),
|
|
MmakeVarAllCs = mmake_var_defn(ModuleMakeVarName ++ ".all_cs",
|
|
string.format("$(%s.mods:%%=$(cs_subdir)%%.c)",
|
|
[s(ModuleMakeVarName)])),
|
|
|
|
get_fact_table_file_names(DepsMap, Modules, FactTableFileNames),
|
|
% XXX EXT
|
|
% We should just be able to append ".c", ".$O" and the pic extension
|
|
% to each string in FactTableFileNames.
|
|
get_fact_table_dependencies(Globals, other_ext(".c"),
|
|
FactTableFileNames, FactTableFileNamesC, !IO),
|
|
get_fact_table_dependencies(Globals, other_ext(".$O"),
|
|
FactTableFileNames, FactTableFileNamesOs, !IO),
|
|
get_fact_table_dependencies(Globals, other_ext(".$(EXT_FOR_PIC_OBJECTS)"),
|
|
FactTableFileNames, FactTableFileNamesPicOs, !IO),
|
|
|
|
MmakeVarCs = mmake_var_defn_list(ModuleMakeVarName ++ ".cs",
|
|
["$(" ++ ModuleMakeVarName ++ ".init_cs)" | FactTableFileNamesC]),
|
|
MmakeVarDlls = mmake_var_defn(ModuleMakeVarName ++ ".dlls",
|
|
string.format("$(%s.mods:%%=$(dlls_subdir)%%.dll)",
|
|
[s(ModuleMakeVarName)])),
|
|
MmakeVarAllOs = mmake_var_defn_list(ModuleMakeVarName ++ ".all_os",
|
|
[string.format("$(%s.mods:%%=$(os_subdir)%%.$O)",
|
|
[s(ModuleMakeVarName)]) |
|
|
FactTableFileNamesOs]),
|
|
MmakeVarAllPicOs = mmake_var_defn_list(ModuleMakeVarName ++ ".all_pic_os",
|
|
[string.format("$(%s.mods:%%=$(os_subdir)%%.$(EXT_FOR_PIC_OBJECTS))",
|
|
[s(ModuleMakeVarName)]) |
|
|
FactTableFileNamesPicOs]),
|
|
MmakeVarOs = mmake_var_defn(ModuleMakeVarName ++ ".os",
|
|
string.format("$(%s.all_os)", [s(ModuleMakeVarName)])),
|
|
MmakeVarPicOs = mmake_var_defn(ModuleMakeVarName ++ ".pic_os",
|
|
string.format("$(%s.all_pic_os)", [s(ModuleMakeVarName)])),
|
|
MmakeVarUseds = mmake_var_defn(ModuleMakeVarName ++ ".useds",
|
|
string.format("$(%s.mods:%%=$(useds_subdir)%%.used)",
|
|
[s(ModuleMakeVarName)])),
|
|
MmakeVarJavas = mmake_var_defn(ModuleMakeVarName ++ ".javas",
|
|
string.format("$(%s.mods:%%=$(javas_subdir)%%.java)",
|
|
[s(ModuleMakeVarName)])),
|
|
MmakeVarAllJavas = mmake_var_defn(ModuleMakeVarName ++ ".all_javas",
|
|
string.format("$(%s.mods:%%=$(javas_subdir)%%.java)",
|
|
[s(ModuleMakeVarName)])),
|
|
|
|
% The Java compiler creates a .class file for each class within the
|
|
% original .java file. The filenames of all these can be matched with
|
|
% `module\$*.class', hence the "\\$$*.class" below.
|
|
% If no such files exist, Make will use the pattern verbatim,
|
|
% so we enclose the pattern in a `wildcard' function to prevent this.
|
|
% Evaluating the .classes variable can be slow so we make it conditional
|
|
% on the grade.
|
|
MmakeVarClassesJava = mmake_var_defn_list(ModuleMakeVarName ++ ".classes",
|
|
[string.format("$(%s.mods:%%=$(classes_subdir)%%.class)",
|
|
[s(ModuleMakeVarName)]),
|
|
string.format(
|
|
"$(wildcard $(%s.mods:%%=$(classes_subdir)%%\\$$*.class))",
|
|
[s(ModuleMakeVarName)])]),
|
|
MmakeVarClassesNonJava = mmake_var_defn(ModuleMakeVarName ++ ".classes",
|
|
""),
|
|
MmakeFragmentVarClasses = mmf_conditional_entry(
|
|
mmake_cond_grade_has_component("java"),
|
|
MmakeVarClassesJava, MmakeVarClassesNonJava),
|
|
|
|
MmakeVarCss = mmake_var_defn(ModuleMakeVarName ++ ".css",
|
|
string.format("$(%s.mods:%%=$(css_subdir)%%.cs)",
|
|
[s(ModuleMakeVarName)])),
|
|
MmakeVarAllCss = mmake_var_defn(ModuleMakeVarName ++ ".all_css",
|
|
string.format("$(%s.mods:%%=$(css_subdir)%%.cs)",
|
|
[s(ModuleMakeVarName)])),
|
|
MmakeVarDirs = mmake_var_defn(ModuleMakeVarName ++ ".dirs",
|
|
string.format("$(%s.mods:%%=$(dirs_subdir)%%.dir)",
|
|
[s(ModuleMakeVarName)])),
|
|
MmakeVarDirOs = mmake_var_defn(ModuleMakeVarName ++ ".dir_os",
|
|
string.format("$(%s.mods:%%=$(dirs_subdir)%%.dir/*.$O)",
|
|
[s(ModuleMakeVarName)])),
|
|
MmakeVarDates = mmake_var_defn(ModuleMakeVarName ++ ".dates",
|
|
string.format("$(%s.mods:%%=$(dates_subdir)%%.date)",
|
|
[s(ModuleMakeVarName)])),
|
|
MmakeVarDate0s = mmake_var_defn(ModuleMakeVarName ++ ".date0s",
|
|
string.format("$(%s.mods:%%=$(date0s_subdir)%%.date0)",
|
|
[s(ModuleMakeVarName)])),
|
|
MmakeVarDate3s = mmake_var_defn(ModuleMakeVarName ++ ".date3s",
|
|
string.format("$(%s.mods:%%=$(date3s_subdir)%%.date3)",
|
|
[s(ModuleMakeVarName)])),
|
|
MmakeVarOptDates = mmake_var_defn(ModuleMakeVarName ++ ".optdates",
|
|
string.format("$(%s.mods:%%=$(optdates_subdir)%%.optdate)",
|
|
[s(ModuleMakeVarName)])),
|
|
MmakeVarTransOptDates =
|
|
mmake_var_defn(ModuleMakeVarName ++ ".trans_opt_dates",
|
|
string.format(
|
|
"$(%s.mods:%%=$(trans_opt_dates_subdir)%%.trans_opt_date)",
|
|
[s(ModuleMakeVarName)])),
|
|
MmakeVarCDates = mmake_var_defn(ModuleMakeVarName ++ ".c_dates",
|
|
string.format("$(%s.mods:%%=$(c_dates_subdir)%%.c_date)",
|
|
[s(ModuleMakeVarName)])),
|
|
MmakeVarJavaDates = mmake_var_defn(ModuleMakeVarName ++ ".java_dates",
|
|
string.format("$(%s.mods:%%=$(java_dates_subdir)%%.java_date)",
|
|
[s(ModuleMakeVarName)])),
|
|
MmakeVarCsDates = mmake_var_defn(ModuleMakeVarName ++ ".cs_dates",
|
|
string.format("$(%s.mods:%%=$(cs_dates_subdir)%%.cs_date)",
|
|
[s(ModuleMakeVarName)])),
|
|
MmakeVarDs = mmake_var_defn(ModuleMakeVarName ++ ".ds",
|
|
string.format("$(%s.mods:%%=$(ds_subdir)%%.d)",
|
|
[s(ModuleMakeVarName)])),
|
|
|
|
% XXX Why is make_module_dep_file_extension a function?
|
|
ModuleDepFileExt = make_module_dep_file_extension,
|
|
ModuleDepFileExtStr = other_extension_to_string(ModuleDepFileExt),
|
|
MmakeVarModuleDeps = mmake_var_defn(ModuleMakeVarName ++ ".module_deps",
|
|
string.format("$(%s.mods:%%=$(module_deps_subdir)%%%s)",
|
|
[s(ModuleMakeVarName), s(ModuleDepFileExtStr)])),
|
|
|
|
(
|
|
Target = target_c,
|
|
globals.lookup_bool_option(Globals, highlevel_code, HighLevelCode),
|
|
(
|
|
HighLevelCode = yes,
|
|
% For the high level C back-end, we generate a `.mih' file
|
|
% for every module.
|
|
MihSources = [string.format("$(%s.mods:%%=$(mihs_subdir)%%.mih)",
|
|
[s(ModuleMakeVarName)])]
|
|
;
|
|
HighLevelCode = no,
|
|
% For the LLDS back-end, we don't use `.mih' files at all.
|
|
MihSources = []
|
|
),
|
|
% We use `.mh' files for both low and high level C backends.
|
|
MhSources =
|
|
[string.format("$(%s.mods:%%=%%.mh)", [s(ModuleMakeVarName)])]
|
|
;
|
|
% We don't generate C header files for non-C backends.
|
|
( Target = target_csharp
|
|
; Target = target_java
|
|
),
|
|
MihSources = [],
|
|
MhSources = []
|
|
),
|
|
MmakeVarMihs =
|
|
mmake_var_defn_list(ModuleMakeVarName ++ ".mihs", MihSources),
|
|
MmakeVarMhs = mmake_var_defn_list(ModuleMakeVarName ++ ".mhs", MhSources),
|
|
|
|
% The `<module>.all_mihs' variable is like `<module>.mihs' except that
|
|
% it contains header files for all the modules, regardless of the grade
|
|
% or --target option. It is used by the rule for `mmake realclean',
|
|
% which should remove anything that could have been automatically
|
|
% generated, even if the grade or --target option has changed.
|
|
MmakeVarAllMihs = mmake_var_defn(ModuleMakeVarName ++ ".all_mihs",
|
|
string.format("$(%s.mods:%%=$(mihs_subdir)%%.mih)",
|
|
[s(ModuleMakeVarName)])),
|
|
|
|
% The `<module>.all_mhs' variable is like `<module>.mhs' except that
|
|
% it contains header files for all the modules, as for `<module>.all_mihs'
|
|
% above.
|
|
MmakeVarAllMhs = mmake_var_defn(ModuleMakeVarName ++ ".all_mhs",
|
|
string.format("$(%s.mods:%%=%%.mh)",
|
|
[s(ModuleMakeVarName)])),
|
|
|
|
MmakeVarInts = mmake_var_defn_list(ModuleMakeVarName ++ ".ints",
|
|
[string.format("$(%s.mods:%%=$(ints_subdir)%%.int)",
|
|
[s(ModuleMakeVarName)]),
|
|
string.format("$(%s.mods:%%=$(int2s_subdir)%%.int2)",
|
|
[s(ModuleMakeVarName)])]),
|
|
% `.int0' files are only generated for modules with submodules.
|
|
% XXX ... or at least they should be. Currently we end up generating
|
|
% .int0 files for nested submodules that don't have any children.
|
|
% (We do the correct thing for separate submodules.)
|
|
MmakeVarInt0s = mmake_var_defn(ModuleMakeVarName ++ ".int0s",
|
|
string.format("$(%s.parent_mods:%%=$(int0s_subdir)%%.int0)",
|
|
[s(ModuleMakeVarName)])),
|
|
% XXX The `<module>.all_int0s' variables is like `<module>.int0s' except
|
|
% that it contains .int0 files for all modules, regardless of whether
|
|
% they should have been created or not. It is used by the rule for
|
|
% `mmake realclean' to ensure that we clean up all the .int0 files,
|
|
% including the ones that were accidently created by the bug described
|
|
% above.
|
|
MmakeVarAllInt0s = mmake_var_defn(ModuleMakeVarName ++ ".all_int0s",
|
|
string.format("$(%s.mods:%%=$(int0s_subdir)%%.int0)",
|
|
[s(ModuleMakeVarName)])),
|
|
MmakeVarInt3s = mmake_var_defn(ModuleMakeVarName ++ ".int3s",
|
|
string.format("$(%s.mods:%%=$(int3s_subdir)%%.int3)",
|
|
[s(ModuleMakeVarName)])),
|
|
MmakeVarOpts = mmake_var_defn(ModuleMakeVarName ++ ".opts",
|
|
string.format("$(%s.mods:%%=$(opts_subdir)%%.opt)",
|
|
[s(ModuleMakeVarName)])),
|
|
MmakeVarTransOpts = mmake_var_defn(ModuleMakeVarName ++ ".trans_opts",
|
|
string.format("$(%s.mods:%%=$(trans_opts_subdir)%%.trans_opt)",
|
|
[s(ModuleMakeVarName)])),
|
|
MmakeVarAnalysiss = mmake_var_defn(ModuleMakeVarName ++ ".analysiss",
|
|
string.format("$(%s.mods:%%=$(analysiss_subdir)%%.analysis)",
|
|
[s(ModuleMakeVarName)])),
|
|
MmakeVarRequests = mmake_var_defn(ModuleMakeVarName ++ ".requests",
|
|
string.format("$(%s.mods:%%=$(requests_subdir)%%.request)",
|
|
[s(ModuleMakeVarName)])),
|
|
MmakeVarImdgs = mmake_var_defn(ModuleMakeVarName ++ ".imdgs",
|
|
string.format("$(%s.mods:%%=$(imdgs_subdir)%%.imdg)",
|
|
[s(ModuleMakeVarName)])),
|
|
MmakeVarProfs = mmake_var_defn(ModuleMakeVarName ++ ".profs",
|
|
string.format("$(%s.mods:%%=%%.prof)",
|
|
[s(ModuleMakeVarName)])),
|
|
|
|
MmakeFragmentsA = list.map(mmake_entry_to_fragment,
|
|
[MmakeStartComment, MmakeVarModuleMs,
|
|
MmakeVarModuleDepErrs, MmakeVarModuleErrs,
|
|
MmakeVarModuleMods, MmakeVarModuleParentMods,
|
|
MmakeVarForeignModules, MmakeVarForeignFileNames, MmakeVarForeignDlls,
|
|
MmakeVarInitCs, MmakeVarAllCs, MmakeVarCs, MmakeVarDlls,
|
|
MmakeVarAllOs, MmakeVarAllPicOs, MmakeVarOs, MmakeVarPicOs,
|
|
MmakeVarUseds,
|
|
MmakeVarJavas, MmakeVarAllJavas]),
|
|
MmakeFragmentsB = list.map(mmake_entry_to_fragment,
|
|
[MmakeVarCss, MmakeVarAllCss,
|
|
MmakeVarDirs, MmakeVarDirOs,
|
|
MmakeVarDates, MmakeVarDate0s, MmakeVarDate3s,
|
|
MmakeVarOptDates, MmakeVarTransOptDates,
|
|
MmakeVarCDates, MmakeVarJavaDates, MmakeVarCsDates,
|
|
MmakeVarDs, MmakeVarModuleDeps, MmakeVarMihs,
|
|
MmakeVarMhs, MmakeVarAllMihs, MmakeVarAllMhs,
|
|
MmakeVarInts, MmakeVarInt0s, MmakeVarAllInt0s, MmakeVarInt3s,
|
|
MmakeVarOpts, MmakeVarTransOpts,
|
|
MmakeVarAnalysiss, MmakeVarRequests, MmakeVarImdgs, MmakeVarProfs]),
|
|
MmakeFile =
|
|
cord.from_list(MmakeFragmentsA) ++
|
|
cord.singleton(MmakeFragmentVarClasses) ++
|
|
cord.from_list(MmakeFragmentsB).
|
|
|
|
%---------------------%
|
|
|
|
:- pred select_ok_modules(deps_map::in, list(module_name)::in,
|
|
list(module_name)::out) is det.
|
|
|
|
select_ok_modules(_, [], []).
|
|
select_ok_modules(DepsMap, [ModuleName | ModuleNames0], ModuleNames) :-
|
|
select_ok_modules(DepsMap, ModuleNames0, ModuleNamesTail),
|
|
map.lookup(DepsMap, ModuleName, deps(_, BurdenedModule)),
|
|
Baggage = BurdenedModule ^ bm_baggage,
|
|
ModuleErrors = Baggage ^ mb_errors,
|
|
FatalErrors = ModuleErrors ^ rm_fatal_errors,
|
|
( if set.is_empty(FatalErrors) then
|
|
ModuleNames = [ModuleName | ModuleNamesTail]
|
|
else
|
|
ModuleNames = ModuleNamesTail
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
% get_fact_table_file_names(DepsMap, Modules, ExtraLinkObjs):
|
|
%
|
|
% Find any extra .$O files that should be linked into the executable.
|
|
% These include fact table object files and object files for foreign
|
|
% code that can't be generated inline for this target.
|
|
%
|
|
:- pred get_fact_table_file_names(deps_map::in, list(module_name)::in,
|
|
list(file_name)::out) is det.
|
|
|
|
get_fact_table_file_names(DepsMap, Modules, FactTableFileNames) :-
|
|
% It is possible, though very unlikely, that two or more modules
|
|
% depend on the same fact table.
|
|
get_fact_table_file_names(DepsMap, Modules,
|
|
set.init, FactTableFileNamesSet),
|
|
set.to_sorted_list(FactTableFileNamesSet, FactTableFileNames).
|
|
|
|
% Gather file names of fact tables.
|
|
%
|
|
:- pred get_fact_table_file_names(deps_map::in, list(module_name)::in,
|
|
set(file_name)::in, set(file_name)::out) is det.
|
|
|
|
get_fact_table_file_names(_DepsMap, [], !FactTableFileNames).
|
|
get_fact_table_file_names(DepsMap, [Module | Modules], !FactTableFileNames) :-
|
|
map.lookup(DepsMap, Module, deps(_, BurdenedModule)),
|
|
ParseTreeModuleSrc = BurdenedModule ^ bm_module,
|
|
get_fact_tables(ParseTreeModuleSrc, FactTableFileNames),
|
|
% Handle object files for foreign code.
|
|
% NOTE: currently none of the backends support foreign code
|
|
% in a non target language.
|
|
set.union(FactTableFileNames, !FactTableFileNames),
|
|
get_fact_table_file_names(DepsMap, Modules, !FactTableFileNames).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
generate_dependencies_write_dep_file(Globals, SourceFileName, ModuleName,
|
|
DepsMap, !IO) :-
|
|
globals.lookup_bool_option(Globals, verbose, Verbose),
|
|
module_name_to_file_name(Globals, $pred, do_create_dirs,
|
|
ext_other(other_ext(".dep")), ModuleName, DepFileName, !IO),
|
|
get_progress_output_stream(Globals, ModuleName, ProgressStream, !IO),
|
|
string.format("%% Creating auto-dependency file `%s'...\n",
|
|
[s(DepFileName)], CreatingMsg),
|
|
maybe_write_string(ProgressStream, Verbose, CreatingMsg, !IO),
|
|
io.open_output(DepFileName, DepResult, !IO),
|
|
(
|
|
DepResult = ok(DepStream),
|
|
generate_dep_file(Globals, SourceFileName, ModuleName, DepsMap,
|
|
MmakeFile, !IO),
|
|
write_mmakefile(DepStream, MmakeFile, !IO),
|
|
io.close_output(DepStream, !IO),
|
|
maybe_write_string(ProgressStream, Verbose, "% done.\n", !IO)
|
|
;
|
|
DepResult = error(IOError),
|
|
maybe_write_string(ProgressStream, Verbose, " failed.\n", !IO),
|
|
maybe_flush_output(ProgressStream, Verbose, !IO),
|
|
get_error_output_stream(Globals, ModuleName, ErrorStream, !IO),
|
|
io.error_message(IOError, IOErrorMessage),
|
|
string.format("error opening file `%s' for output: %s",
|
|
[s(DepFileName), s(IOErrorMessage)], DepMessage),
|
|
report_error(ErrorStream, DepMessage, !IO)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- type maybe_mmake_var == pair(list(string), string).
|
|
|
|
:- pred generate_dep_file(globals::in, file_name::in, module_name::in,
|
|
deps_map::in, mmakefile::out, io::di, io::uo) is det.
|
|
|
|
generate_dep_file(Globals, SourceFileName, ModuleName, DepsMap,
|
|
!:MmakeFile, !IO) :-
|
|
ModuleNameString = sym_name_to_string(ModuleName),
|
|
library.version(Version, FullArch),
|
|
|
|
MmakeStartComment = mmake_start_comment("program dependencies",
|
|
ModuleNameString, SourceFileName, Version, FullArch),
|
|
|
|
module_name_to_make_var_name(ModuleName, ModuleMakeVarName),
|
|
|
|
module_name_to_file_name(Globals, $pred, do_create_dirs,
|
|
ext_other(other_ext(".init")), ModuleName, InitFileName, !IO),
|
|
module_name_to_file_name(Globals, $pred, do_create_dirs,
|
|
ext_other(other_ext("_init.c")), ModuleName, InitCFileName, !IO),
|
|
module_name_to_file_name(Globals, $pred, do_create_dirs,
|
|
ext_other(other_ext("_init.$O")), ModuleName, InitObjFileName, !IO),
|
|
module_name_to_file_name(Globals, $pred, do_create_dirs,
|
|
ext_other(other_ext("_init.pic_o")),
|
|
ModuleName, InitPicObjFileName, !IO),
|
|
|
|
globals.lookup_bool_option(Globals, generate_mmc_make_module_dependencies,
|
|
MmcMakeDeps),
|
|
globals.lookup_bool_option(Globals, intermodule_optimization, Intermod),
|
|
globals.lookup_bool_option(Globals, transitive_optimization, TransOpt),
|
|
(
|
|
MmcMakeDeps = yes,
|
|
ModuleDepsVar = "$(" ++ ModuleMakeVarName ++ ".module_deps)",
|
|
MaybeModuleDepsVar = [ModuleDepsVar],
|
|
MaybeModuleDepsVarSpace = ModuleDepsVar ++ " "
|
|
;
|
|
MmcMakeDeps = no,
|
|
MaybeModuleDepsVar = [],
|
|
MaybeModuleDepsVarSpace = ""
|
|
),
|
|
(
|
|
Intermod = yes,
|
|
OptsVar = "$(" ++ ModuleMakeVarName ++ ".opts)",
|
|
MaybeOptsVar = [OptsVar],
|
|
MaybeOptsVarSpace = OptsVar ++ " "
|
|
;
|
|
Intermod = no,
|
|
MaybeOptsVar = [],
|
|
MaybeOptsVarSpace = ""
|
|
),
|
|
(
|
|
TransOpt = yes,
|
|
TransOptsVar = "$(" ++ ModuleMakeVarName ++ ".trans_opts)",
|
|
MaybeTransOptsVar = [TransOptsVar],
|
|
MaybeTransOptsVarSpace = TransOptsVar ++ " "
|
|
;
|
|
TransOpt = no,
|
|
MaybeTransOptsVar = [],
|
|
MaybeTransOptsVarSpace = ""
|
|
),
|
|
MaybeModuleDepsVarPair = MaybeModuleDepsVar - MaybeModuleDepsVarSpace,
|
|
MaybeOptsVarPair = MaybeOptsVar - MaybeOptsVarSpace,
|
|
MaybeTransOptsVarPair = MaybeTransOptsVar - MaybeTransOptsVarSpace,
|
|
|
|
start_mmakefile(!:MmakeFile),
|
|
add_mmake_entry(MmakeStartComment, !MmakeFile),
|
|
generate_dep_file_exec_library_targets(Globals, ModuleName,
|
|
ModuleMakeVarName, InitFileName, InitObjFileName,
|
|
MaybeOptsVar, MaybeTransOptsVar,
|
|
ExeFileName, JarFileName, LibFileName, SharedLibFileName,
|
|
!MmakeFile, !IO),
|
|
generate_dep_file_init_targets(Globals, ModuleName, ModuleMakeVarName,
|
|
InitCFileName, InitFileName, DepFileName, DvFileName, !MmakeFile, !IO),
|
|
generate_dep_file_install_targets(Globals, ModuleName, DepsMap,
|
|
ModuleMakeVarName, MmcMakeDeps, Intermod, TransOpt,
|
|
MaybeModuleDepsVarPair, MaybeOptsVarPair, MaybeTransOptsVarPair,
|
|
!MmakeFile, !IO),
|
|
generate_dep_file_collective_targets(Globals, ModuleName,
|
|
ModuleMakeVarName, !MmakeFile, !IO),
|
|
generate_dep_file_clean_targets(Globals, ModuleName, ModuleMakeVarName,
|
|
ExeFileName, InitCFileName, InitObjFileName, InitPicObjFileName,
|
|
InitFileName, LibFileName, SharedLibFileName, JarFileName,
|
|
DepFileName, DvFileName, !MmakeFile, !IO).
|
|
|
|
:- pred generate_dep_file_exec_library_targets(globals::in,
|
|
module_name::in, string::in, string::in, string::in,
|
|
list(string)::in, list(string)::in,
|
|
string::out, string::out, string::out, string::out,
|
|
mmakefile::in, mmakefile::out, io::di, io::uo) is det.
|
|
|
|
generate_dep_file_exec_library_targets(Globals, ModuleName,
|
|
ModuleMakeVarName, InitFileName, InitObjFileName,
|
|
MaybeOptsVar, MaybeTransOptsVar,
|
|
ExeFileName, JarFileName, LibFileName, SharedLibFileName,
|
|
!MmakeFile, !IO) :-
|
|
module_name_to_file_name(Globals, $pred, do_not_create_dirs,
|
|
ext_other(other_ext("")), ModuleName, ExeFileName, !IO),
|
|
MmakeRuleExtForExe = mmake_simple_rule("ext_for_exe",
|
|
mmake_rule_is_phony,
|
|
ExeFileName,
|
|
[ExeFileName ++ "$(EXT_FOR_EXE)"],
|
|
[]),
|
|
MmakeFragmentExtForExe = mmf_conditional_fragments(
|
|
mmake_cond_strings_not_equal("$(EXT_FOR_EXE)", ""),
|
|
[mmf_entry(MmakeRuleExtForExe)], []),
|
|
|
|
% Note we have to do some ``interesting'' hacks to get
|
|
% `$(ALL_MLLIBS_DEP)' to work in the dependency list,
|
|
% without getting complaints about undefined variables.
|
|
All_MLLibsDep =
|
|
"$(foreach @," ++ ModuleMakeVarName ++ ",$(ALL_MLLIBS_DEP))",
|
|
All_MLObjs =
|
|
"$(foreach @," ++ ModuleMakeVarName ++ ",$(ALL_MLOBJS))",
|
|
All_MLPicObjs =
|
|
"$(patsubst %.o,%.$(EXT_FOR_PIC_OBJECTS)," ++
|
|
"$(foreach @," ++ ModuleMakeVarName ++ ",$(ALL_MLOBJS)))",
|
|
|
|
NL_All_MLObjs = "\\\n\t\t" ++ All_MLObjs,
|
|
|
|
% When compiling to C, we want to include $(foo.cs) first in
|
|
% the dependency list, before $(foo.os).
|
|
% This is not strictly necessary, since the .$O files themselves depend
|
|
% on the .c files, but want to do it to ensure that Make will try to
|
|
% create all the C files first, thus detecting errors early,
|
|
% rather than first spending time compiling C files to .$O,
|
|
% which could be a waste of time if the program contains errors.
|
|
|
|
ModuleMakeVarNameClasses = "$(" ++ ModuleMakeVarName ++ ".classes)",
|
|
|
|
ModuleMakeVarNameOs = "$(" ++ ModuleMakeVarName ++ ".os)",
|
|
NonJavaMainRuleAction1Line1 =
|
|
"$(ML) $(ALL_GRADEFLAGS) $(ALL_MLFLAGS) -- $(ALL_LDFLAGS) " ++
|
|
"$(EXEFILE_OPT)" ++ ExeFileName ++ "$(EXT_FOR_EXE) " ++
|
|
InitObjFileName ++ " \\",
|
|
NonJavaMainRuleAction1Line2 =
|
|
"\t" ++ ModuleMakeVarNameOs ++ " " ++ NL_All_MLObjs ++
|
|
" $(ALL_MLLIBS)",
|
|
MmakeRuleExecutableJava = mmake_simple_rule("executable_java",
|
|
mmake_rule_is_not_phony,
|
|
ExeFileName,
|
|
[ModuleMakeVarNameClasses],
|
|
[]),
|
|
MmakeRuleExecutableNonJava = mmake_simple_rule("executable_non_java",
|
|
mmake_rule_is_not_phony,
|
|
ExeFileName ++ "$(EXT_FOR_EXE)",
|
|
[ModuleMakeVarNameOs, InitObjFileName, All_MLObjs, All_MLLibsDep],
|
|
[NonJavaMainRuleAction1Line1, NonJavaMainRuleAction1Line2]),
|
|
MmakeFragmentExecutable = mmf_conditional_entry(
|
|
mmake_cond_grade_has_component("java"),
|
|
MmakeRuleExecutableJava, MmakeRuleExecutableNonJava),
|
|
|
|
module_name_to_lib_file_name(Globals, $pred, do_not_create_dirs,
|
|
"lib", other_ext(""), ModuleName, LibTargetName, !IO),
|
|
module_name_to_lib_file_name(Globals, $pred, do_create_dirs,
|
|
"lib", other_ext(".$A"), ModuleName, LibFileName, !IO),
|
|
module_name_to_lib_file_name(Globals, $pred, do_create_dirs,
|
|
"lib", other_ext(".$(EXT_FOR_SHARED_LIB)"),
|
|
ModuleName, SharedLibFileName, !IO),
|
|
module_name_to_lib_file_name(Globals, $pred, do_not_create_dirs,
|
|
"lib", other_ext(".$(EXT_FOR_SHARED_LIB)"),
|
|
ModuleName, MaybeSharedLibFileName, !IO),
|
|
module_name_to_file_name(Globals, $pred, do_not_create_dirs,
|
|
ext_other(other_ext(".jar")), ModuleName, JarFileName, !IO),
|
|
|
|
% Set up the installed name for shared libraries.
|
|
|
|
globals.lookup_bool_option(Globals, shlib_linker_use_install_name,
|
|
UseInstallName),
|
|
(
|
|
UseInstallName = yes,
|
|
get_install_name_option(Globals, SharedLibFileName, InstallNameOpt)
|
|
;
|
|
UseInstallName = no,
|
|
InstallNameOpt = ""
|
|
),
|
|
|
|
ModuleMakeVarNameInts = "$(" ++ ModuleMakeVarName ++ ".ints)",
|
|
ModuleMakeVarNameInt3s = "$(" ++ ModuleMakeVarName ++ ".int3s)",
|
|
AllIntSources = [ModuleMakeVarNameInts, ModuleMakeVarNameInt3s] ++
|
|
MaybeOptsVar ++ MaybeTransOptsVar ++ [InitFileName],
|
|
MmakeRuleLibTargetJava = mmake_simple_rule("lib_target_java",
|
|
mmake_rule_is_phony,
|
|
LibTargetName,
|
|
[JarFileName | AllIntSources],
|
|
[]),
|
|
MmakeRuleLibTargetNonJava = mmake_simple_rule("lib_target_non_java",
|
|
mmake_rule_is_phony,
|
|
LibTargetName,
|
|
[LibFileName, MaybeSharedLibFileName | AllIntSources],
|
|
[]),
|
|
MmakeFragmentLibTarget = mmf_conditional_entry(
|
|
mmake_cond_grade_has_component("java"),
|
|
MmakeRuleLibTargetJava, MmakeRuleLibTargetNonJava),
|
|
|
|
ModuleMakeVarNamePicOs = "$(" ++ ModuleMakeVarName ++ ".pic_os)",
|
|
SharedLibAction1Line1 =
|
|
"$(ML) --make-shared-lib $(ALL_GRADEFLAGS) $(ALL_MLFLAGS) " ++
|
|
"-- " ++ InstallNameOpt ++ " $(ALL_LD_LIBFLAGS) " ++
|
|
"-o " ++ SharedLibFileName ++ " \\",
|
|
SharedLibAction1Line2 = "\t" ++ ModuleMakeVarNamePicOs ++ " \\",
|
|
SharedLibAction1Line3 = "\t" ++ All_MLPicObjs ++ " $(ALL_MLLIBS)",
|
|
MmakeRuleSharedLib = mmake_simple_rule("shared_lib",
|
|
mmake_rule_is_not_phony,
|
|
SharedLibFileName,
|
|
[ModuleMakeVarNamePicOs, All_MLPicObjs, All_MLLibsDep],
|
|
[SharedLibAction1Line1, SharedLibAction1Line2, SharedLibAction1Line3]),
|
|
MmakeFragmentSharedLib = mmf_conditional_fragments(
|
|
mmake_cond_strings_not_equal("$(EXT_FOR_SHARED_LIB)", "$(A)"),
|
|
[mmf_entry(MmakeRuleSharedLib)], []),
|
|
|
|
LibAction1 = "rm -f " ++ LibFileName,
|
|
LibAction2Line1 =
|
|
"$(AR) $(ALL_ARFLAGS) $(AR_LIBFILE_OPT)" ++ LibFileName ++
|
|
" " ++ ModuleMakeVarNameOs ++ " \\",
|
|
LibAction2Line2 = "\t" ++ All_MLObjs,
|
|
LibAction3 = "$(RANLIB) $(ALL_RANLIBFLAGS) " ++ LibFileName,
|
|
MmakeRuleLib = mmake_simple_rule("lib",
|
|
mmake_rule_is_not_phony,
|
|
LibFileName,
|
|
[ModuleMakeVarNameOs, All_MLObjs],
|
|
[LibAction1, LibAction2Line1, LibAction2Line2, LibAction3]),
|
|
|
|
list_class_files_for_jar_mmake(Globals, ModuleMakeVarNameClasses,
|
|
ListClassFiles),
|
|
JarAction1 = "$(JAR) $(JAR_CREATE_FLAGS) " ++ JarFileName ++ " " ++
|
|
ListClassFiles,
|
|
MmakeRuleJar = mmake_simple_rule("jar",
|
|
mmake_rule_is_not_phony,
|
|
JarFileName,
|
|
[ModuleMakeVarNameClasses],
|
|
[JarAction1]),
|
|
|
|
add_mmake_fragment(MmakeFragmentExtForExe, !MmakeFile),
|
|
add_mmake_fragment(MmakeFragmentExecutable, !MmakeFile),
|
|
add_mmake_fragment(MmakeFragmentLibTarget, !MmakeFile),
|
|
add_mmake_fragment(MmakeFragmentSharedLib, !MmakeFile),
|
|
add_mmake_entries([MmakeRuleLib, MmakeRuleJar], !MmakeFile).
|
|
|
|
:- pred generate_dep_file_init_targets(globals::in,
|
|
module_name::in, string::in, string::in, string::in,
|
|
string::out, string::out,
|
|
mmakefile::in, mmakefile::out, io::di, io::uo) is det.
|
|
|
|
generate_dep_file_init_targets(Globals, ModuleName, ModuleMakeVarName,
|
|
InitCFileName, InitFileName, DepFileName, DvFileName,
|
|
!MmakeFile, !IO) :-
|
|
module_name_to_file_name(Globals, $pred, do_not_create_dirs,
|
|
ext_other(other_ext(".dep")), ModuleName, DepFileName, !IO),
|
|
module_name_to_file_name(Globals, $pred, do_not_create_dirs,
|
|
ext_other(other_ext(".dv")), ModuleName, DvFileName, !IO),
|
|
|
|
ModuleMakeVarNameCs = "$(" ++ ModuleMakeVarName ++ ".cs)",
|
|
InitAction1 = "echo > " ++ InitFileName,
|
|
InitAction2 = "$(MKLIBINIT) " ++ ModuleMakeVarNameCs ++
|
|
" >> " ++ InitFileName,
|
|
% $(EXTRA_INIT_COMMAND) should expand to a command to
|
|
% generate extra entries in the `.init' file for a library.
|
|
% It may expand to the empty string.
|
|
InitAction3 = "$(EXTRA_INIT_COMMAND) >> " ++ InitFileName,
|
|
MmakeRuleInitFile = mmake_simple_rule("init_file",
|
|
mmake_rule_is_not_phony,
|
|
InitFileName,
|
|
[DepFileName, ModuleMakeVarNameCs],
|
|
[InitAction1, InitAction2, InitAction3]),
|
|
|
|
% The `force-module_init' dependency forces the commands for
|
|
% the `module_init.c' rule to be run every time the rule
|
|
% is considered.
|
|
ModuleFileName = sym_name_to_string(ModuleName),
|
|
ForceC2InitTarget = "force-" ++ ModuleFileName ++ "_init",
|
|
MmakeRuleForceInitCFile = mmake_simple_rule("force_init_c_file",
|
|
mmake_rule_is_not_phony,
|
|
ForceC2InitTarget,
|
|
[],
|
|
[]),
|
|
|
|
TmpInitCFileName = InitCFileName ++ ".tmp",
|
|
ModuleMakeVarNameInitCs = "$(" ++ ModuleMakeVarName ++ ".init_cs)",
|
|
InitCAction1 =
|
|
"@$(C2INIT) $(ALL_GRADEFLAGS) $(ALL_C2INITFLAGS) " ++
|
|
"--init-c-file " ++ TmpInitCFileName ++ " " ++
|
|
ModuleMakeVarNameInitCs ++ " $(ALL_C2INITARGS)",
|
|
InitCAction2 = "@mercury_update_interface " ++ InitCFileName,
|
|
MmakeRuleInitCFile = mmake_simple_rule("init_c_file",
|
|
mmake_rule_is_not_phony,
|
|
InitCFileName,
|
|
[ForceC2InitTarget, ModuleMakeVarNameCs],
|
|
[InitCAction1, InitCAction2]),
|
|
|
|
add_mmake_entries(
|
|
[MmakeRuleInitFile, MmakeRuleForceInitCFile, MmakeRuleInitCFile],
|
|
!MmakeFile).
|
|
|
|
:- pred generate_dep_file_install_targets(globals::in, module_name::in,
|
|
deps_map::in, string::in, bool::in, bool::in, bool::in,
|
|
maybe_mmake_var::in, maybe_mmake_var::in, maybe_mmake_var::in,
|
|
mmakefile::in, mmakefile::out, io::di, io::uo) is det.
|
|
|
|
generate_dep_file_install_targets(Globals, ModuleName, DepsMap,
|
|
ModuleMakeVarName, MmcMakeDeps, Intermod, TransOpt,
|
|
MaybeModuleDepsVarPair, MaybeOptsVarPair, MaybeTransOptsVarPair,
|
|
!MmakeFile, !IO) :-
|
|
% XXX Note that we install the `.opt' and `.trans_opt' files
|
|
% in two places: in the `lib/$(GRADE)/opts' directory, so
|
|
% that mmc will find them, and also in the `ints' directory,
|
|
% so that Mmake will find them. That is not ideal, but it works.
|
|
|
|
MaybeOptsVarPair = MaybeOptsVar - MaybeOptsVarSpace,
|
|
MaybeTransOptsVarPair = MaybeTransOptsVar - MaybeTransOptsVarSpace,
|
|
MaybeModuleDepsVarPair = MaybeModuleDepsVar - MaybeModuleDepsVarSpace,
|
|
|
|
module_name_to_lib_file_name(Globals, $pred, do_not_create_dirs,
|
|
"lib", other_ext(".install_ints"), ModuleName,
|
|
LibInstallIntsTargetName, !IO),
|
|
module_name_to_lib_file_name(Globals, $pred, do_not_create_dirs,
|
|
"lib", other_ext(".install_opts"), ModuleName,
|
|
LibInstallOptsTargetName, !IO),
|
|
module_name_to_lib_file_name(Globals, $pred, do_not_create_dirs,
|
|
"lib", other_ext(".install_hdrs"), ModuleName,
|
|
LibInstallHdrsTargetName, !IO),
|
|
module_name_to_lib_file_name(Globals, $pred, do_not_create_dirs,
|
|
"lib", other_ext(".install_grade_hdrs"), ModuleName,
|
|
LibInstallGradeHdrsTargetName, !IO),
|
|
|
|
ModuleMakeVarNameInts = "$(" ++ ModuleMakeVarName ++ ".ints)",
|
|
ModuleMakeVarNameInt3s = "$(" ++ ModuleMakeVarName ++ ".int3s)",
|
|
|
|
(
|
|
Intermod = yes,
|
|
MaybeSpaceOptStr = " opt"
|
|
;
|
|
Intermod = no,
|
|
MaybeSpaceOptStr = ""
|
|
),
|
|
( if
|
|
Intermod = yes,
|
|
some [BurdenedModule] (
|
|
map.member(DepsMap, _, deps(_, BurdenedModule)),
|
|
ParseTreeModuleSrc = BurdenedModule ^ bm_module,
|
|
IncludeMap = ParseTreeModuleSrc ^ ptms_include_map,
|
|
not map.is_empty(IncludeMap)
|
|
)
|
|
then
|
|
% The `.int0' files only need to be installed with
|
|
% `--intermodule-optimization'.
|
|
SpaceInt0Str = " int0",
|
|
ModuleVarNameInt0s = "$(" ++ ModuleMakeVarName ++ ".int0s)",
|
|
MaybeModuleVarNameInt0sSpace = ModuleVarNameInt0s ++ " ",
|
|
MaybeModuleVarNameInt0s = [ModuleVarNameInt0s]
|
|
else
|
|
SpaceInt0Str = "",
|
|
MaybeModuleVarNameInt0sSpace = "",
|
|
MaybeModuleVarNameInt0s = []
|
|
),
|
|
(
|
|
TransOpt = yes,
|
|
MaybeSpaceTransOptStr = " trans_opt"
|
|
;
|
|
TransOpt = no,
|
|
MaybeSpaceTransOptStr = ""
|
|
),
|
|
(
|
|
MmcMakeDeps = yes,
|
|
MaybeSpaceDepStr = " module_dep"
|
|
;
|
|
MmcMakeDeps = no,
|
|
MaybeSpaceDepStr = ""
|
|
),
|
|
|
|
LibInstallIntsFiles = """" ++
|
|
ModuleMakeVarNameInts ++ " " ++ ModuleMakeVarNameInt3s ++ " " ++
|
|
MaybeModuleVarNameInt0sSpace ++ MaybeOptsVarSpace ++
|
|
MaybeTransOptsVarSpace ++ MaybeModuleDepsVarSpace ++ """",
|
|
|
|
MmakeRuleLibInstallInts = mmake_simple_rule("lib_install_ints",
|
|
mmake_rule_is_phony,
|
|
LibInstallIntsTargetName,
|
|
[ModuleMakeVarNameInts, ModuleMakeVarNameInt3s] ++
|
|
MaybeModuleVarNameInt0s ++ MaybeOptsVar ++ MaybeTransOptsVar ++
|
|
MaybeModuleDepsVar ++ ["install_lib_dirs"],
|
|
["files=" ++ LibInstallIntsFiles ++ "; \\",
|
|
"for file in $$files; do \\",
|
|
"\ttarget=""$(INSTALL_INT_DIR)/`basename $$file`""; \\",
|
|
"\tif cmp -s ""$$file"" ""$$target""; then \\",
|
|
"\t\techo \"$$target unchanged\"; \\",
|
|
"\telse \\",
|
|
"\t\techo \"installing $$target\"; \\",
|
|
"\t\t$(INSTALL) ""$$file"" ""$$target""; \\",
|
|
"\tfi; \\",
|
|
"done",
|
|
"# The following is needed to support the `--use-subdirs' option.",
|
|
"# We try using `$(LN_S)', but if that fails, then we just use",
|
|
"# `$(INSTALL)'.",
|
|
"for ext in int int2 int3" ++
|
|
SpaceInt0Str ++ MaybeSpaceOptStr ++ MaybeSpaceTransOptStr ++
|
|
MaybeSpaceDepStr ++ "; do \\",
|
|
"\tdir=""$(INSTALL_INT_DIR)/Mercury/$${ext}s""; \\",
|
|
"\trm -rf ""$$dir""; \\",
|
|
"\t$(LN_S) .. ""$$dir"" || { \\",
|
|
"\t\t{ [ -d ""$$dir"" ] || \\",
|
|
"\t\t$(INSTALL_MKDIR) ""$$dir""; } && \\",
|
|
"\t\t$(INSTALL) ""$(INSTALL_INT_DIR)""/*.$$ext ""$$dir""; \\",
|
|
"\t} || exit 1; \\",
|
|
"done"]),
|
|
|
|
( if
|
|
Intermod = no,
|
|
TransOpt = no
|
|
then
|
|
LibInstallOptsSources = [],
|
|
LibInstallOptsActions = [silent_noop_action]
|
|
else
|
|
LibInstallOptsSources = MaybeOptsVar ++ MaybeTransOptsVar ++
|
|
["install_grade_dirs"],
|
|
LibInstallOptsFiles =
|
|
"""" ++ MaybeOptsVarSpace ++ MaybeTransOptsVarSpace ++ """",
|
|
LibInstallOptsActions =
|
|
["files=" ++ LibInstallOptsFiles ++ "; \\",
|
|
"for file in $$files; do \\",
|
|
"\ttarget=""$(INSTALL_GRADE_INT_DIR)/`basename $$file`"";\\",
|
|
"\tif cmp -s ""$$file"" ""$$target""; then \\",
|
|
"\t\techo \"$$target unchanged\"; \\",
|
|
"\telse \\",
|
|
"\t\techo \"installing $$target\"; \\",
|
|
"\t\t$(INSTALL) ""$$file"" ""$$target""; \\",
|
|
"\tfi; \\",
|
|
"done",
|
|
"# The following is needed to support the `--use-subdirs' option",
|
|
"# We try using `$(LN_S)', but if that fails, then we just use",
|
|
"# `$(INSTALL)'.",
|
|
"for ext in " ++ MaybeSpaceOptStr ++ MaybeSpaceTransOptStr ++
|
|
"; do \\",
|
|
"\tdir=""$(INSTALL_GRADE_INT_DIR)/Mercury/$${ext}s""; \\",
|
|
"\trm -rf ""$$dir""; \\",
|
|
"\t$(LN_S) .. ""$$dir"" || { \\",
|
|
"\t\t{ [ -d ""$$dir"" ] || \\",
|
|
"\t\t\t$(INSTALL_MKDIR) ""$$dir""; } && \\",
|
|
"\t\t$(INSTALL) ""$(INSTALL_GRADE_INT_DIR)""/*.$$ext \\",
|
|
"\t\t\t""$$dir""; \\",
|
|
"\t} || exit 1; \\",
|
|
"done"]
|
|
),
|
|
MmakeRuleLibInstallOpts = mmake_simple_rule("lib_install_opts",
|
|
mmake_rule_is_phony,
|
|
LibInstallOptsTargetName,
|
|
LibInstallOptsSources,
|
|
LibInstallOptsActions),
|
|
|
|
% XXX Note that we install the header files in two places:
|
|
% in the `lib/inc' or `lib/$(GRADE)/$(FULLARCH)/inc' directory,
|
|
% so that the C compiler will find them, and also in the `ints' directory,
|
|
% so that Mmake will find them. That is not ideal, but it works.
|
|
%
|
|
% (A better fix would be to change the VPATH setting in
|
|
% scripts/Mmake.vars.in so that Mmake also searches the
|
|
% `lib/$(GRADE)/$(FULLARCH)/inc' directory, but doing that properly
|
|
% is non-trivial.)
|
|
|
|
ModuleMakeVarNameMhs = string.format("$(%s.mhs)", [s(ModuleMakeVarName)]),
|
|
MmakeRuleLibInstallHdrsNoMhs = mmake_simple_rule("install_lib_hdrs_nomhs",
|
|
mmake_rule_is_phony,
|
|
LibInstallHdrsTargetName,
|
|
[ModuleMakeVarNameMhs, "install_lib_dirs"],
|
|
[silent_noop_action]),
|
|
MmakeRuleLibInstallHdrsMhs = mmake_simple_rule("install_lib_hdrs_mhs",
|
|
mmake_rule_is_phony,
|
|
LibInstallHdrsTargetName,
|
|
[ModuleMakeVarNameMhs, "install_lib_dirs"],
|
|
["for hdr in " ++ ModuleMakeVarNameMhs ++ "; do \\",
|
|
"\t$(INSTALL) $$hdr $(INSTALL_INT_DIR); \\",
|
|
"\t$(INSTALL) $$hdr $(INSTALL_INC_DIR); \\",
|
|
"done"]),
|
|
MmakeFragmentLibInstallHdrs = mmf_conditional_entry(
|
|
mmake_cond_strings_equal(ModuleMakeVarNameMhs, ""),
|
|
MmakeRuleLibInstallHdrsNoMhs,
|
|
MmakeRuleLibInstallHdrsMhs),
|
|
|
|
ModuleMakeVarNameMihs =
|
|
string.format("$(%s.mihs)", [s(ModuleMakeVarName)]),
|
|
MmakeRuleLibInstallGradeHdrsNoMihs = mmake_simple_rule(
|
|
"install_grade_hdrs_no_mihs",
|
|
mmake_rule_is_phony,
|
|
LibInstallGradeHdrsTargetName,
|
|
[ModuleMakeVarNameMihs, "install_grade_dirs"],
|
|
[silent_noop_action]),
|
|
MmakeRuleLibInstallGradeHdrsMihs = mmake_simple_rule(
|
|
"install_grade_hdrs_mihs",
|
|
mmake_rule_is_phony,
|
|
LibInstallGradeHdrsTargetName,
|
|
[ModuleMakeVarNameMihs, "install_grade_dirs"],
|
|
["for hdr in " ++ ModuleMakeVarNameMihs ++ "; do \\",
|
|
"\t$(INSTALL) $$hdr $(INSTALL_INT_DIR); \\",
|
|
"\t$(INSTALL) $$hdr $(INSTALL_GRADE_INC_DIR); \\",
|
|
"done",
|
|
"# The following is needed to support the `--use-subdirs' option.",
|
|
"# We try using `$(LN_S)', but if that fails, then we just use",
|
|
"# `$(INSTALL)'.",
|
|
"rm -rf $(INSTALL_GRADE_INC_SUBDIR)",
|
|
"$(LN_S) .. $(INSTALL_GRADE_INC_SUBDIR) || { \\",
|
|
"\t{ [ -d $(INSTALL_GRADE_INC_SUBDIR) ] || \\",
|
|
"\t\t$(INSTALL_MKDIR) $(INSTALL_GRADE_INC_SUBDIR); \\",
|
|
"\t} && \\",
|
|
"\t$(INSTALL) $(INSTALL_GRADE_INC_DIR)/*.mih \\",
|
|
"\t\t$(INSTALL_GRADE_INC_SUBDIR); \\",
|
|
"} || exit 1",
|
|
"rm -rf $(INSTALL_INT_DIR)/Mercury/mihs",
|
|
"$(LN_S) .. $(INSTALL_INT_DIR)/Mercury/mihs || { \\",
|
|
"\t{ [ -d $(INSTALL_INT_DIR)/Mercury/mihs ] || \\",
|
|
"\t\t$(INSTALL_MKDIR) \\",
|
|
"\t\t$(INSTALL_INT_DIR)/Mercury/mihs; \\",
|
|
"\t} && \\",
|
|
"\t$(INSTALL) $(INSTALL_GRADE_INC_DIR)/*.mih \\",
|
|
"\t\t$(INSTALL_INT_DIR); \\",
|
|
"} || exit 1"]),
|
|
MmakeFragmentLibInstallGradeHdrs = mmf_conditional_entry(
|
|
mmake_cond_strings_equal(ModuleMakeVarNameMihs, ""),
|
|
MmakeRuleLibInstallGradeHdrsNoMihs,
|
|
MmakeRuleLibInstallGradeHdrsMihs),
|
|
|
|
add_mmake_entry(MmakeRuleLibInstallInts, !MmakeFile),
|
|
add_mmake_entry(MmakeRuleLibInstallOpts, !MmakeFile),
|
|
add_mmake_fragment(MmakeFragmentLibInstallHdrs, !MmakeFile),
|
|
add_mmake_fragment(MmakeFragmentLibInstallGradeHdrs, !MmakeFile).
|
|
|
|
:- pred generate_dep_file_collective_targets(globals::in,
|
|
module_name::in, string::in,
|
|
mmakefile::in, mmakefile::out, io::di, io::uo) is det.
|
|
|
|
generate_dep_file_collective_targets(Globals, ModuleName,
|
|
ModuleMakeVarName, !MmakeFile, !IO) :-
|
|
list.map_foldl(
|
|
generate_dep_file_collective_target(Globals, ModuleName,
|
|
ModuleMakeVarName),
|
|
[
|
|
ext_other(other_ext(".check")) - ".errs",
|
|
ext_other(other_ext(".ints")) - ".dates",
|
|
ext_other(other_ext(".int3s")) - ".date3s",
|
|
ext_other(other_ext(".opts")) - ".optdates",
|
|
ext_other(other_ext(".trans_opts")) - ".trans_opt_dates",
|
|
ext_other(other_ext(".javas")) - ".javas",
|
|
ext_other(other_ext(".classes")) - ".classes",
|
|
ext_other(other_ext(".all_ints")) - ".dates",
|
|
ext_other(other_ext(".all_int3s")) - ".date3s",
|
|
ext_other(other_ext(".all_opts")) - ".optdates",
|
|
ext_other(other_ext(".all_trans_opts")) - ".trans_opt_dates"
|
|
], MmakeRules, !IO),
|
|
add_mmake_entries(MmakeRules, !MmakeFile).
|
|
|
|
:- pred generate_dep_file_collective_target(globals::in,
|
|
module_name::in, string::in, pair(ext, string)::in,
|
|
mmake_entry::out, io::di, io::uo) is det.
|
|
|
|
generate_dep_file_collective_target(Globals, ModuleName, ModuleMakeVarName,
|
|
Ext - VarExtension, MmakeRule, !IO) :-
|
|
module_name_to_file_name(Globals, $pred, do_not_create_dirs, Ext,
|
|
ModuleName, TargetName, !IO),
|
|
Source = string.format("$(%s%s)", [s(ModuleMakeVarName), s(VarExtension)]),
|
|
ExtStr = extension_to_string(Ext),
|
|
MmakeRule = mmake_simple_rule(
|
|
"collective_target_" ++ ExtStr ++ VarExtension, mmake_rule_is_phony,
|
|
TargetName, [Source], []).
|
|
|
|
:- pred generate_dep_file_clean_targets(globals::in,
|
|
module_name::in, string::in, string::in, string::in,
|
|
string::in, string::in, string::in, string::in, string::in, string::in,
|
|
string::in, string::in,
|
|
mmakefile::in, mmakefile::out, io::di, io::uo) is det.
|
|
|
|
generate_dep_file_clean_targets(Globals, ModuleName, ModuleMakeVarName,
|
|
ExeFileName, InitCFileName, InitObjFileName, InitPicObjFileName,
|
|
InitFileName, LibFileName, SharedLibFileName, JarFileName,
|
|
DepFileName, DvFileName, !MmakeFile, !IO) :-
|
|
% If you change the clean targets below, please also update the
|
|
% documentation in doc/user_guide.texi.
|
|
|
|
module_name_to_file_name(Globals, $pred, do_not_create_dirs,
|
|
ext_other(other_ext(".clean")),
|
|
ModuleName, CleanTargetName, !IO),
|
|
module_name_to_file_name(Globals, $pred, do_not_create_dirs,
|
|
ext_other(other_ext(".realclean")),
|
|
ModuleName, RealCleanTargetName, !IO),
|
|
|
|
% XXX Put these into a logical order.
|
|
CleanSuffixes = [".dirs", ".cs", ".mihs", ".all_os", ".all_pic_os",
|
|
".c_dates", ".java_dates", ".useds", ".javas", ".profs",
|
|
".dep_errs", ".errs", ".foreign_cs"],
|
|
CleanFiles = [InitCFileName, InitObjFileName, InitPicObjFileName],
|
|
MmakeRulesClean =
|
|
% XXX Why is the first rule not phony?
|
|
[mmake_simple_rule("clean_local", mmake_rule_is_not_phony,
|
|
"clean_local", [CleanTargetName], []),
|
|
mmake_simple_rule("clean_target", mmake_rule_is_phony,
|
|
CleanTargetName,
|
|
[],
|
|
list.map(remove_suffix_files_cmd(ModuleMakeVarName),
|
|
CleanSuffixes) ++
|
|
[remove_files_cmd(CleanFiles)])],
|
|
|
|
% XXX We delete $(ModuleMakeVarName).all_int0s instead of
|
|
% $(ModuleMakeVarName).int0s to make sure that we delete
|
|
% any spurious .int0 files created for nested submodules.
|
|
% For further details, see the XXX comments above.
|
|
RealCleanSuffixes = [".dates", ".date0s", ".date3s",
|
|
".optdates", ".trans_opt_dates", ".ints", ".all_int0s", ".int3s",
|
|
".opts", ".trans_opts", ".analysiss", ".requests", ".imdgs",
|
|
".ds", ".module_deps", ".all_mhs", ".all_mihs", ".dlls",
|
|
".foreign_dlls", ".classes"],
|
|
RealCleanFiles = [ExeFileName ++ "$(EXT_FOR_EXE) ", InitFileName,
|
|
LibFileName, SharedLibFileName, JarFileName, DepFileName, DvFileName],
|
|
MmakeRulesRealClean =
|
|
% XXX Why is the first rule not phony?
|
|
[mmake_simple_rule("realclean_local", mmake_rule_is_not_phony,
|
|
"realclean_local", [RealCleanTargetName], []),
|
|
mmake_simple_rule("realclean_target", mmake_rule_is_phony,
|
|
RealCleanTargetName,
|
|
[CleanTargetName],
|
|
list.map(remove_suffix_files_cmd(ModuleMakeVarName),
|
|
RealCleanSuffixes) ++
|
|
[remove_files_cmd(RealCleanFiles)])],
|
|
|
|
add_mmake_entries(MmakeRulesClean ++ MmakeRulesRealClean, !MmakeFile).
|
|
|
|
% remove_suffix_files_cmd(ModuleMakeVarName, Extension):
|
|
%
|
|
% Return a command to delete the files in $(ModuleMakeVarNameExtension).
|
|
%
|
|
% XXX Xargs doesn't handle special characters in the file names correctly.
|
|
% This is currently not a problem in practice as we never generate
|
|
% file names containing special characters.
|
|
%
|
|
% Any fix for this problem will also require a fix in `mmake.in'.
|
|
%
|
|
:- func remove_suffix_files_cmd(string, string) = string.
|
|
|
|
remove_suffix_files_cmd(ModuleMakeVarName, Extension) =
|
|
string.format("-echo $(%s%s) | xargs rm -f",
|
|
[s(ModuleMakeVarName), s(Extension)]).
|
|
|
|
:- func remove_files_cmd(list(string)) = string.
|
|
|
|
remove_files_cmd(Files) =
|
|
"-rm -f " ++ string.join_list(" ", Files).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred get_source_file(deps_map::in, module_name::in, file_name::out) is det.
|
|
|
|
get_source_file(DepsMap, ModuleName, FileName) :-
|
|
map.lookup(DepsMap, ModuleName, Deps),
|
|
Deps = deps(_, BurdenedModule),
|
|
Baggage = BurdenedModule ^ bm_baggage,
|
|
SourceFileName = Baggage ^ mb_source_file_name,
|
|
( if string.remove_suffix(SourceFileName, ".m", SourceFileBase) then
|
|
FileName = SourceFileBase
|
|
else
|
|
unexpected($pred, "source file name doesn't end in `.m'")
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
output_module_order(Globals, ModuleName, Ext, DepsOrdering, !IO) :-
|
|
module_name_to_file_name(Globals, $pred, do_create_dirs,
|
|
ext_other(Ext), ModuleName, OrdFileName, !IO),
|
|
get_progress_output_stream(Globals, ModuleName, ProgressStream, !IO),
|
|
globals.lookup_bool_option(Globals, verbose, Verbose),
|
|
string.format("%% Creating module order file `%s'...",
|
|
[s(OrdFileName)], CreatingMsg),
|
|
maybe_write_string(ProgressStream, Verbose, CreatingMsg, !IO),
|
|
io.open_output(OrdFileName, OrdResult, !IO),
|
|
(
|
|
OrdResult = ok(OrdStream),
|
|
io.write_list(OrdStream, DepsOrdering, "\n\n",
|
|
write_module_scc(OrdStream), !IO),
|
|
io.close_output(OrdStream, !IO),
|
|
maybe_write_string(ProgressStream, Verbose, " done.\n", !IO)
|
|
;
|
|
OrdResult = error(IOError),
|
|
maybe_write_string(ProgressStream, Verbose, " failed.\n", !IO),
|
|
maybe_flush_output(ProgressStream, Verbose, !IO),
|
|
get_error_output_stream(Globals, ModuleName, ErrorStream, !IO),
|
|
io.error_message(IOError, IOErrorMessage),
|
|
string.format("error opening file `%s' for output: %s",
|
|
[s(OrdFileName), s(IOErrorMessage)], OrdMessage),
|
|
report_error(ErrorStream, OrdMessage, !IO)
|
|
).
|
|
|
|
:- pred write_module_scc(io.output_stream::in, set(module_name)::in,
|
|
io::di, io::uo) is det.
|
|
|
|
write_module_scc(Stream, SCC0, !IO) :-
|
|
set.to_sorted_list(SCC0, SCC),
|
|
% XXX This is suboptimal (the stream should be specified once, not twice),
|
|
% but in the absence of a test case, I (zs) am leaving it alone for now.
|
|
io.write_list(Stream, SCC, "\n", prog_out.write_sym_name(Stream), !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% get_both_opt_deps(Globals, BuildOptFiles, Deps, IntermodDirs,
|
|
% OptDeps, TransOptDeps, !Cache, !IO):
|
|
%
|
|
% For each dependency, search intermod_directories for a .m file.
|
|
% If it exists, add it to both output lists. Otherwise, if a .opt
|
|
% file exists, add it to the OptDeps list, and if a .trans_opt
|
|
% file exists, add it to the TransOptDeps list.
|
|
% If --use-opt-files is set, don't look for `.m' files, since we are
|
|
% not building `.opt' files, only using those which are available.
|
|
% XXX This won't find nested submodules.
|
|
% XXX Use `mmc --make' if that matters.
|
|
%
|
|
:- pred get_both_opt_deps(globals::in, bool::in, list(string)::in,
|
|
list(module_name)::in, list(module_name)::out, list(module_name)::out,
|
|
module_file_name_cache::in, module_file_name_cache::out,
|
|
io::di, io::uo) is det.
|
|
|
|
get_both_opt_deps(_, _, _, [], [], [], !Cache, !IO).
|
|
get_both_opt_deps(Globals, BuildOptFiles, IntermodDirs, [Dep | Deps],
|
|
!:OptDeps, !:TransOptDeps, !Cache, !IO) :-
|
|
get_both_opt_deps(Globals, BuildOptFiles, IntermodDirs, Deps,
|
|
!:OptDeps, !:TransOptDeps, !Cache, !IO),
|
|
(
|
|
BuildOptFiles = yes,
|
|
search_for_module_source(IntermodDirs, Dep, MaybeFileName, !IO),
|
|
(
|
|
MaybeFileName = ok(_),
|
|
!:OptDeps = [Dep | !.OptDeps],
|
|
!:TransOptDeps = [Dep | !.TransOptDeps],
|
|
Found = yes
|
|
;
|
|
MaybeFileName = error(_),
|
|
Found = no
|
|
)
|
|
;
|
|
BuildOptFiles = no,
|
|
Found = no
|
|
),
|
|
(
|
|
Found = no,
|
|
make_module_file_name(Globals, $pred,
|
|
ext_other(other_ext(".opt")), Dep, OptName, !Cache, !IO),
|
|
search_for_file_returning_dir(IntermodDirs, OptName, MaybeOptDir, !IO),
|
|
(
|
|
MaybeOptDir = ok(_),
|
|
!:OptDeps = [Dep | !.OptDeps]
|
|
;
|
|
MaybeOptDir = error(_)
|
|
),
|
|
make_module_file_name(Globals, $pred,
|
|
ext_other(other_ext(".trans_opt")), Dep, TransOptName,
|
|
!Cache, !IO),
|
|
search_for_file_returning_dir(IntermodDirs, TransOptName,
|
|
MaybeTransOptDir, !IO),
|
|
(
|
|
MaybeTransOptDir = ok(_),
|
|
!:TransOptDeps = [Dep | !.TransOptDeps]
|
|
;
|
|
MaybeTransOptDir = error(_)
|
|
)
|
|
;
|
|
Found = yes
|
|
).
|
|
|
|
get_opt_deps(_Globals, _BuildOptFiles, _IntermodDirs, _OtherExt, [], [], !IO).
|
|
get_opt_deps(Globals, BuildOptFiles, IntermodDirs, OtherExt, [Dep | Deps],
|
|
!:OptDeps, !IO) :-
|
|
get_opt_deps(Globals, BuildOptFiles, IntermodDirs, OtherExt, Deps,
|
|
!:OptDeps, !IO),
|
|
(
|
|
BuildOptFiles = yes,
|
|
search_for_module_source(IntermodDirs, Dep, Result1, !IO),
|
|
(
|
|
Result1 = ok(_),
|
|
!:OptDeps = [Dep | !.OptDeps],
|
|
Found = yes
|
|
;
|
|
Result1 = error(_),
|
|
Found = no
|
|
)
|
|
;
|
|
BuildOptFiles = no,
|
|
Found = no
|
|
),
|
|
(
|
|
Found = no,
|
|
module_name_to_search_file_name(Globals, $pred,
|
|
ext_other(OtherExt), Dep, OptName, !IO),
|
|
search_for_file(IntermodDirs, OptName, MaybeOptDir, !IO),
|
|
(
|
|
MaybeOptDir = ok(_),
|
|
!:OptDeps = [Dep | !.OptDeps]
|
|
;
|
|
MaybeOptDir = error(_)
|
|
)
|
|
;
|
|
Found = yes
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred compare_module_names(module_name::in, module_name::in,
|
|
comparison_result::out) is det.
|
|
|
|
compare_module_names(Sym1, Sym2, Result) :-
|
|
Str1 = sym_name_to_string(Sym1),
|
|
Str2 = sym_name_to_string(Sym2),
|
|
compare(Result, Str1, Str2).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module parse_tree.write_deps_file.
|
|
%---------------------------------------------------------------------------%
|