mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-19 03:13:40 +00:00
compiler/file_names.m:
Document the meaning of the maybe_create_dirs and maybe_search types.
Delete long-obsolete references to .il files.
compiler/make.util.m:
Rename make_remove_target_file to remove_make_target_file, since this
predicate removes target files in Makefiles, and does not "make" anything.
Rename several other predicates in a similar manner, for the same reason.
Add an extra argument to get_file_name and some related predicates
that will allow future conditionally-enabled trace goals in the compiler
to track where the requests for file name translations come from.
compiler/write_deps_file.m:
Factor out some code.
compiler/make.dependencies.m:
compiler/make.module_dep_file.m:
compiler/make.module_target.m:
compiler/make.program_target.m:
Conform to the changes above.
tools/file_name_translation_stats:
Allow for large numbers of file name translations.
2744 lines
120 KiB
Mathematica
2744 lines
120 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 2008-2011 The University of Melbourne.
|
|
% Copyright (C) 2013-2017, 2019-2023 The Mercury team.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% 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.parse_tree_out_sym_name.
|
|
:- 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.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),
|
|
BaseDeps = [ModuleName | set.to_sorted_list(LongDeps)],
|
|
( if
|
|
( TransOpt = yes
|
|
; UseTransOpt = yes
|
|
)
|
|
then
|
|
get_both_opt_deps(Globals, BuildOptFiles, IntermodDirs,
|
|
BaseDeps, OptDeps, TransOptDeps1, !Cache, !IO),
|
|
MaybeTransOptDeps1 = yes(TransOptDeps1)
|
|
else
|
|
get_opt_deps(Globals, BuildOptFiles, IntermodDirs,
|
|
other_ext(".opt"), BaseDeps, 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 occurred 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 accidentally 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
|
|
some [BurdenedModule] (
|
|
map.member(DepsMap, _, deps(_, BurdenedModule)),
|
|
ParseTreeModuleSrc = BurdenedModule ^ bm_module,
|
|
IncludeMap = ParseTreeModuleSrc ^ ptms_include_map,
|
|
not map.is_empty(IncludeMap)
|
|
)
|
|
then
|
|
% We always install `.int0' files; see the comment in the body of
|
|
% make.program_target.install_ints_and_headers/8 for the reason why.
|
|
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.text_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", 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.
|
|
%---------------------------------------------------------------------------%
|