[m-rev.] for review: mmc --make [3]
Simon Taylor
stayl at cs.mu.OZ.AU
Wed Feb 6 02:20:58 AEDT 2002
Index: compiler/compile_target_code.m
===================================================================
RCS file: compiler/compile_target_code.m
diff -N compiler/compile_target_code.m
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ compiler/compile_target_code.m 24 Jan 2002 17:31:23 -0000
@@ -0,0 +1,125 @@
+%-----------------------------------------------------------------------------%
+% Copyright (C) 2002 University of Melbourne.
+% This file may only be copied under the terms of the GNU General
+% Public License - see the file COPYING in the Mercury distribution.
+%-----------------------------------------------------------------------------%
+% File: compile_target_code.m
+% Main authors: stayl
+%
+% Code to compile the generated `.c', `.s', `.o', etc, files.
+%
+% XXX Code will be moved here from mercury_compile.m after the `mmc --make'
+% change has been reviewed.
+%-----------------------------------------------------------------------------%
+:- module compile_target_code.
+
+:- interface.
+
+:- import_module prog_data.
+:- import_module bool, io, std_util.
+
+ % Write the number of `.c' files written by this
+ % compilation with `--split-c-files'.
+:- pred write_num_split_c_files(module_name, int, bool, io__state, io__state).
+:- mode write_num_split_c_files(in, in, out, di, uo) is det.
+
+ % Find the number of `.c' files written by a previous
+ % compilation with `--split-c-files'.
+:- pred read_num_split_c_files(module_name, maybe_error(int),
+ io__state, io__state).
+:- mode read_num_split_c_files(in, out, di, uo) is det.
+
+ % remove_split_c_output_files(ModuleName, NumChunks).
+ %
+ % Remove the `.c' and `.o' files written by a previous
+ % compilation with `--split-c-files'.
+:- pred remove_split_c_output_files(module_name, int, io__state, io__state).
+:- mode remove_split_c_output_files(in, in, di, uo) is det.
+
+%-----------------------------------------------------------------------------%
+:- implementation.
+
+:- import_module modules, globals, options.
+:- import_module int, string.
+
+write_num_split_c_files(ModuleName, NumChunks, Succeeded) -->
+ module_name_to_file_name(ModuleName, ".num_split", yes,
+ NumChunksFileName),
+ io__open_output(NumChunksFileName, Res),
+ ( { Res = ok(OutputStream) } ->
+ io__write_int(OutputStream, NumChunks),
+ io__nl(OutputStream),
+ io__close_output(OutputStream),
+ { Succeeded = yes }
+ ;
+ { Succeeded = no },
+ io__progname_base("mercury_compile", ProgName),
+ io__write_string("\n"),
+ io__write_string(ProgName),
+ io__write_string(": can't open `"),
+ io__write_string(NumChunksFileName),
+ io__write_string("' for output\n"),
+ io__set_exit_status(1)
+ ).
+
+read_num_split_c_files(ModuleName, MaybeNumChunks) -->
+ module_name_to_file_name(ModuleName, ".num_split", no,
+ NumChunksFileName),
+ io__open_input(NumChunksFileName, Res),
+ (
+ { Res = ok(FileStream) },
+ io__read_word(FileStream, MaybeNumChunksString),
+ io__close_input(FileStream),
+ (
+ { MaybeNumChunksString = ok(NumChunksString) },
+ (
+ { string__to_int(
+ string__from_char_list(NumChunksString),
+ NumChunks) }
+ ->
+ { MaybeNumChunks = ok(NumChunks) }
+ ;
+ { MaybeNumChunks = error(
+ "Software error: error in `"
+ ++ NumChunksFileName
+ ++ "': expected single int.\n") }
+ )
+ ;
+ { MaybeNumChunksString = eof },
+ { MaybeNumChunks = error(
+ "Software error: error in `"
+ ++ NumChunksFileName
+ ++ "': expected single int.\n") }
+ ;
+ { MaybeNumChunksString = error(_) },
+ { MaybeNumChunks = error(
+ "Software error: error in `"
+ ++ NumChunksFileName
+ ++ "': expected single int.\n") }
+ )
+ ;
+ { Res = error(Error) },
+ { MaybeNumChunks = error(io__error_message(Error)) }
+ ).
+
+remove_split_c_output_files(ModuleName, NumChunks) -->
+ remove_split_c_output_files(ModuleName, 0, NumChunks).
+
+:- pred remove_split_c_output_files(module_name, int, int,
+ io__state, io__state).
+:- mode remove_split_c_output_files(in,in, in, di, uo) is det.
+
+remove_split_c_output_files(ModuleName, ThisChunk, NumChunks) -->
+ ( { ThisChunk =< NumChunks } ->
+ globals__io_lookup_string_option(object_file_extension, Obj),
+ module_name_to_split_c_file_name(ModuleName, ThisChunk,
+ ".c", CFileName),
+ module_name_to_split_c_file_name(ModuleName, ThisChunk,
+ Obj, ObjFileName),
+ io__remove_file(CFileName, _),
+ io__remove_file(ObjFileName, _),
+ remove_split_c_output_files(ModuleName, ThisChunk, NumChunks)
+ ;
+ []
+ ).
+
Index: compiler/make.m
===================================================================
RCS file: compiler/make.m
diff -N compiler/make.m
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ compiler/make.m 3 Feb 2002 15:26:47 -0000
@@ -0,0 +1,378 @@
+%-----------------------------------------------------------------------------%
+% Copyright (C) 2002 The University of Melbourne.
+% This file may only be copied under the terms of the GNU General
+% Public License - see the file COPYING in the Mercury distribution.
+%-----------------------------------------------------------------------------%
+% File: make.m
+% Main author: stayl
+%
+% A builtin Mercury-specific make replacement.
+%
+% TODO:
+% - `--split-c-files'
+% - fix `--target il'
+% - check commands for compilation of foreign code files
+% in mercury_compile.m
+% - fix handling of the `.exe' file
+% - library installation
+% - transitive inter-module optimization (probably won't bother since
+% that is being rewritten anyway)
+% - parallel/distributed builds
+%
+%-----------------------------------------------------------------------------%
+:- module make.
+
+:- interface.
+
+:- import_module modules, options_file, prog_io.
+:- import_module io, list.
+
+ % make__process_args(OptionArgs, NonOptionArgs).
+:- pred make__process_args(list(string)::in, list(file_name)::in,
+ io__state::di, io__state::uo) is det.
+
+:- pred make__write_module_dep_file(module_imports::in,
+ io__state::di, io__state::uo) is det.
+
+:- func make__module_dep_file_extension = string.
+
+%-----------------------------------------------------------------------------%
+:- implementation.
+
+:- include_module make__dependencies, make__module_dep_file.
+:- include_module make__module_target, make__program_target, make__util.
+
+:- import_module make__dependencies, make__module_dep_file.
+:- import_module make__module_target, make__program_target, make__util.
+
+:- import_module globals, options, handle_options, modules.
+:- import_module prog_data, foreign, mercury_compile, mercury_to_mercury.
+:- import_module prog_io, prog_out, prog_io_util, timestamp.
+
+:- import_module assoc_list, bool, char, dir, exception, getopt, int, list.
+:- import_module map, parser, require, set, std_util, string, term, term_io.
+
+:- type make_info
+ ---> make_info(
+ % The items field of each module_imports
+ % structure should be empty -- we're not
+ % trying to cache the items here.
+ module_dependencies :: map(module_name, maybe(module_imports)),
+
+ file_timestamps :: file_timestamps,
+
+ % The original set of options passed to mmc,
+ % not including the targets to be made.
+ option_args :: list(string),
+
+ % The contents of the Mercury.options file.
+ options_variables :: options_variables,
+
+ dependency_status :: map(dependency_file, dependency_status),
+
+ % For each module, the set of modules for
+ % which the `.int' files are read, excluding
+ % those read as a result of reading `.opt' files.
+ % The bool records whether there was an error
+ % in the dependencies.
+ % XXX Use a better representation for the sets.
+ cached_direct_imports :: cached_direct_imports,
+
+ % The boolean is `yes' if the result is complete.
+ % XXX Use a better representation for the sets.
+ cached_transitive_dependencies ::
+ cached_transitive_dependencies,
+
+ % Should the `.module_dep' files be rebuilt.
+ % Set to `no' for `mmc --make clean'.
+ rebuild_dependencies :: bool,
+
+ keep_going :: bool,
+
+ % Modules for which we have redirected output
+ % to a `.err' file during this invocation of mmc.
+ error_file_modules :: set(module_name)
+ ).
+
+:- type make_error
+ ---> target_error(target_file)
+ ; dependencies_error(module_name)
+ ; other(string)
+ .
+
+:- type compilation_task == pair(compilation_task_type, module_name).
+
+:- type compilation_task_type
+ ---> process_module(module_compilation_task_type)
+ ; target_code_to_object_code
+ .
+
+:- type module_compilation_task_type
+ ---> errorcheck
+ ; make_short_interface
+ ; make_interface
+ ; make_private_interface
+ ; make_optimization_interface
+ ; make_transitive_optimization_interface
+ ; compile_to_target_code
+ .
+
+:- type module_target_type
+ ---> source
+ ; errors
+ ; private_interface
+ ; long_interface
+ ; short_interface
+ ; unqualified_short_interface
+ ; intermodule_interface
+ ; aditi_code
+ ; c_header
+ ; c_code
+ ; il_code
+ ; il_asm
+ ; java_code
+ ; asm_code(pic)
+ ; object_code(pic)
+ .
+
+ % Are we generating position indepedent code (for use in a
+ % shared library)? On some architectures, pic and non-pic
+ % code is incompatible, so we need to generate `.o' and `.pic_o'
+ % files.
+:- type pic
+ ---> pic
+ ; non_pic
+ .
+
+% :- type linked_target_type in mercury_compile.m.
+
+:- type misc_target_type
+ ---> clean
+ ; realclean
+ ; check
+ ; install_library
+ .
+
+:- type file_timestamps == map(string, maybe_error(timestamp)).
+
+:- type dependency_status
+ ---> not_considered
+ ; being_built
+ ; up_to_date
+ ; error
+ .
+
+:- type target_file == pair(module_name, module_target_type).
+:- type linked_target_file == pair(module_name, linked_target_type).
+
+%-----------------------------------------------------------------------------%
+
+make__write_module_dep_file(Imports) -->
+ make__module_dep_file__write_module_dep_file(Imports).
+
+make__module_dep_file_extension = ".module_dep".
+
+make__process_args(OptionArgs, Targets0) -->
+ read_options_files(MaybeVariables),
+ (
+ { MaybeVariables = yes(Variables) },
+ % Look up the MCFLAGS and GRADEFLAGS from the options file.
+ lookup_mmc_options(Variables, MaybeMCFlags),
+ (
+ { MaybeMCFlags = yes(MCFlags) },
+ handle_options(MCFlags ++ OptionArgs, MaybeError,
+ _, _, _),
+ (
+ { MaybeError = yes(OptionsError) },
+ usage_error(OptionsError),
+ { Continue0 = no }
+ ;
+ { MaybeError = no },
+ { Continue0 = yes }
+ )
+ ;
+ { MaybeMCFlags = no },
+ { Continue0 = no }
+ )
+ ;
+ { MaybeVariables = no },
+ { Variables = options_variables_init },
+ { Continue0 = no }
+ ),
+ (
+ { Continue0 = yes },
+ { Targets0 = [] }
+ ->
+ lookup_main_target(Variables, MaybeMAIN_TARGET),
+ (
+ { MaybeMAIN_TARGET = yes(Targets) },
+ (
+ { Targets = [_ | _] },
+ { Continue = yes }
+ ;
+ { Targets = [] },
+ { Continue = no },
+ io__write_string(
+ "** Error: no targets specified and `MAIN_TARGET' not defined.\n")
+ )
+ ;
+ { MaybeMAIN_TARGET = no },
+ { Targets = [] },
+ { Continue = no }
+ )
+ ;
+ { Continue = Continue0 },
+ { Targets = Targets0 }
+ ),
+ ( { Continue = no } ->
+ io__set_exit_status(1)
+ ;
+ { ShouldRebuildDeps = yes },
+ globals__io_lookup_bool_option(keep_going, KeepGoing),
+ { MakeInfo0 = make_info(map__init, map__init,
+ OptionArgs, Variables, map__init,
+ init_cached_direct_imports,
+ init_cached_transitive_dependencies,
+ ShouldRebuildDeps, KeepGoing, set__init) },
+
+ globals__io_get_globals(Globals),
+ foldl2_maybe_stop_at_error(KeepGoing,
+ (pred(TargetStr::in, Success0::out,
+ Info0::in, Info::out, di, uo) is det -->
+ (
+ { target_file(Globals, TargetStr,
+ ModuleName, TargetType) }
+ ->
+ (
+ { TargetType = module_target(ModuleTargetType) },
+ make_module_target(
+ target(ModuleName - ModuleTargetType),
+ Success0, Info0, Info)
+ ;
+ { TargetType = linked_target(ProgramTargetType) },
+ make_linked_target(
+ ModuleName - ProgramTargetType, Success0,
+ Info0, Info)
+ ;
+ { TargetType = misc_target(MiscTargetType) },
+ make_misc_target(ModuleName - MiscTargetType,
+ Success0, Info0, Info)
+ )
+ ;
+ % Accept and ignore `.depend' targets.
+ % `mmc --make' does not need a separate
+ % make depend step. The dependencies for
+ % each module are regenerated on demand.
+ { string__length(TargetStr, NameLength) },
+ { search_backwards_for_dot(TargetStr,
+ NameLength - 1, DotLocn) },
+ { string__split(TargetStr, DotLocn, _, ".depend") }
+ ->
+ { Success0 = yes },
+ { Info = Info0 }
+ ;
+ { Info = Info0 },
+ { Success0 = no },
+ io__write_string("** Unknown target: "),
+ io__write_string(TargetStr),
+ io__write_string(".\n")
+ )
+ ), Targets, Success, MakeInfo0, _MakeInfo),
+
+ ( { Success = no } ->
+ io__set_exit_status(1)
+ ;
+ []
+ )
+ ).
+
+%-----------------------------------------------------------------------------%
+
+:- type target_type
+ ---> module_target(module_target_type)
+ ; linked_target(linked_target_type)
+ ; misc_target(misc_target_type)
+ .
+
+:- pred target_file(globals::in, string::in,
+ module_name::out, target_type::out) is semidet.
+
+target_file(Globals, FileName, ModuleName, TargetType) :-
+ (
+ string__length(FileName, NameLength),
+ search_backwards_for_dot(FileName, NameLength - 1, DotLocn),
+ string__split(FileName, DotLocn, ModuleNameStr0, Suffix),
+ solutions(
+ (pred(TargetFile0::out) is nondet :-
+ (
+ Suffix = target_extension(Globals,
+ ModuleTargetType)
+ ->
+ ModuleNameStr = ModuleNameStr0,
+ TargetType0 = module_target(ModuleTargetType)
+ ;
+ globals__lookup_string_option(Globals,
+ library_extension, Suffix),
+ string__append("lib", ModuleNameStr1, ModuleNameStr0)
+ ->
+ ModuleNameStr = ModuleNameStr1,
+ TargetType0 = linked_target(static_library)
+ ;
+ globals__lookup_string_option(Globals,
+ shared_library_extension, Suffix),
+ string__append("lib", ModuleNameStr1, ModuleNameStr0)
+ ->
+ ModuleNameStr = ModuleNameStr1,
+ TargetType0 = linked_target(shared_library)
+ ;
+ globals__lookup_string_option(Globals,
+ executable_file_extension, Suffix)
+ ->
+ ModuleNameStr = ModuleNameStr0,
+ TargetType0 = linked_target(executable)
+ ;
+ Suffix = ".check"
+ ->
+ ModuleNameStr = ModuleNameStr0,
+ TargetType0 = misc_target(check)
+ ;
+ Suffix = ".clean"
+ ->
+ ModuleNameStr = ModuleNameStr0,
+ TargetType0 = misc_target(clean)
+ ;
+ Suffix = ".realclean"
+ ->
+ ModuleNameStr = ModuleNameStr0,
+ TargetType0 = misc_target(realclean)
+ ;
+ Suffix = ".install"
+ ->
+ ModuleNameStr = ModuleNameStr0,
+ TargetType0 = misc_target(install_library)
+ ;
+ fail
+ ),
+ file_name_to_module_name(ModuleNameStr, ModuleName0),
+ TargetFile0 = ModuleName0 - TargetType0
+ ), TargetFiles),
+ TargetFiles = [TargetFile]
+ ->
+ TargetFile = ModuleName - TargetType
+ ;
+ globals__lookup_string_option(Globals, executable_file_extension, ""),
+ TargetType = linked_target(executable),
+ file_name_to_module_name(FileName, ModuleName)
+ ).
+
+:- pred search_backwards_for_dot(string::in, int::in, int::out) is semidet.
+
+search_backwards_for_dot(String, Index, DotIndex) :-
+ Index >= 0,
+ ( string__index_det(String, Index, '.') ->
+ DotIndex = Index
+ ;
+ search_backwards_for_dot(String, Index - 1, DotIndex)
+ ).
+
+%-----------------------------------------------------------------------------%
Index: compiler/make.dependencies.m
===================================================================
RCS file: compiler/make.dependencies.m
diff -N compiler/make.dependencies.m
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ compiler/make.dependencies.m 21 Jan 2002 06:21:20 -0000
@@ -0,0 +1,844 @@
+%-----------------------------------------------------------------------------%
+% Copyright (C) 2002 The University of Melbourne.
+% This file may only be copied under the terms of the GNU General
+% Public License - see the file COPYING in the Mercury distribution.
+%-----------------------------------------------------------------------------%
+% File: make.dependencies.m
+% Author: stayl
+%
+% Code to find the dependencies for a particular target,
+% e.g. module.c depends on module.m, import.int, etc.
+%-----------------------------------------------------------------------------%
+:- module make__dependencies.
+
+:- interface.
+
+ % find_module_deps(ModuleName, Succeeded, Deps, Info0, Info).
+ %
+ % The reason we don't return maybe(Deps) is that with `--keep-going'
+ % we want to do as much work as possible.
+:- type find_module_deps(T) ==
+ pred(module_name, bool, set(T),
+ make_info, make_info, io__state, io__state).
+:- inst find_module_deps ==
+ (pred(in, out, out, in, out, di, uo) is det).
+
+:- type dependency_file
+ ---> target(target_file) % A target which could be made.
+ ; file(file_name, maybe(option)) % An ordinary file which
+ % `mmc --make' does not know
+ % how to rebuild. The option
+ % gives a list of directories
+ % in which to search.
+ .
+
+ % Return a closure which will find the dependencies for
+ % a target type given a module name.
+:- func target_dependencies(globals, module_target_type) =
+ find_module_deps(dependency_file).
+:- mode target_dependencies(in, in) = out(find_module_deps) is det.
+
+ % Union the output set of dependencies for a given module
+ % with the accumulated set. This is used with
+ % foldl3_maybe_stop_at_error to iterate over a list of
+ % module_names to find all target files for those modules.
+:- pred union_deps(find_module_deps(T)::in(find_module_deps),
+ module_name::in, bool::out, set(T)::in, set(T)::out,
+ make_info::in, make_info::out, io__state::di, io__state::uo) is det.
+
+%-----------------------------------------------------------------------------%
+
+ % Find all modules in the current directory which are
+ % reachable (by import) from the given module.
+:- pred find_reachable_local_modules(module_name::in, bool::out,
+ set(module_name)::out, make_info::in, make_info::out,
+ io__state::di, io__state::uo) is det.
+
+%-----------------------------------------------------------------------------%
+
+:- pred dependency_status(dependency_file::in, dependency_status::out,
+ make_info::in, make_info::out, io__state::di, io__state::uo) is det.
+
+%-----------------------------------------------------------------------------%
+
+:- type dependencies_result
+ ---> up_to_date
+ ; out_of_date
+ ; error
+ .
+
+ % Check that all the dependency targets are up-to-date.
+:- pred check_dependencies(string::in, maybe_error(timestamp)::in,
+ list(dependency_file)::in, dependencies_result::out,
+ make_info::in, make_info::out, io__state::di, io__state::uo) is det.
+
+ % Check that all the dependency files are up-to-date.
+:- pred check_dependency_timestamps(string::in,
+ maybe_error(timestamp)::in, list(File)::in,
+ pred(File, io__state, io__state)::(pred(in, di, uo) is det),
+ list(maybe_error(timestamp))::in, dependencies_result::out,
+ io__state::di, io__state::uo) is det.
+
+%-----------------------------------------------------------------------------%
+
+:- type cached_direct_imports.
+:- func init_cached_direct_imports = cached_direct_imports.
+
+:- type cached_transitive_dependencies.
+:- func init_cached_transitive_dependencies = cached_transitive_dependencies.
+
+%-----------------------------------------------------------------------------%
+:- implementation.
+
+:- type deps_result(T) == pair(bool, set(T)).
+:- type module_deps_result == deps_result(module_name).
+
+union_deps(FindDeps, ModuleName, Success, Deps0,
+ set__union(Deps0, Deps), Info0, Info) -->
+ FindDeps(ModuleName, Success, Deps, Info0, Info).
+
+ % Note that we go to some effort in this module to stop
+ % dependency calculation as soon as possible if there
+ % are errors. This is important because the calls to
+ % get_module_dependencies from the dependency calculation
+ % predicates can result in every module in the program being
+ % read.
+:- func combine_deps(find_module_deps(T), find_module_deps(T)) =
+ find_module_deps(T).
+:- mode combine_deps(in(find_module_deps), in(find_module_deps)) =
+ out(find_module_deps) is det.
+
+combine_deps(FindDeps1, FindDeps2) =
+ (pred(ModuleName::in, Success::out, Deps::out,
+ Info0::in, Info::out, di, uo) is det -->
+ FindDeps1(ModuleName, Success1, Deps1, Info0, Info1),
+ ( { Success1 = no, Info1 ^ keep_going = no } ->
+ { Info = Info1 },
+ { Success = no },
+ { Deps = Deps1 }
+ ;
+ FindDeps2(ModuleName, Success2, Deps2, Info1, Info),
+ { Success = Success1 `and` Success2 },
+ { Deps = set__union(Deps1, Deps2) }
+ )
+ ).
+
+:- func combine_deps_list(list(find_module_deps(T))) =
+ find_module_deps(T).
+:- mode combine_deps_list(in(list_skel(find_module_deps))) =
+ out(find_module_deps) is det.
+
+combine_deps_list([]) = no_deps.
+combine_deps_list([FindDeps | FindDepsList]) =
+ ( FindDepsList = [] ->
+ FindDeps
+ ;
+ combine_deps(FindDeps, combine_deps_list(FindDepsList))
+ ).
+
+target_dependencies(_, source) = no_deps.
+target_dependencies(Globals, errors) = compiled_code_dependencies(Globals).
+target_dependencies(_, private_interface) = interface_file_dependencies.
+target_dependencies(_, long_interface) = interface_file_dependencies.
+target_dependencies(_, short_interface) = interface_file_dependencies.
+target_dependencies(_, unqualified_short_interface) = source `of` self.
+target_dependencies(Globals, aditi_code) = compiled_code_dependencies(Globals).
+target_dependencies(Globals, c_header) = target_dependencies(Globals, c_code).
+target_dependencies(Globals, c_code) = compiled_code_dependencies(Globals).
+target_dependencies(Globals, il_code) = compiled_code_dependencies(Globals).
+target_dependencies(_, il_asm) = il_code `of` self.
+target_dependencies(Globals, java_code) = compiled_code_dependencies(Globals).
+target_dependencies(Globals, asm_code(_)) =
+ compiled_code_dependencies(Globals).
+target_dependencies(Globals, object_code(PIC)) = Deps :-
+ globals__get_target(Globals, CompilationTarget),
+ TargetCode = ( CompilationTarget = asm -> asm_code(PIC) ; c_code ),
+ globals__lookup_bool_option(Globals, highlevel_code, HighLevelCode),
+
+ %
+ % For --highlevel-code, the `.c' file will #include the header
+ % file for all imported modules.
+ %
+ HeaderDeps =
+ ( CompilationTarget = c, HighLevelCode = yes ->
+ combine_deps_list([
+ c_header `of` direct_imports,
+ c_header `of` indirect_imports,
+ c_header `of` parents,
+ c_header `of` intermod_imports,
+ c_header `of` foreign_imports
+ ])
+ ;
+ no_deps
+ ),
+ Deps = combine_deps_list([
+ TargetCode `of` self,
+ c_header `of` foreign_imports,
+ HeaderDeps
+ ]).
+target_dependencies(_, intermodule_interface) =
+ combine_deps_list([
+ source `of` self,
+ private_interface `of` parents,
+ long_interface `of` non_intermod_direct_imports,
+ short_interface `of` non_intermod_indirect_imports
+ ]).
+
+:- func interface_file_dependencies =
+ (find_module_deps(dependency_file)::out(find_module_deps)) is det.
+
+interface_file_dependencies =
+ combine_deps_list([
+ source `of` self,
+ private_interface `of` parents,
+ unqualified_short_interface `of` direct_imports,
+ unqualified_short_interface `of` indirect_imports
+ ]).
+
+:- func compiled_code_dependencies(globals::in) =
+ (find_module_deps(dependency_file)::out(find_module_deps)) is det.
+
+compiled_code_dependencies(Globals) = Deps :-
+ globals__lookup_bool_option(Globals,
+ intermodule_optimization, Intermod),
+ ( Intermod = yes ->
+ % XXX Handle inter-module optimization
+ % with sub-modules properly. Currently
+ % inter-module optimization is pretty much
+ % disabled in the presence of sub-modules.
+ % We need to read the `.int0' files for the parents
+ % of all modules for which we read `.opt' files.
+ Deps = combine_deps_list([
+ intermodule_interface `of` self,
+ intermodule_interface `of` intermod_imports,
+ compiled_code_dependencies
+ ])
+ ;
+ Deps = compiled_code_dependencies
+ ).
+
+:- func compiled_code_dependencies =
+ (find_module_deps(dependency_file)::out(find_module_deps)) is det.
+
+compiled_code_dependencies =
+ combine_deps_list([
+ source `of` self,
+ fact_table `files_of` self,
+ private_interface `of` parents,
+ long_interface `of` direct_imports,
+ short_interface `of` indirect_imports
+ ]).
+
+:- func module_target_type `of` find_module_deps(module_name) =
+ find_module_deps(dependency_file).
+:- mode in `of` in(find_module_deps) = out(find_module_deps) is det.
+
+FileType `of` FindDeps =
+ (pred(ModuleName::in, Success::out, TargetFiles::out,
+ Info0::in, Info::out, di, uo) is det -->
+ FindDeps(ModuleName, Success, ModuleNames, Info0, Info),
+ { TargetFiles = set__sorted_list_to_set(
+ make_dependency_list(set__to_sorted_list(ModuleNames),
+ FileType)) }
+ ).
+
+:- func find_module_deps(pair(file_name, maybe(option))) `files_of`
+ find_module_deps(module_name) =
+ find_module_deps(dependency_file).
+:- mode in(find_module_deps) `files_of` in(find_module_deps)
+ = out(find_module_deps) is det.
+
+FindFiles `files_of` FindDeps =
+ (pred(ModuleName::in, Success::out, DepFiles::out,
+ Info0::in, Info::out, di, uo) is det -->
+ { KeepGoing = Info0 ^ keep_going },
+
+ FindDeps(ModuleName, Success0, ModuleNames, Info0, Info1),
+ ( { Success0 = no, KeepGoing = no } ->
+ { Success = no },
+ { Info = Info1 },
+ { DepFiles = set__init }
+ ;
+ foldl3_maybe_stop_at_error(KeepGoing,
+ union_deps(FindFiles),
+ set__to_sorted_list(ModuleNames),
+ Success1, set__init, FileNames, Info1, Info),
+ { Success = Success0 `and` Success1 },
+ { DepFiles = set__sorted_list_to_set(
+ list__map(
+ (func(FileName - Option) = file(FileName, Option)),
+ set__to_sorted_list(FileNames))) }
+ )
+ ).
+
+:- pred no_deps(module_name::in, bool::out, set(T)::out,
+ make_info::in, make_info::out, io__state::di, io__state::uo) is det.
+
+no_deps(_, yes, set__init, Info, Info) --> [].
+
+:- pred self(module_name::in, bool::out, set(module_name)::out,
+ make_info::in, make_info::out, io__state::di, io__state::uo) is det.
+
+self(ModuleName, yes, set__make_singleton_set(ModuleName), Info, Info) --> [].
+
+:- pred parents(module_name::in, bool::out, set(module_name)::out,
+ make_info::in, make_info::out, io__state::di, io__state::uo) is det.
+
+parents(ModuleName, yes, set__list_to_set(Ancestors), Info, Info) -->
+ { get_ancestors(ModuleName, Ancestors) }.
+
+%-----------------------------------------------------------------------------%
+
+:- type cached_direct_imports == map(module_name, module_deps_result).
+
+init_cached_direct_imports = map__init.
+
+:- pred direct_imports(module_name::in, bool::out, set(module_name)::out,
+ make_info::in, make_info::out, io__state::di, io__state::uo) is det.
+
+direct_imports(ModuleName, Success, Modules, Info0, Info) -->
+ ( { Result0 = Info0 ^ cached_direct_imports ^ elem(ModuleName) } ->
+ { Result0 = Success - Modules },
+ { Info = Info0 }
+ ;
+ { KeepGoing = Info0 ^ keep_going },
+
+ non_intermod_direct_imports(ModuleName, Success0,
+ Modules0, Info0, Info1),
+ ( { Success0 = no, KeepGoing = no } ->
+ { Info3 = Info1 },
+ { Success = no },
+ { Modules = set__init }
+ ;
+ %
+ % We also read `.int' files for modules imported
+ % by `.opt' files.
+ %
+ intermod_imports(ModuleName, Success1,
+ IntermodModules, Info1, Info2),
+ ( { Success1 = no, KeepGoing = no } ->
+ { Info3 = Info2 },
+ { Success = no },
+ { Modules = set__init }
+ ;
+ foldl3_maybe_stop_at_error(Info2 ^ keep_going,
+ union_deps(non_intermod_direct_imports),
+ set__to_sorted_list(IntermodModules), Success2,
+ Modules0, Modules1, Info2, Info3),
+ { Success = Success0 `and` Success1 `and` Success2 },
+ { Modules = set__delete(Modules1, ModuleName) }
+ )
+ ),
+ { Info = Info3 ^ cached_direct_imports
+ ^ elem(ModuleName) := Success - Modules }
+ ).
+
+ % Return the modules for which `.int' files are read in a compilation
+ % which does not use `--intermodule-optimization'.
+:- pred non_intermod_direct_imports(module_name::in, bool::out,
+ set(module_name)::out, make_info::in, make_info::out,
+ io__state::di, io__state::uo) is det.
+
+non_intermod_direct_imports(ModuleName, Success, Modules, Info0, Info) -->
+ get_module_dependencies(ModuleName, MaybeImports, Info0, Info1),
+ (
+ { MaybeImports = yes(Imports) },
+
+ %
+ % Find the direct imports of this module (modules
+ % for which we will read the `.int' files).
+ %
+ % Note that we need to do this both for the interface
+ % imports of this module and for the *implementation*
+ % imports of its ancestors. This is because if this
+ % module is defined in the implementation section of
+ % its parent, then the interface of this module may
+ % depend on things imported only by its parent's
+ % implementation.
+ %
+ % If this module was actually defined in the interface
+ % section of one of its ancestors, then it should only
+ % depend on the interface imports of that ancestor,
+ % so the dependencies added here are in fact more
+ % conservative than they need to be in that case.
+ % However, that should not be a major problem.
+ % (This duplicates how this is handled by modules.m).
+ %
+ { Modules0 = set__union(set__list_to_set(Imports ^ impl_deps),
+ set__list_to_set(Imports ^ int_deps)) },
+ ( { ModuleName = qualified(ParentModule, _) } ->
+ non_intermod_direct_imports(ParentModule, Success,
+ ParentImports, Info1, Info),
+ { Modules = set__union(ParentImports, Modules0) }
+ ;
+ { Success = yes },
+ { Modules = Modules0 },
+ { Info = Info1 }
+ )
+ ;
+ { MaybeImports = no },
+ { Success = no },
+ { Modules = set__init },
+ { Info = Info1 }
+ ).
+
+%-----------------------------------------------------------------------------%
+
+ % Return the list of modules for which we should read `.int2' files.
+:- pred indirect_imports(module_name::in, bool::out, set(module_name)::out,
+ make_info::in, make_info::out, io__state::di, io__state::uo) is det.
+
+indirect_imports(ModuleName, Success, Modules, Info0, Info) -->
+ indirect_imports_2(direct_imports, ModuleName,
+ Success, Modules, Info0, Info).
+
+ % Return the list of modules for which we should read `.int2' files,
+ % ignoring those which need to be read as a result of importing
+ % modules imported by a `.opt' file.
+:- pred non_intermod_indirect_imports(module_name::in, bool::out,
+ set(module_name)::out, make_info::in, make_info::out,
+ io__state::di, io__state::uo) is det.
+
+non_intermod_indirect_imports(ModuleName, Success, Modules, Info0, Info) -->
+ indirect_imports_2(non_intermod_direct_imports, ModuleName,
+ Success, Modules, Info0, Info).
+
+:- pred indirect_imports_2(find_module_deps(module_name)::in(find_module_deps),
+ module_name::in, bool::out, set(module_name)::out,
+ make_info::in, make_info::out, io__state::di, io__state::uo) is det.
+
+indirect_imports_2(FindDirectImports, ModuleName, Success, IndirectImports,
+ Info0, Info) -->
+ { KeepGoing = Info1 ^ keep_going },
+
+ FindDirectImports(ModuleName, DirectSuccess,
+ DirectImports, Info0, Info1),
+ ( { DirectSuccess = no, KeepGoing = no } ->
+ { Success = no },
+ { IndirectImports = set__init },
+ { Info = Info1 }
+ ;
+ foldl3_maybe_stop_at_error(Info1 ^ keep_going,
+ union_deps(find_transitive_interface_imports),
+ set__to_sorted_list(DirectImports), IndirectSuccess,
+ set__init, IndirectImports0, Info1, Info),
+ { IndirectImports = set__difference(
+ set__delete(IndirectImports0, ModuleName),
+ DirectImports) },
+ { Success = DirectSuccess `and` IndirectSuccess }
+ ).
+
+%-----------------------------------------------------------------------------%
+
+ % Return the list of modules for which we should read `.opt' files.
+:- pred intermod_imports(module_name::in, bool::out, set(module_name)::out,
+ make_info::in, make_info::out, io__state::di, io__state::uo) is det.
+
+intermod_imports(ModuleName, Success, Modules, Info0, Info) -->
+ globals__io_lookup_bool_option(intermodule_optimization, Intermod),
+ (
+ { Intermod = yes },
+ % XXX Read `.opt' files transitively.
+ non_intermod_direct_imports(ModuleName, Success,
+ Modules, Info0, Info)
+ ;
+ { Intermod = no },
+ { Info = Info0 },
+ { Success = yes },
+ { Modules = set__init }
+ ).
+
+%-----------------------------------------------------------------------------%
+
+:- pred foreign_imports(module_name::in, bool::out, set(module_name)::out,
+ make_info::in, make_info::out, io__state::di, io__state::uo) is det.
+
+foreign_imports(ModuleName, Success, Modules, Info0, Info) -->
+ %
+ % The object file depends on the header files for the modules
+ % mentioned in `:- pragma foreign_import_module' declarations
+ % in the current module and the `.opt' files it imports.
+ %
+ globals__io_get_globals(Globals),
+ { globals__get_backend_foreign_languages(Globals, Languages) },
+ intermod_imports(ModuleName, IntermodSuccess, IntermodModules,
+ Info0, Info1),
+ foldl3_maybe_stop_at_error(Info1 ^ keep_going,
+ union_deps(find_module_foreign_imports(
+ set__list_to_set(Languages))),
+ [ModuleName | set__to_sorted_list(IntermodModules)],
+ ForeignSuccess, set__init, Modules, Info1, Info),
+ { Success = IntermodSuccess `and` ForeignSuccess }.
+
+:- pred find_module_foreign_imports(set(foreign_language)::in, module_name::in,
+ bool::out, set(module_name)::out,
+ make_info::in, make_info::out, io__state::di, io__state::uo) is det.
+
+find_module_foreign_imports(Languages, ModuleName,
+ Success, ForeignModules, Info0, Info) -->
+ get_module_dependencies(ModuleName, MaybeImports, Info0, Info),
+ {
+ MaybeImports = yes(Imports),
+ ForeignModules = set__list_to_set(
+ get_foreign_imported_modules(Languages,
+ Imports ^ foreign_import_module_info)),
+ Success = yes
+ ;
+ MaybeImports = no,
+ ForeignModules = set__init,
+ Success = no
+ }.
+
+:- func get_foreign_imported_modules(foreign_import_module_info) =
+ list(module_name).
+
+get_foreign_imported_modules(ForeignImportModules) =
+ get_foreign_imported_modules_2(no, ForeignImportModules).
+
+:- func get_foreign_imported_modules(set(foreign_language),
+ foreign_import_module_info) = list(module_name).
+
+get_foreign_imported_modules(Languages, ForeignImportModules) =
+ get_foreign_imported_modules_2(yes(Languages), ForeignImportModules).
+
+:- func get_foreign_imported_modules_2(maybe(set(foreign_language)),
+ foreign_import_module_info) = list(module_name).
+
+get_foreign_imported_modules_2(MaybeLanguages, ForeignImportModules) =
+ list__filter_map(
+ (func(ForeignImportModule) = ForeignModule is semidet :-
+ ForeignImportModule =
+ foreign_import_module(Language, ForeignModule, _),
+ (
+ MaybeLanguages = yes(Languages),
+ set__member(Language, Languages)
+ ;
+ MaybeLanguages = no
+ )
+ ), ForeignImportModules).
+
+%-----------------------------------------------------------------------------%
+
+:- pred fact_table(module_name::in,
+ bool::out, set(pair(file_name, maybe(option)))::out,
+ make_info::in, make_info::out, io__state::di, io__state::uo) is det.
+
+fact_table(ModuleName, Success, Files, Info0, Info) -->
+ get_module_dependencies(ModuleName, MaybeImports, Info0, Info),
+ {
+ MaybeImports = yes(Imports),
+ Success = yes,
+ Files = set__list_to_set(
+ make_target_list(Imports ^ fact_table_deps, no))
+ ;
+ MaybeImports = no,
+ Success = no,
+ Files = set__init
+ }.
+
+%-----------------------------------------------------------------------------%
+
+:- type transitive_dependencies_root
+ ---> transitive_dependencies_root(
+ module_name,
+ transitive_dependencies_type,
+ module_locn
+ ).
+
+:- type transitive_deps_result == pair(bool, set(module_name)).
+
+:- type transitive_dependencies_type
+ ---> interface_imports
+ ; all_dependencies % including parents and children
+ .
+
+:- type module_locn
+ ---> local_module % The source file for the module is in
+ % the current directory.
+ ; any_module
+ .
+
+:- type cached_transitive_dependencies ==
+ map(transitive_dependencies_root, transitive_deps_result).
+
+init_cached_transitive_dependencies = map__init.
+
+find_reachable_local_modules(ModuleName, Success, Modules, Info0, Info) -->
+ find_transitive_module_dependencies(all_dependencies, local_module,
+ ModuleName, Success, Modules0, Info0, Info),
+ { Modules = set__insert(Modules0, ModuleName) }.
+
+:- pred find_transitive_interface_imports(module_name::in, bool::out,
+ set(module_name)::out, make_info::in, make_info::out,
+ io__state::di, io__state::uo) is det.
+
+find_transitive_interface_imports(ModuleName,
+ Success, Modules, Info0, Info) -->
+ find_transitive_module_dependencies(interface_imports, any_module,
+ ModuleName, Success, Modules, Info0, Info).
+
+:- pred find_transitive_module_dependencies(transitive_dependencies_type::in,
+ module_locn::in, module_name::in, bool::out, set(module_name)::out,
+ make_info::in, make_info::out, io__state::di, io__state::uo) is det.
+
+find_transitive_module_dependencies(DependenciesType, ModuleLocn,
+ ModuleName, Success, Modules, Info0, Info) -->
+ globals__io_lookup_bool_option(keep_going, KeepGoing),
+ find_transitive_module_dependencies_2(KeepGoing,
+ DependenciesType, ModuleLocn, ModuleName,
+ Success, set__init, Modules0, Info0, Info1),
+ { set__delete(Modules0, ModuleName, Modules) },
+ { DepsRoot = transitive_dependencies_root(ModuleName,
+ DependenciesType, ModuleLocn) },
+ { Info = Info1 ^ cached_transitive_dependencies
+ ^ elem(DepsRoot) := Success - Modules }.
+
+:- pred find_transitive_module_dependencies_2(bool::in,
+ transitive_dependencies_type::in, module_locn::in,
+ module_name::in, bool::out, set(module_name)::in,
+ set(module_name)::out, make_info::in, make_info::out,
+ io__state::di, io__state::uo) is det.
+
+find_transitive_module_dependencies_2(KeepGoing, DependenciesType,
+ ModuleLocn, ModuleName, Success, Modules0, Modules,
+ Info0, Info) -->
+ (
+ { set__member(ModuleName, Modules0) }
+ ->
+ { Success = yes },
+ { Modules = Modules0 },
+ { Info = Info0 }
+ ;
+ { DepsRoot = transitive_dependencies_root(ModuleName,
+ DependenciesType, ModuleLocn) },
+ { Result0 = Info0 ^ cached_transitive_dependencies ^ elem(DepsRoot) }
+ ->
+ { Result0 = Success - Modules1 },
+ { Modules = set__union(Modules0, Modules1) },
+ { Info = Info0 }
+ ;
+ get_module_dependencies(ModuleName, MaybeImports, Info0, Info1),
+ (
+ { MaybeImports = yes(Imports) },
+ (
+ {
+ ModuleLocn = any_module
+ ;
+ ModuleLocn = local_module,
+ Imports ^ module_dir = dir__this_directory
+ }
+ ->
+ {
+ % Parents don't need to be considered here.
+ % Anywhere the interface of the child module
+ % is needed, the parent must also have been
+ % imported.
+ DependenciesType = interface_imports,
+ ImportsToCheck = Imports ^ int_deps
+ ;
+ DependenciesType = all_dependencies,
+ ImportsToCheck =
+ list__condense([
+ Imports ^ int_deps,
+ Imports ^ impl_deps,
+ Imports ^ parent_deps,
+ Imports ^ children,
+ get_foreign_imported_modules(
+ Imports ^ foreign_import_module_info)
+ ])
+ },
+ foldl3_maybe_stop_at_error(KeepGoing,
+ find_transitive_module_dependencies_2(KeepGoing,
+ DependenciesType, ModuleLocn),
+ ImportsToCheck, Success,
+ set__insert(Modules0, ModuleName), Modules,
+ Info1, Info)
+ ;
+ { Success = yes },
+ { Modules = Modules0 },
+ { Info = Info1 }
+ )
+ ;
+ { MaybeImports = no },
+ { Success = no } ,
+ { Modules = Modules0 },
+ { Info = Info1 }
+ )
+ ).
+
+%-----------------------------------------------------------------------------%
+
+check_dependencies(TargetFileName, MaybeTimestamp,
+ DepFiles, DepsResult, Info0, Info) -->
+ list__map_foldl2(dependency_status, DepFiles,
+ DepStatusList, Info0, Info1),
+ { assoc_list__from_corresponding_lists(DepFiles,
+ DepStatusList, DepStatusAL) },
+ { list__filter(
+ (pred((_ - DepStatus)::in) is semidet :-
+ DepStatus \= up_to_date
+ ), DepStatusAL, UnbuiltDependencies) },
+
+ ( { UnbuiltDependencies \= [] } ->
+ { Info = Info1 },
+ debug_msg(
+ (pred(di, uo) is det -->
+ io__write_string(TargetFileName),
+ io__write_string(
+ ": dependencies could not be built.\n\t"),
+ io__write_list(UnbuiltDependencies,
+ ",\n\t",
+ (pred((DepTarget - DepStatus)::in,
+ di, uo) is det -->
+ write_dependency_file(DepTarget),
+ io__write_string(" - "),
+ io__write(DepStatus)
+ )),
+ io__nl
+ )),
+ { DepsResult = error }
+ ;
+ debug_msg(
+ (pred(di, uo) is det -->
+ io__write_string(TargetFileName),
+ io__write_string(": finished dependencies\n")
+ )),
+ list__map_foldl2(get_dependency_timestamp, DepFiles,
+ DepTimestamps, Info1, Info),
+
+ check_dependency_timestamps(TargetFileName, MaybeTimestamp,
+ DepFiles, write_dependency_file, DepTimestamps,
+ DepsResult)
+ ).
+
+check_dependency_timestamps(TargetFileName, MaybeTimestamp, DepFiles,
+ WriteDepFile, DepTimestamps, DepsResult) -->
+ (
+ { MaybeTimestamp = error(_) },
+ { DepsResult = out_of_date },
+ debug_msg(
+ (pred(di, uo) is det -->
+ io__write_string(TargetFileName),
+ io__write_string("does not exist.\n")
+ ))
+ ;
+ { MaybeTimestamp = ok(Timestamp) },
+ globals__io_lookup_bool_option(rebuild, Rebuild),
+
+ (
+ { list__member(MaybeDepTimestamp1, DepTimestamps) },
+ { MaybeDepTimestamp1 = error(_) }
+ ->
+ { DepsResult = error }
+ ;
+ { Rebuild = yes }
+ ->
+ %
+ % With `--rebuild', a target is always considered
+ % to be out-of-date, regardless of the timestamps
+ % of its dependencies.
+ %
+ { DepsResult = out_of_date }
+ ;
+ { list__member(MaybeDepTimestamp2, DepTimestamps) },
+ { MaybeDepTimestamp2 = ok(DepTimestamp) },
+ { compare((>), DepTimestamp, Timestamp) }
+ ->
+ debug_newer_dependencies(TargetFileName, MaybeTimestamp,
+ DepFiles, WriteDepFile, DepTimestamps),
+ { DepsResult = out_of_date }
+ ;
+ { DepsResult = up_to_date }
+ )
+ ).
+
+:- pred debug_newer_dependencies(string::in, maybe_error(timestamp)::in,
+ list(T)::in, pred(T, io__state, io__state)::(pred(in, di, uo) is det),
+ list(maybe_error(timestamp))::in, io__state::di, io__state::uo) is det.
+
+debug_newer_dependencies(TargetFileName, MaybeTimestamp,
+ DepFiles, WriteDepFile, DepTimestamps) -->
+ debug_msg(
+ (pred(di, uo) is det -->
+ io__write_string(TargetFileName),
+ io__write_string(": newer dependencies: "),
+ { assoc_list__from_corresponding_lists(DepFiles,
+ DepTimestamps, DepTimestampAL) },
+ { solutions(
+ (pred(DepFile::out) is nondet :-
+ list__member(DepFile - MaybeDepTimestamp,
+ DepTimestampAL),
+ (
+ MaybeDepTimestamp = error(_)
+ ;
+ MaybeDepTimestamp = ok(DepTimestamp),
+ MaybeTimestamp = ok(Timestamp),
+ compare((>), DepTimestamp, Timestamp)
+ )), NewerDeps) },
+ io__write_list(NewerDeps, ",\n\t", WriteDepFile),
+ io__nl
+ )).
+
+dependency_status(file(FileName, _) @ Dep, Status, Info0, Info) -->
+ ( { Status0 = Info0 ^ dependency_status ^ elem(Dep) } ->
+ { Info = Info0 },
+ { Status = Status0 }
+ ;
+ get_dependency_timestamp(Dep, MaybeTimestamp, Info0, Info1),
+ (
+ { MaybeTimestamp = ok(_) },
+ { Status = up_to_date }
+ ;
+ { MaybeTimestamp = error(Error) },
+ { Status = error },
+ io__write_string("** Error: file `"),
+ io__write_string(FileName),
+ io__write_string("' not found: "),
+ io__write_string(Error)
+ ),
+ { Info = Info1 ^ dependency_status ^ elem(Dep) := Status }
+ ).
+dependency_status(target(Target) @ Dep, Status, Info0, Info) -->
+ { Target = ModuleName - FileType },
+ ( { FileType = source } ->
+ % Source files are always up-to-date.
+ { Info = Info0 },
+ { Status = up_to_date }
+ ; { Status0 = Info0 ^ dependency_status ^ elem(Dep) } ->
+ { Info = Info0 },
+ { Status = Status0 }
+ ;
+ get_module_dependencies(ModuleName, MaybeImports, Info0, Info1),
+ (
+ { MaybeImports = no },
+ { Status = error },
+ { Info2 = Info1 }
+ ;
+ { MaybeImports = yes(Imports) },
+ ( { Imports ^ module_dir \= dir__this_directory } ->
+ %
+ % Targets from libraries are always
+ % considered to be up-to-date if they
+ % exist.
+ %
+ get_target_timestamp(Target, MaybeTimestamp, Info1, Info2),
+ (
+ { MaybeTimestamp = ok(_) },
+ { Status = up_to_date }
+ ;
+ { MaybeTimestamp = error(Error) },
+ { Status = error },
+ io__write_string("** Error: file `"),
+ write_target_file(Target),
+ io__write_string("' not found: "),
+ io__write_string(Error)
+ )
+ ;
+ { Info2 = Info1 },
+ { Status = not_considered }
+ )
+ ),
+ { Info = Info2 ^ dependency_status ^ elem(Dep) := Status }
+ ).
+
+%-----------------------------------------------------------------------------%
Index: compiler/make.module_dep_file.m
===================================================================
RCS file: compiler/make.module_dep_file.m
diff -N compiler/make.module_dep_file.m
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ compiler/make.module_dep_file.m 3 Feb 2002 12:44:40 -0000
@@ -0,0 +1,590 @@
+%-----------------------------------------------------------------------------%
+% Copyright (C) 2002 The University of Melbourne.
+% This file may only be copied under the terms of the GNU General
+% Public License - see the file COPYING in the Mercury distribution.
+%-----------------------------------------------------------------------------%
+% File: make.module_dep_file.m
+% Author: stayl
+%
+% Code to read and write the `<module>.module_dep' files, which contain
+% information about inter-module dependencies.
+%-----------------------------------------------------------------------------%
+:- module make__module_dep_file.
+
+:- interface.
+
+:- import_module modules.
+:- import_module std_util, io.
+
+ % Get the dependencies for a given module.
+ % Dependencies are generated on demand, not by a `mmc --make depend'
+ % command, so this predicate may need to read the source for
+ % the module.
+:- pred get_module_dependencies(module_name::in, maybe(module_imports)::out,
+ make_info::in, make_info::out, io__state::di, io__state::uo) is det.
+
+:- pred write_module_dep_file(module_imports::in,
+ io__state::di, io__state::uo) is det.
+
+%-----------------------------------------------------------------------------%
+:- implementation.
+
+get_module_dependencies(ModuleName, MaybeImports, Info0, Info) -->
+ { RebuildDeps = Info0 ^ rebuild_dependencies },
+ (
+ { ModuleName = unqualified(_) }
+ ->
+ get_module_dependencies_2(RebuildDeps, ModuleName, MaybeImports,
+ Info0, Info)
+ ;
+ { map__search(Info0 ^ module_dependencies,
+ ModuleName, MaybeImports0) }
+ ->
+ { MaybeImports = MaybeImports0 },
+ { Info = Info0 }
+ ;
+ %
+ % For sub-modules, we need to generate the dependencies
+ % for the parent modules first (make_module_dependencies
+ % expects to be given the top-level module in a source file).
+ % If the module is a nested module, its dependencies will be
+ % generated as a side effect of generating the parent's
+ % dependencies.
+ %
+ { get_ancestors(ModuleName, Ancestors) },
+ list__foldl3(
+ generate_ancestor_dependencies(RebuildDeps),
+ Ancestors, no, Error, Info0, Info1),
+ (
+ { Error = yes },
+ { MaybeImports = no },
+ { Info = Info1 ^ module_dependencies
+ ^ elem(ModuleName) := MaybeImports }
+ ;
+ { Error = no },
+ get_module_dependencies_2(RebuildDeps,
+ ModuleName, MaybeImports, Info1, Info)
+ )
+ ).
+
+:- pred generate_ancestor_dependencies(bool::in, module_name::in,
+ bool::in, bool::out, make_info::in, make_info::out,
+ io__state::di, io__state::uo) is det.
+
+generate_ancestor_dependencies(_, ModuleName, yes, yes, Info,
+ Info ^ module_dependencies ^ elem(ModuleName) := no) --> [].
+generate_ancestor_dependencies(RebuildDeps, ModuleName,
+ no, Error, Info0, Info) -->
+ get_module_dependencies_2(RebuildDeps,
+ ModuleName, MaybeImports, Info0, Info),
+ { MaybeImports = yes(_), Error = no
+ ; MaybeImports = no, Error = yes
+ }.
+
+:- pred get_module_dependencies_2(bool::in, module_name::in,
+ maybe(module_imports)::out, make_info::in, make_info::out,
+ io__state::di, io__state::uo) is det.
+
+get_module_dependencies_2(RebuildDeps, ModuleName,
+ MaybeImports, Info0, Info) -->
+ (
+ { map__search(Info0 ^ module_dependencies, ModuleName, MaybeImports0) }
+ ->
+ { MaybeImports = MaybeImports0 },
+ { Info = Info0 }
+ ;
+ % We can't just use
+ % `get_target_timestamp(ModuleName - source, ..)'
+ % because that could recursively call get_module_dependencies,
+ % leading to an infinite loop. Just using module_name_to_file_name
+ % will fail if the module name doesn't match the file name, but
+ % that case is handled below.
+ module_name_to_file_name(ModuleName, ".m", no, SourceFileName),
+ get_file_timestamp([dir__this_directory], SourceFileName,
+ MaybeSourceFileTimestamp, Info0, Info2),
+
+ module_name_to_file_name(ModuleName, module_dep_file_extension,
+ no, DepFileName),
+ globals__io_lookup_accumulating_option(search_directories, SearchDirs),
+ get_file_timestamp(SearchDirs, DepFileName,
+ MaybeDepFileTimestamp, Info2, Info3),
+
+ (
+ { MaybeSourceFileTimestamp = ok(SourceFileTimestamp) },
+ { MaybeDepFileTimestamp = ok(DepFileTimestamp) },
+ (
+ { RebuildDeps = no
+ ; compare((>), DepFileTimestamp, SourceFileTimestamp)
+ }
+ ->
+ read_module_dependencies(RebuildDeps,
+ ModuleName, Info3, Info6)
+ ;
+ make_module_dependencies(ModuleName, Info3, Info6)
+ )
+ ;
+ { MaybeSourceFileTimestamp = error(_) },
+ { MaybeDepFileTimestamp = ok(DepFileTimestamp) },
+ read_module_dependencies(RebuildDeps,
+ ModuleName, Info3, Info4),
+
+ %
+ % Check for the case where the module name doesn't match
+ % the source file name (e.g. parse.m contains module
+ % mdb.parse). Get the correct source file name from
+ % the module dependency file, then check whether the
+ % module dependency file is up to date.
+ %
+ { map__lookup(Info4 ^ module_dependencies,
+ ModuleName, MaybeImports0) },
+ (
+ { MaybeImports0 = yes(Imports0) },
+ { Imports0 ^ module_dir = dir__this_directory }
+ ->
+ { SourceFileName1 = Imports0 ^ source_file_name },
+ get_file_timestamp([dir__this_directory], SourceFileName1,
+ MaybeSourceFileTimestamp1, Info4, Info5),
+ (
+ { MaybeSourceFileTimestamp1 =
+ ok(SourceFileTimestamp1) },
+ (
+ { RebuildDeps = no
+ ; compare((>), DepFileTimestamp,
+ SourceFileTimestamp1)
+ }
+ ->
+ { Info6 = Info5 }
+ ;
+ make_module_dependencies(ModuleName, Info5, Info6)
+ )
+ ;
+ { MaybeSourceFileTimestamp1 = error(Message) },
+ io__write_string("** Error reading file `"),
+ io__write_string(SourceFileName1),
+ io__write_string("' to generate dependencies: "),
+ io__write_string(Message),
+ io__write_string(".\n"),
+ { Info6 = Info5 }
+ )
+ ;
+ { Info6 = Info4 }
+ )
+ ;
+ { MaybeDepFileTimestamp = error(_)},
+
+ %
+ % Try to make the dependencies. This will succeed
+ % when the module name doesn't match the file name
+ % and the dependencies for this module haven't been
+ % built before. It will fail if the source file is
+ % in another directory.
+ %
+ ( { RebuildDeps = yes } ->
+ make_module_dependencies(ModuleName, Info3, Info6)
+ ;
+ { Info6 = Info3 ^ module_dependencies
+ ^ elem(ModuleName) := no }
+ )
+ ),
+
+ { MaybeImports1 = Info6 ^ module_dependencies ^ elem(ModuleName) ->
+ Info = Info6,
+ MaybeImports = MaybeImports1
+ ;
+ MaybeImports = no,
+ Info = Info6 ^ module_dependencies ^ elem(ModuleName) := no
+ }
+ ).
+
+%-----------------------------------------------------------------------------%
+
+:- func module_dependencies_version_number = int.
+
+module_dependencies_version_number = 1.
+
+write_module_dep_file(Imports0) -->
+ % Make sure all the required fields are filled in.
+ globals__io_get_globals(Globals),
+ { strip_imported_items(Imports0 ^ items, Items) },
+ { init_dependencies(Imports0 ^ source_file_name,
+ Imports0 ^ source_file_module_name,
+ Imports0 ^ nested_children, no_module_errors, Globals,
+ Imports0 ^ module_name - Items, Imports) },
+ do_write_module_dep_file(Imports).
+
+:- pred do_write_module_dep_file(module_imports::in,
+ io__state::di, io__state::uo) is det.
+
+do_write_module_dep_file(Imports) -->
+ { ModuleName = Imports ^ module_name },
+ module_name_to_file_name(ModuleName, module_dep_file_extension,
+ yes, ProgDepFile),
+ io__open_output(ProgDepFile, ProgDepResult),
+ (
+ { ProgDepResult = ok(ProgDepStream) },
+ io__set_output_stream(ProgDepStream, OldOutputStream),
+ io__write_string("module("),
+ io__write_int(module_dependencies_version_number),
+ io__write_string(", """),
+ io__write_string(Imports ^ source_file_name),
+ io__write_string(""",\n\t"),
+ mercury_output_bracketed_sym_name(
+ Imports ^ source_file_module_name),
+ io__write_string(",\n\t{"),
+ io__write_list(Imports ^ parent_deps,
+ ", ", mercury_output_bracketed_sym_name),
+ io__write_string("},\n\t{"),
+ io__write_list(Imports ^ int_deps,
+ ", ", mercury_output_bracketed_sym_name),
+ io__write_string("},\n\t{"),
+ io__write_list(Imports ^ impl_deps,
+ ", ", mercury_output_bracketed_sym_name),
+ io__write_string("},\n\t{"),
+ io__write_list(Imports ^ children,
+ ", ", mercury_output_bracketed_sym_name),
+ io__write_string("},\n\t{"),
+ io__write_list(Imports ^ nested_children,
+ ", ", mercury_output_bracketed_sym_name),
+ io__write_string("},\n\t{"),
+ io__write_list(Imports ^ fact_table_deps,
+ ", ", io__write),
+ io__write_string("},\n\t{"),
+ {
+ Imports ^ foreign_code =
+ contains_foreign_code(ForeignLanguages0)
+ ->
+ ForeignLanguages = set__to_sorted_list(
+ ForeignLanguages0)
+ ;
+ ForeignLanguages = []
+ },
+ io__write_list(ForeignLanguages, ", ",
+ mercury_output_foreign_language_string),
+ io__write_string("},\n\t{"),
+ io__write_list(Imports ^ foreign_import_module_info, ", ",
+ (pred(ForeignImportModule::in, di, uo) is det -->
+ { ForeignImportModule = foreign_import_module(
+ Lang, ForeignImport, _) },
+ mercury_output_foreign_language_string(Lang),
+ io__write_string(" - "),
+ mercury_output_bracketed_sym_name(ForeignImport)
+ )),
+ io__write_string("},\n\t"),
+ io__write(Imports ^ contains_foreign_export),
+ io__write_string(",\n\t"),
+ io__write(Imports ^ has_main),
+ io__write_string("\n).\n"),
+ io__set_output_stream(OldOutputStream, _),
+ io__close_output(ProgDepStream)
+ ;
+ { ProgDepResult = error(Error) },
+ { io__error_message(Error, Msg) },
+ io__write_strings(["Error opening ", ProgDepFile,
+ "for output: ", Msg, "\n"]),
+ io__set_exit_status(1)
+ ).
+
+:- pred read_module_dependencies(bool::in, module_name::in,
+ make_info::in, make_info::out, io__state::di, io__state::uo) is det.
+
+read_module_dependencies(RebuildDeps, ModuleName, Info0, Info) -->
+ module_name_to_file_name(ModuleName, module_dep_file_extension,
+ no, ModuleDepFile),
+ globals__io_lookup_accumulating_option(search_directories, SearchDirs),
+ io__input_stream(OldInputStream),
+ search_for_file(SearchDirs, ModuleDepFile, SearchResult),
+ ( { SearchResult = yes(ModuleDir) } ->
+ parser__read_term(ImportsTermResult),
+ io__set_input_stream(OldInputStream, ModuleDepStream),
+ io__close_input(ModuleDepStream),
+ (
+ { ImportsTermResult = term(_, ImportsTerm) },
+ { ImportsTerm = term__functor(term__atom("module"),
+ ModuleArgs, _) },
+ { ModuleArgs = [
+ VersionNumberTerm,
+ SourceFileTerm,
+ SourceFileModuleNameTerm,
+ ParentsTerm,
+ IntDepsTerm,
+ ImplDepsTerm,
+ ChildrenTerm,
+ NestedChildrenTerm,
+ FactDepsTerm,
+ ForeignLanguagesTerm,
+ ForeignImportsTerm,
+ ContainsForeignExportTerm,
+ HasMainTerm
+ ] },
+ { VersionNumberTerm = term__functor(
+ term__integer(module_dependencies_version_number),
+ [], _) },
+ { SourceFileTerm = term__functor(
+ term__string(SourceFileName), [], _) },
+ { sym_name_and_args(SourceFileModuleNameTerm,
+ SourceFileModuleName, []) },
+ { parse_sym_name_list(ParentsTerm, Parents) },
+ { parse_sym_name_list(IntDepsTerm, IntDeps) },
+ { parse_sym_name_list(ImplDepsTerm, ImplDeps) },
+ { parse_sym_name_list(ChildrenTerm, Children) },
+ { parse_sym_name_list(NestedChildrenTerm, NestedChildren) },
+ { FactDepsTerm = term__functor(term__atom("{}"),
+ FactDepsStrings, _) },
+ { list__map(
+ (pred(StringTerm::in, String::out) is semidet :-
+ StringTerm = term__functor(
+ term__string(String), [], _)
+ ), FactDepsStrings, FactDeps) },
+ { ForeignLanguagesTerm = term__functor(
+ term__atom("{}"), ForeignLanguagesTerms, _) },
+ { list__map(
+ (pred(LanguageTerm::in,
+ Language::out) is semidet :-
+ LanguageTerm = term__functor(
+ term__string(LanguageString), [], _),
+ globals__convert_foreign_language(
+ LanguageString, Language)
+ ), ForeignLanguagesTerms, ForeignLanguages) },
+ { ForeignImportsTerm = term__functor(term__atom("{}"),
+ ForeignImportTerms, _) },
+ { list__map(
+ (pred(ForeignImportTerm::in,
+ ForeignImportModule::out) is semidet :-
+ ForeignImportTerm = term__functor(term__atom("-"),
+ [LanguageTerm, ImportedModuleTerm], _),
+ LanguageTerm = term__functor(
+ term__string(LanguageString), [], _),
+ globals__convert_foreign_language(LanguageString,
+ Language),
+ sym_name_and_args(ImportedModuleTerm,
+ ImportedModuleName, []),
+ ForeignImportModule = foreign_import_module(
+ Language, ImportedModuleName,
+ term__context_init)
+ ), ForeignImportTerms, ForeignImports) },
+
+ { ContainsForeignExportTerm =
+ term__functor(term__atom(ContainsForeignExportStr),
+ [], _) },
+ { ContainsForeignExportStr = "contains_foreign_export",
+ ContainsForeignExport = contains_foreign_export
+ ; ContainsForeignExportStr = "no_foreign_export",
+ ContainsForeignExport = no_foreign_export
+ },
+
+ { HasMainTerm = term__functor(term__atom(HasMainStr),
+ [], _) },
+ { HasMainStr = "has_main", HasMain = has_main
+ ; HasMainStr = "no_main", HasMain = no_main
+ }
+ ->
+ { ForeignLanguages = [] ->
+ ContainsForeignCode = no_foreign_code
+ ;
+ ContainsForeignCode = contains_foreign_code(
+ set__list_to_set(ForeignLanguages))
+ },
+ { Imports = module_imports(SourceFileName,
+ SourceFileModuleName, ModuleName, Parents,
+ IntDeps, ImplDeps, [], [], Children,
+ NestedChildren, FactDeps, ContainsForeignCode,
+ ForeignImports, ContainsForeignExport,
+ [], no_module_errors, no, HasMain, ModuleDir) },
+ { Info1 = Info0 ^ module_dependencies
+ ^ elem(ModuleName) := yes(Imports) },
+
+ %
+ % Read the dependencies for the nested children.
+ % If something goes wrong (for example one of the
+ % files was removed), the dependencies for all
+ % modules in the source file will be remade
+ % (make_module_dependencies expects to be given
+ % the top-level module in the source file).
+ %
+ { SubRebuildDeps = no },
+ list__foldl2(read_module_dependencies(SubRebuildDeps),
+ NestedChildren, Info1, Info2),
+ (
+ { list__member(NestedChild, NestedChildren) },
+ {
+ map__search(Info2 ^ module_dependencies,
+ NestedChild, ChildImports)
+ ->
+ ChildImports = no
+ ;
+ true
+ }
+ ->
+ read_module_dependencies_remake(RebuildDeps,
+ ModuleName, "error in nested sub-modules",
+ Info2, Info)
+ ;
+ { Info = Info2 }
+ )
+ ;
+ read_module_dependencies_remake(RebuildDeps,
+ ModuleName, "parse error", Info0, Info)
+ )
+ ;
+ read_module_dependencies_remake(RebuildDeps, ModuleName,
+ "couldn't find `.module_dep' file", Info0, Info)
+ ).
+
+ % Something went wrong reading the dependencies, so just rebuild them.
+:- pred read_module_dependencies_remake(bool::in, module_name::in, string::in,
+ make_info::in, make_info::out, io__state::di, io__state::uo) is det.
+
+read_module_dependencies_remake(RebuildDeps, ModuleName, Msg, Info0, Info) -->
+ ( { RebuildDeps = yes } ->
+ module_name_to_file_name(ModuleName,
+ module_dep_file_extension, no, ModuleDepsFile),
+ debug_msg(
+ (pred(di, uo) is det -->
+ io__write_string("Error reading file `"),
+ io__write_string(ModuleDepsFile),
+ io__write_string("rebuilding: "),
+ io__write_string(Msg),
+ io__nl
+ )),
+ make_module_dependencies(ModuleName, Info0, Info)
+ ;
+ { Info = Info0 }
+ ).
+
+:- pred parse_sym_name_list(term::in, list(sym_name)::out) is semidet.
+
+parse_sym_name_list(term__functor(term__atom("{}"), Args, _), SymNames) :-
+ list__map(
+ (pred(Arg::in, SymName::out) is semidet :-
+ sym_name_and_args(Arg, SymName, [])
+ ), Args, SymNames).
+
+ % The module_name given must be the top level module in
+ % the source file. get_module_dependencies ensures this by
+ % making the dependencies for all parent modules of the
+ % requested module first.
+:- pred make_module_dependencies(module_name::in, make_info::in,
+ make_info::out, io__state::di, io__state::uo) is det.
+
+make_module_dependencies(ModuleName, Info0, Info) -->
+ { Search = no },
+ { ReturnTimestamp = yes },
+
+ redirect_output(ModuleName, MaybeErrorStream, Info0, Info1),
+ (
+ { MaybeErrorStream = yes(ErrorStream) },
+ io__set_output_stream(ErrorStream, OldOutputStream),
+ read_mod(ModuleName, ".m",
+ "Getting dependencies for module", Search, ReturnTimestamp,
+ Items, Error, SourceFileName, _),
+ ( { Error = fatal_module_errors } ->
+ io__set_output_stream(OldOutputStream, _),
+ io__write_string("** Error: error reading file `"),
+ io__write_string(SourceFileName),
+ io__write_string("' to generate dependencies.\n"),
+
+ % Display the contents of the `.err' file, then remove it
+ % so we don't leave `.err' files lying around for nonexistent
+ % modules.
+ globals__io_lookup_int_option(output_compile_error_lines, Lines),
+ globals__io_set_option(output_compile_error_lines, int(10000)),
+ unredirect_output(ModuleName, ErrorStream, Info1, Info2),
+ globals__io_set_option(output_compile_error_lines, int(Lines)),
+ module_name_to_file_name(ModuleName, ".err", no, ErrFileName),
+ io__remove_file(ErrFileName, _),
+ { Info = Info2 ^ module_dependencies ^ elem(ModuleName) := no }
+ ;
+ io__set_exit_status(0),
+ io__set_output_stream(ErrorStream, _),
+ split_into_submodules(ModuleName, Items, SubModuleList),
+ io__set_output_stream(OldOutputStream, _),
+
+ globals__io_get_globals(Globals),
+ { assoc_list__keys(SubModuleList, SubModuleNames) },
+ { list__map(
+ init_dependencies(SourceFileName, ModuleName,
+ SubModuleNames, Error, Globals),
+ SubModuleList, ModuleImportList) },
+ { list__foldl(
+ (pred(ModuleImports::in, in, out) is det -->
+ { SubModuleName = ModuleImports ^ module_name },
+ ^ module_dependencies ^ elem(SubModuleName)
+ := yes(ModuleImports)
+ ), ModuleImportList, Info1, Info2) },
+
+ %
+ % If there were no errors, write out the `.int3' file
+ % while we have the contents of the module. The `int3'
+ % file doesn't depend on anything else.
+ %
+ ( { Error = no_module_errors } ->
+ { Target = ModuleName - unqualified_short_interface },
+ maybe_make_target_message(OldOutputStream, Target),
+ build_with_check_for_interrupt(
+ build_with_module_options(ModuleName,
+ ["--make-short-interface"],
+ make_short_interfaces(ErrorStream,
+ SourceFileName, SubModuleList)),
+ cleanup_short_interfaces(SubModuleNames),
+ Succeeded, Info2, Info3)
+ ;
+ { Info3 = Info2 },
+ { Succeeded = no }
+ ),
+
+ build_with_check_for_interrupt(
+ (pred(yes::out, MakeInfo::in, MakeInfo::out, di, uo) is det -->
+ list__foldl(do_write_module_dep_file,
+ ModuleImportList)
+ ), cleanup_module_dep_files(SubModuleNames),
+ _, Info3, Info5),
+
+ record_made_target(ModuleName - unqualified_short_interface,
+ process_module(make_short_interface), Succeeded, Info5, Info6),
+
+ unredirect_output(ModuleName, ErrorStream,
+ Info6, Info)
+ )
+ ;
+ { MaybeErrorStream = no },
+ { Info = Info1 }
+ ).
+
+:- pred make_short_interfaces(io__output_stream::in, file_name::in,
+ assoc_list(module_name, item_list)::in, list(string)::in, bool::out,
+ make_info::in, make_info::out, io__state::di, io__state::uo) is det.
+
+make_short_interfaces(ErrorStream, SourceFileName, SubModuleList,
+ _, Succeeded, Info, Info) -->
+ io__set_output_stream(ErrorStream, OutputStream),
+ list__foldl(
+ (pred(SubModule::in, di, uo) is det -->
+ { SubModule = SubModuleName - SubModuleItems },
+ modules__make_short_interface(SourceFileName,
+ SubModuleName, SubModuleItems)
+ ), SubModuleList),
+ io__set_output_stream(OutputStream, _),
+ io__get_exit_status(ExitStatus),
+ { Succeeded = ( ExitStatus = 0 -> yes ; no ) }.
+
+:- pred cleanup_short_interfaces(list(module_name)::in,
+ make_info::in, make_info::out, io__state::di, io__state::uo) is det.
+
+cleanup_short_interfaces(SubModuleNames, Info0, Info) -->
+ list__foldl2(
+ (pred(SubModuleName::in, Info1::in, Info2::out, di, uo) is det -->
+ remove_target_file(SubModuleName, unqualified_short_interface,
+ Info1, Info2)
+ ), SubModuleNames, Info0, Info).
+
+:- pred cleanup_module_dep_files(list(module_name)::in,
+ make_info::in, make_info::out, io__state::di, io__state::uo) is det.
+
+cleanup_module_dep_files(SubModuleNames, Info0, Info) -->
+ list__foldl2(
+ (pred(SubModuleName::in, Info1::in, Info2::out, di, uo) is det -->
+ remove_file(SubModuleName, module_dep_file_extension,
+ Info1, Info2)
+ ), SubModuleNames, Info0, Info).
+
+%-----------------------------------------------------------------------------%
Index: compiler/make.module_target.m
===================================================================
RCS file: compiler/make.module_target.m
diff -N compiler/make.module_target.m
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ compiler/make.module_target.m 5 Feb 2002 09:39:21 -0000
@@ -0,0 +1,701 @@
+%-----------------------------------------------------------------------------%
+% Copyright (C) 2002 The University of Melbourne.
+% This file may only be copied under the terms of the GNU General
+% Public License - see the file COPYING in the Mercury distribution.
+%-----------------------------------------------------------------------------%
+:- module make__module_target.
+
+:- interface.
+
+:- pred make_module_target(dependency_file::in, bool::out,
+ make_info::in, make_info::out, io__state::di, io__state::uo) is det.
+
+ % For make__module_dep_file__write_module_dep_file.
+:- pred record_made_target(target_file::in, compilation_task_type::in,
+ bool::in, make_info::in, make_info::out,
+ io__state::di, io__state::uo) is det.
+
+:- type foreign_code_file
+ ---> foreign_code_file(
+ foreign_language :: foreign_language,
+ target_file :: file_name,
+ object_file :: file_name
+ ).
+
+ % Find the foreign code files generated when a module is processed.
+:- pred external_foreign_code_files(module_imports::in,
+ list(foreign_code_file)::out, io__state::di, io__state::uo) is det.
+
+%-----------------------------------------------------------------------------%
+:- implementation.
+
+:- import_module passes_aux.
+
+:- pred make_module_target(dependency_file::in, bool::in, bool::out,
+ make_info::in, make_info::out, io__state::di, io__state::uo) is det.
+
+make_module_target(TargetFile, Succeeded1, Succeeded1 `and` Succeeded2,
+ Info0, Info) -->
+ make_module_target(TargetFile, Succeeded2, Info0, Info).
+
+make_module_target(file(_, _) @ Dep, Succeeded, Info0, Info) -->
+ dependency_status(Dep, Status, Info0, Info),
+ { Succeeded = ( Status = error -> no ; yes ) }.
+make_module_target(target(TargetFile) @ Dep, Succeeded, Info0, Info) -->
+ dependency_status(Dep, Status, Info0, Info1),
+ (
+ { Status = not_considered },
+ { TargetFile = ModuleName - FileType },
+ get_module_dependencies(ModuleName, MaybeImports, Info1, Info2),
+ (
+ { MaybeImports = no },
+ { Succeeded = no },
+ { Info = Info2 ^ dependency_status ^ elem(Dep) := error }
+ ;
+ { MaybeImports = yes(Imports) },
+ globals__io_get_globals(Globals),
+ { CompilationTask = compilation_task(Globals, FileType) },
+ (
+ % For a target built by processing a Mercury source file,
+ % the target for a nested sub-module is produced as a side
+ % effect of making the target for the top-level module in
+ % the file.
+ { CompilationTask = process_module(_) - _ },
+ { Imports ^ source_file_module_name \= ModuleName }
+ ->
+ make_module_target(
+ target(Imports ^ source_file_module_name - FileType),
+ Succeeded, Info2, Info)
+ ;
+ { CompilationTask = CompilationTaskType - _ },
+ touched_files(TargetFile, CompilationTaskType,
+ TouchedTargetFiles, TouchedFiles, Info2, Info3),
+ { list__foldl(update_target_status(being_built),
+ TouchedTargetFiles, Info3, Info4) },
+
+ debug_file_msg(TargetFile, "checking dependencies"),
+
+ { CompilationTask = process_module(_) - _ ->
+ ModulesToCheck = [ModuleName | Imports ^ nested_children]
+ ;
+ ModulesToCheck = [ModuleName]
+ },
+
+ foldl3_maybe_stop_at_error(Info4 ^ keep_going,
+ union_deps(target_dependencies(Globals, FileType)),
+ ModulesToCheck, DepsSuccess, set__init,
+ DepFiles0, Info4, Info5),
+ { DepFiles = set__to_sorted_list(DepFiles0) },
+
+ debug_msg(
+ (pred(di, uo) is det -->
+ write_target_file(TargetFile),
+ io__write_string(": dependencies:\n"),
+ io__write_list(DepFiles, ", ", write_dependency_file),
+ io__nl
+ )),
+
+ %
+ % For comparison, find the oldest of the touched
+ % timestamp files.
+ %
+ list__map_foldl2(
+ get_timestamp_file_timestamp, TouchedTargetFiles,
+ TouchedTargetFileTimestamps, Info5, Info6),
+ list__map_foldl2(get_file_timestamp([dir__this_directory]),
+ TouchedFiles, TouchedFileTimestamps, Info6, Info8),
+ { MaybeOldestTimestamp0 = list__foldl(find_oldest_timestamp,
+ TouchedTargetFileTimestamps, ok(newest_timestamp)) },
+ { MaybeOldestTimestamp = list__foldl(find_oldest_timestamp,
+ TouchedFileTimestamps, MaybeOldestTimestamp0) },
+ module_name_to_file_name(ModuleName,
+ target_extension(Globals, FileType),
+ no, TargetFileName),
+
+ globals__io_lookup_bool_option(keep_going, KeepGoing),
+ ( { DepsSuccess = no, KeepGoing = no } ->
+ { Info10 = Info8 },
+ { DepsResult = error }
+ ;
+ foldl2_maybe_stop_at_error(KeepGoing,
+ make_module_target, DepFiles,
+ _, Info8, Info9),
+ check_dependencies(TargetFileName,
+ MaybeOldestTimestamp, DepFiles,
+ DepsResult0, Info9, Info10),
+ { DepsResult =
+ ( DepsSuccess = yes -> DepsResult0 ; error ) }
+ ),
+ (
+ { DepsResult = error },
+ { Succeeded = no },
+ { list__foldl(update_target_status(error),
+ TouchedTargetFiles, Info10, Info) }
+ ;
+ { DepsResult = out_of_date },
+ build_target(CompilationTask, TargetFile, Imports,
+ TouchedTargetFiles, TouchedFiles, Succeeded,
+ Info10, Info)
+ ;
+ { DepsResult = up_to_date },
+ debug_file_msg(TargetFile, "up to date"),
+ { Succeeded = yes },
+ { list__foldl(update_target_status(up_to_date),
+ [TargetFile | TouchedTargetFiles],
+ Info10, Info) }
+ )
+ )
+ )
+ ;
+ { Status = up_to_date },
+ { Succeeded = yes },
+ { Info = Info1 }
+ ;
+ { Status = being_built },
+ { error(
+ "make_module_target: target being built, circular dependencies?") },
+ { Succeeded = no },
+ { Info = Info1 }
+ ;
+ { Status = error },
+ { Succeeded = no },
+ { Info = Info1 }
+ ).
+
+:- func find_oldest_timestamp(maybe_error(timestamp),
+ maybe_error(timestamp)) = maybe_error(timestamp).
+
+find_oldest_timestamp(error(_) @ Timestamp, _) = Timestamp.
+find_oldest_timestamp(ok(_), error(_) @ Timestamp) = Timestamp.
+find_oldest_timestamp(ok(Timestamp1), ok(Timestamp2)) =
+ ok( ( compare((<), Timestamp1, Timestamp2) -> Timestamp1 ; Timestamp2 ) ).
+
+%-----------------------------------------------------------------------------%
+
+:- pred build_target(compilation_task_result::in, target_file::in,
+ module_imports::in, list(target_file)::in, list(file_name)::in,
+ bool::out, make_info::in, make_info::out,
+ io__state::di, io__state::uo) is det.
+
+build_target(CompilationTask, TargetFile, Imports, TouchedTargetFiles,
+ TouchedFiles, Succeeded, Info0, Info) -->
+ maybe_make_target_message(TargetFile),
+ { TargetFile = ModuleName - _FileType },
+ { CompilationTask = Task - TaskOptions },
+ { Cleanup =
+ (pred(MakeInfo0::in, MakeInfo::out, di, uo) is det -->
+ % XXX Remove `.int.tmp' files.
+ list__foldl2(remove_target_file, TouchedTargetFiles,
+ MakeInfo0, MakeInfo1),
+ list__foldl2(remove_file, TouchedFiles,
+ MakeInfo1, MakeInfo)
+ ) },
+ build_with_check_for_interrupt(
+ build_with_module_options_and_output_redirect(ModuleName,
+ TaskOptions, build_target_2(ModuleName, Task, Imports)),
+ Cleanup, Succeeded, Info0, Info1),
+ record_made_target_2(Succeeded, TargetFile, TouchedTargetFiles,
+ TouchedFiles, Info1, Info).
+
+:- pred build_target_2(module_name::in, compilation_task_type::in,
+ module_imports::in, list(string)::in, io__output_stream::in,
+ bool::out, make_info::in, make_info::out,
+ io__state::di, io__state::uo) is det.
+
+build_target_2(ModuleName, process_module(ModuleTask), _Imports,
+ AllOptionArgs, ErrorStream, Succeeded, Info, Info) -->
+ { prog_out__sym_name_to_string(ModuleName, ".", ModuleArg) },
+
+ globals__io_lookup_bool_option(verbose_commands, Verbose),
+ ( { Verbose = yes } ->
+ { AllArgs = list__append(AllOptionArgs, [ModuleArg]) },
+ io__write_string("Invoking command `mmc "),
+ % XXX Don't write the default options.
+ io__write_list(quote_args(AllArgs), " ",
+ io__write_string),
+ io__write_string("'"),
+ io__nl
+ ;
+ []
+ ),
+
+ %
+ % Run compilations to target code in a separate process.
+ % This is necessary for `--target asm' because the GCC
+ % backend can only be invoked once per process. It's a good
+ % idea for other the backends because it avoids problems with
+ % the Boehm GC retaining memory by scanning too much of the
+ % Mercury stacks. If the compilation is run in a separate
+ % process, it is also easier to kill if an interrupt arrives.
+ %
+ io__set_output_stream(ErrorStream, OldOutputStream),
+ ( { ModuleTask = compile_to_target_code } ->
+ call_in_forked_process(call_mercury_compile_main([ModuleArg]),
+ invoke_mmc(ErrorStream, AllOptionArgs), Succeeded)
+ ;
+ call_mercury_compile_main([ModuleArg], Succeeded)
+ ),
+ io__set_output_stream(OldOutputStream, _),
+
+ (
+ { ModuleTask = compile_to_target_code
+ ; ModuleTask = errorcheck
+ }
+ ->
+ % The `.err_date' file is needed because the `.err'
+ % file is touched by all phases of compilation, including
+ % writing interfaces.
+ touch_interface_datestamp(ModuleName, ".err_date")
+ ;
+ []
+ ).
+
+build_target_2(ModuleName, target_code_to_object_code,
+ Imports, _, ErrorStream, Succeeded, Info0, Info) -->
+ get_target_code_to_object_code_foreign_files(ModuleName,
+ ForeignCodeFiles, Info0, Info),
+ globals__io_get_target(CompilationTarget),
+
+ { CompileTargetCode =
+ (pred(Succeeded1::out, di, uo) is det -->
+ build_object_code(ModuleName, CompilationTarget,
+ ErrorStream, Imports, Succeeded0),
+ list__map_foldl(compile_foreign_code_file(ErrorStream),
+ ForeignCodeFiles, ForeignCodeSucceeded),
+ {
+ Succeeded0 = yes,
+ \+ list__member(no, ForeignCodeSucceeded)
+ ->
+ Succeeded1 = yes
+ ;
+ Succeeded1 = no
+ }
+ ) },
+
+
+ % Run the compilation in a child process so it can
+ % be killed if an interrupt arrives.
+ call_in_forked_process(CompileTargetCode,
+ CompileTargetCode, Succeeded).
+
+:- pred build_object_code(module_name::in, compilation_target::in,
+ io__output_stream::in, module_imports::in, bool::out,
+ io__state::di, io__state::uo) is det.
+
+build_object_code(ModuleName, c, ErrorStream, _Imports, Succeeded) -->
+ mercury_compile__compile_c_file(ErrorStream, ModuleName, Succeeded).
+build_object_code(ModuleName, asm, ErrorStream, _Imports, Succeeded) -->
+ mercury_compile__assemble(ErrorStream, ModuleName, Succeeded).
+build_object_code(ModuleName, java, ErrorStream, _Imports, Succeeded) -->
+ mercury_compile__compile_java_file(ErrorStream, ModuleName, Succeeded).
+build_object_code(ModuleName, il, ErrorStream, Imports, Succeeded) -->
+ mercury_compile__il_assemble(ErrorStream, ModuleName,
+ Imports ^ has_main, Succeeded).
+
+:- pred compile_foreign_code_file(io__output_stream::in, foreign_code_file::in,
+ bool::out, io__state::di, io__state::uo) is det.
+
+compile_foreign_code_file(ErrorStream, foreign_code_file(c, CFile, ObjFile),
+ Succeeded) -->
+ mercury_compile__compile_c_file(ErrorStream,
+ CFile, ObjFile, Succeeded).
+compile_foreign_code_file(ErrorStream, foreign_code_file(il, ILFile, DLLFile),
+ Succeeded) -->
+ mercury_compile__il_assemble(ErrorStream, ILFile, DLLFile,
+ no_main, Succeeded).
+compile_foreign_code_file(ErrorStream,
+ foreign_code_file(managed_cplusplus, MCPPFile, DLLFile),
+ Succeeded) -->
+ mercury_compile__compile_managed_cplusplus_file(ErrorStream,
+ MCPPFile, DLLFile, Succeeded).
+compile_foreign_code_file(ErrorStream,
+ foreign_code_file(csharp, CSharpFile, DLLFile),
+ Succeeded) -->
+ mercury_compile__compile_csharp_file(ErrorStream,
+ CSharpFile, DLLFile, Succeeded).
+
+%-----------------------------------------------------------------------------%
+
+:- pred call_mercury_compile_main(list(string)::in, bool::out,
+ io__state::di, io__state::uo) is det.
+
+call_mercury_compile_main(Args, Succeeded) -->
+ io__get_exit_status(Status0),
+ io__set_exit_status(0),
+ mercury_compile__main(Args),
+ io__get_exit_status(Status),
+ { Succeeded = ( Status = 0 -> yes ; no ) },
+ io__set_exit_status(Status0).
+
+:- pred invoke_mmc(io__output_stream::in, list(string)::in, bool::out,
+ io__state::di, io__state::uo) is det.
+
+invoke_mmc(ErrorStream, Args, Succeeded) -->
+ { CommandVerbosity = verbose }, % We've already written the command.
+ { Command = string__join_list(" ", ["mmc" | quote_args(Args)]) },
+ invoke_shell_command(ErrorStream, CommandVerbosity,
+ Command, Succeeded).
+
+%-----------------------------------------------------------------------------%
+
+record_made_target(TargetFile, CompilationTask, Succeeded, Info0, Info) -->
+ touched_files(TargetFile, CompilationTask, TouchedTargetFiles,
+ TouchedFiles, Info0, Info1),
+ record_made_target_2(Succeeded, TargetFile, TouchedTargetFiles,
+ TouchedFiles, Info1, Info).
+
+:- pred record_made_target_2(bool::in, target_file::in, list(target_file)::in,
+ list(file_name)::in, make_info::in, make_info::out,
+ io__state::di, io__state::uo) is det.
+
+record_made_target_2(Succeeded, TargetFile, TouchedTargetFiles,
+ OtherTouchedFiles, Info0, Info) -->
+ ( { Succeeded = yes } ->
+ { TargetStatus = up_to_date },
+ { Info1 = Info0 }
+ ;
+ { TargetStatus = error },
+ { Info1 = Info0 },
+ target_file_error(TargetFile)
+ ),
+
+ { list__foldl(update_target_status(TargetStatus),
+ TouchedTargetFiles, Info1, Info2) },
+
+ { DeleteTimestamp =
+ (pred(TouchedFile::in, MakeInfo0::in, MakeInfo::out) is det :-
+ MakeInfo = MakeInfo0 ^ file_timestamps :=
+ map__delete(MakeInfo0 ^ file_timestamps, TouchedFile)
+ ) },
+ list__map_foldl2(get_file_name, TouchedTargetFiles,
+ TouchedTargetFileNames, Info2, Info3),
+ { list__foldl(DeleteTimestamp, TouchedTargetFileNames, Info3, Info4) },
+ { list__foldl(DeleteTimestamp, OtherTouchedFiles, Info4, Info) }.
+
+:- pred update_target_status(dependency_status::in, target_file::in,
+ make_info::in, make_info::out) is det.
+
+update_target_status(TargetStatus, TargetFile, Info,
+ Info ^ dependency_status ^ elem(target(TargetFile)) := TargetStatus).
+
+%-----------------------------------------------------------------------------%
+
+:- type compilation_task_result == pair(compilation_task_type, list(string)).
+
+:- func compilation_task(globals, module_target_type) =
+ compilation_task_result.
+
+compilation_task(_, source) = _ :- error("compilation_task").
+compilation_task(_, errors) =
+ process_module(errorcheck) - ["--errorcheck_only"].
+compilation_task(_, unqualified_short_interface) =
+ process_module(make_short_interface) -
+ ["--make-short-interface"].
+compilation_task(Globals, short_interface) =
+ compilation_task(Globals, long_interface).
+compilation_task(_, long_interface) =
+ process_module(make_interface) - ["--make-interface"].
+compilation_task(_, private_interface) =
+ process_module(make_private_interface) -
+ ["--make-private-interface"].
+compilation_task(_, intermodule_interface) =
+ process_module(make_optimization_interface) -
+ ["--make-optimization-interface"].
+compilation_task(_, aditi_code) =
+ process_module(compile_to_target_code) - ["--aditi-only"].
+compilation_task(Globals, c_header) = compilation_task(Globals, c_code).
+compilation_task(_, c_code) = process_module(compile_to_target_code) -
+ ["--compile-to-c"].
+compilation_task(_, il_code) = process_module(compile_to_target_code) -
+ ["--il-only"].
+compilation_task(_, il_asm) = target_code_to_object_code - [].
+compilation_task(_, java_code) = process_module(compile_to_target_code) -
+ ["--java-only"].
+compilation_task(_, asm_code(PIC)) =
+ process_module(compile_to_target_code) -
+ ( PIC = pic -> ["--pic"] ; [] ).
+compilation_task(Globals, object_code(PIC)) =
+ target_code_to_object_code - Flags :-
+ globals__get_target(Globals, Target),
+ ( PIC = pic ->
+ Flags = ( Target = asm -> ["--pic"] ; ["--pic-reg"] )
+ ;
+ Flags = []
+ ).
+
+ % Find the files which could be touched by a compilation task.
+:- pred touched_files(target_file::in, compilation_task_type::in,
+ list(target_file)::out, list(file_name)::out,
+ make_info::in, make_info::out, io__state::di, io__state::uo) is det.
+
+touched_files(TargetFile, process_module(Task), TouchedTargetFiles,
+ TouchedFileNames, Info0, Info) -->
+ { TargetFile = ModuleName - FileType },
+ get_module_dependencies(ModuleName, MaybeImports, Info0, Info1),
+ { MaybeImports = yes(Imports0) ->
+ Imports = Imports0
+ ;
+ % This error should have been caught earlier.
+ % We shouldn't be attempting to build a target
+ % if we couldn't find the dependencies for the
+ % module.
+ error("touched_files: no module dependencies")
+ },
+
+ { NestedChildren = Imports ^ nested_children },
+ { SourceFileModuleNames = [ModuleName | NestedChildren] },
+
+ list__map_foldl2(get_module_dependencies, NestedChildren,
+ MaybeNestedImportsList, Info1, Info),
+ {
+ list__map(
+ (pred(yes(NestedModuleImports)::in,
+ NestedModuleImports::out) is semidet),
+ MaybeNestedImportsList, NestedImportsList)
+ ->
+ ModuleImportsList = [Imports | NestedImportsList]
+ ;
+ % This error should have been caught earlier.
+ % We shouldn't be attempting to build a target
+ % if we couldn't find the dependencies for the
+ % module or its nested sub-modules.
+ error("touched_files: no nested module dependencies")
+ },
+
+ globals__io_get_target(CompilationTarget),
+ { Task = compile_to_target_code, CompilationTarget = asm ->
+ % For `--target asm' the code for the nested children
+ % is placed in the `.s' file for the top-level module
+ % in the source file.
+ TargetModuleNames = [ModuleName]
+ ;
+ TargetModuleNames = SourceFileModuleNames
+ },
+
+ %
+ % Find out what header files are generated.
+ %
+ (
+ { Task = compile_to_target_code }
+ ->
+ list__map_foldl(external_foreign_code_files, ModuleImportsList,
+ ForeignCodeFileList),
+ { ForeignCodeFiles = list__map(
+ (func(ForeignFile) = ForeignFile ^ target_file),
+ list__condense(ForeignCodeFileList)) },
+ (
+ { CompilationTarget = c },
+ globals__io_lookup_bool_option(highlevel_code, HighLevelCode),
+ ( { HighLevelCode = yes } ->
+ %
+ % When compiling to high-level C, we always generate
+ % a header file.
+ %
+ { HeaderModuleNames = SourceFileModuleNames }
+ ;
+ %
+ % When compiling to low-level C, we only generate a
+ % header file if the module contains `:- pragma export'
+ % declarations.
+ %
+ { HeaderModuleNames =
+ list__filter_map(
+ (func(MImports) =
+ MImports ^ module_name is semidet :-
+ contains_foreign_export =
+ MImports ^ contains_foreign_export
+ ), ModuleImportsList) }
+ ),
+ { HeaderTargets = make_target_list(HeaderModuleNames,
+ c_header) }
+ ;
+ { CompilationTarget = asm },
+ %
+ % When compiling to assembler, we only generate
+ % a header file if the module contains foreign code.
+ %
+ { HeaderModuleNames =
+ list__filter_map(
+ (func(MImports) = MImports ^ module_name is semidet :-
+ contains_foreign_code(_) = MImports ^ foreign_code
+ ), ModuleImportsList) },
+ { HeaderTargets = make_target_list(HeaderModuleNames,
+ c_header) }
+ ;
+ { CompilationTarget = il },
+ { HeaderTargets = [] }
+ ;
+ { CompilationTarget = java },
+ { HeaderTargets = [] }
+ ),
+
+ { TouchedTargetFiles0 =
+ make_target_list(TargetModuleNames, FileType) },
+ { TouchedTargetFiles = TouchedTargetFiles0 ++ HeaderTargets }
+ ;
+ { Task = make_interface }
+ ->
+ % Both long and short interface files are produced
+ % when making the interface.
+ { ForeignCodeFiles = [] },
+ { TouchedTargetFiles =
+ make_target_list(TargetModuleNames, long_interface)
+ ++ make_target_list(TargetModuleNames, short_interface) }
+ ;
+ { ForeignCodeFiles = [] },
+ { TouchedTargetFiles =
+ make_target_list(TargetModuleNames, FileType) }
+ ),
+
+
+ list__foldl2(
+ (pred((TargetModuleName - TargetFileType)::in, TimestampFiles0::in,
+ TimestampFiles1::out, di, uo) is det -->
+ ( { TimestampExt = timestamp_extension(TargetFileType) } ->
+ module_name_to_file_name(TargetModuleName,
+ TimestampExt, no, TimestampFile),
+ { TimestampFiles1 =
+ [TimestampFile | TimestampFiles0] }
+ ;
+ { TimestampFiles1 = TimestampFiles0 }
+ )
+ ), TouchedTargetFiles, [], TimestampFileNames),
+
+ { TouchedFileNames = list__condense([ForeignCodeFiles,
+ TimestampFileNames]) }.
+
+touched_files(TargetFile, target_code_to_object_code,
+ [TargetFile], ForeignObjectFiles, Info0, Info) -->
+ { TargetFile = ModuleName - _ },
+ get_target_code_to_object_code_foreign_files(ModuleName,
+ ForeignCodeFileList, Info0, Info),
+ { ForeignObjectFiles = list__map(
+ (func(ForeignFile) = ForeignFile ^ object_file),
+ ForeignCodeFileList) }.
+
+:- pred get_target_code_to_object_code_foreign_files(module_name::in,
+ list(foreign_code_file)::out, make_info::in, make_info::out,
+ io__state::di, io__state::uo) is det.
+
+get_target_code_to_object_code_foreign_files(ModuleName, ForeignCodeFiles,
+ Info0, Info) -->
+ get_module_dependencies(ModuleName, MaybeImports, Info0, Info1),
+ { MaybeImports = yes(Imports0) ->
+ Imports = Imports0
+ ;
+ % This error should have been caught earlier.
+ % We shouldn't be attempting to build a target
+ % if we couldn't find the dependencies for the
+ % module.
+ error(
+"get_target_code_to_object_code_foreign_files: no module dependencies")
+ },
+
+ %
+ % For `--target asm' there is only one `.s' file per module
+ % so we should compile the foreign code for
+ %
+ globals__io_get_target(CompilationTarget),
+ ( { CompilationTarget = asm } ->
+ { NestedChildren = Imports ^ nested_children },
+
+ list__map_foldl2(get_module_dependencies, NestedChildren,
+ MaybeNestedImportsList, Info1, Info),
+ {
+ list__map(
+ (pred(yes(NestedModuleImports)::in,
+ NestedModuleImports::out) is semidet),
+ MaybeNestedImportsList, NestedImportsList)
+ ->
+ ModuleImportsList = [Imports | NestedImportsList]
+ ;
+ % This error should have been caught earlier.
+ % We shouldn't be attempting to build a target
+ % if we couldn't find the dependencies for the
+ % module or its nested sub-modules.
+ error(
+"get_target_code_to_object_code_foreign_files: no nested module dependencies")
+ }
+ ;
+ { Info = Info1 },
+ { ModuleImportsList = [Imports] }
+ ),
+ list__map_foldl(external_foreign_code_files,
+ ModuleImportsList, ForeignCodeFileLists),
+ { ForeignCodeFiles = list__condense(ForeignCodeFileLists) }.
+
+external_foreign_code_files(Imports, ForeignFiles) -->
+ %
+ % Find externally compiled foreign code files for
+ % `:- pragma foreign_proc' declarations.
+ %
+ globals__io_get_target(CompilationTarget),
+ { ModuleName = Imports ^ module_name },
+ (
+ { CompilationTarget = asm },
+ { Imports ^ foreign_code = contains_foreign_code(Langs) },
+ { set__member(c, Langs) }
+ ->
+ module_name_to_file_name(
+ foreign_language_module_name(ModuleName, c), ".c",
+ no, CCodeFileName),
+ module_name_to_file_name(
+ foreign_language_module_name(ModuleName, c), ".o",
+ no, ObjFileName),
+ { ForeignFiles0 =
+ [foreign_code_file(c, CCodeFileName, ObjFileName) ] }
+ ;
+ { CompilationTarget = il },
+ { Imports ^ foreign_code = contains_foreign_code(Langs) }
+ ->
+ list__map_foldl(external_foreign_code_files_for_il(ModuleName),
+ set__to_sorted_list(Langs), ForeignFilesList),
+ { list__condense(ForeignFilesList, ForeignFiles0) }
+ ;
+ { ForeignFiles0 = [] }
+ ),
+
+ %
+ % Find externally compiled foreign code files for fact tables.
+ %
+ ( { CompilationTarget = c ; CompilationTarget = asm } ->
+ list__map_foldl(
+ (pred(FactTableFile::in, FactTableForeignFile::out,
+ di, uo) is det -->
+ fact_table_file_name(ModuleName, FactTableFile,
+ ".c", FactTableCFile),
+ globals__io_lookup_string_option(
+ object_file_extension, ObjExt),
+ fact_table_file_name(ModuleName, FactTableFile,
+ ObjExt, FactTableObjFile),
+ { FactTableForeignFile = foreign_code_file(c,
+ FactTableCFile, FactTableObjFile) }
+ ), Imports ^ fact_table_deps, FactTableForeignFiles),
+ { ForeignFiles = ForeignFiles0 ++ FactTableForeignFiles }
+ ;
+ { ForeignFiles = ForeignFiles0 }
+ ).
+
+:- pred external_foreign_code_files_for_il(module_name::in,
+ foreign_language::in, list(foreign_code_file)::out,
+ io__state::di, io__state::uo) is det.
+
+external_foreign_code_files_for_il(ModuleName, Language,
+ ForeignFiles) -->
+ (
+ { ForeignModuleName = foreign_language_module_name(ModuleName,
+ Language) },
+ { ForeignExt = foreign_language_file_extension(Language) }
+ ->
+ module_name_to_file_name(ForeignModuleName, ForeignExt, no,
+ ForeignFileName),
+ module_name_to_file_name(ForeignModuleName, ".dll", no,
+ ForeignDLLFileName),
+ { ForeignFiles = [foreign_code_file(Language, ForeignFileName,
+ ForeignDLLFileName)] }
+ ;
+ % No external file is generated for this foreign language.
+ { ForeignFiles = [] }
+ ).
+
+%-----------------------------------------------------------------------------%
--------------------------------------------------------------------------
mercury-reviews mailing list
post: mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------
More information about the reviews
mailing list