[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