[m-rev.] for review: multiple foreign language support

Tyson Dowd trd at cs.mu.OZ.AU
Fri Jul 20 01:46:50 AEST 2001


Here's another round on this diff,

The big change is that we now generate dependencies for multiple
foreign languages,


--- zzlog.multi2	Wed Jul 18 14:24:52 2001
+++ zzlog.multi4	Thu Jul 19 17:27:41 2001
@@ -1,8 +1,8 @@
 
-Estimated hours taken: 8
+Estimated hours taken: 16
 Branches: main
 
-Support multiple language foreign_proc in the one file.
+Support multiple language foreign_procs in the one file.
 
 If there is more then one applicable foreign_proc for a
 given clause, select the most "preferred" programming
@@ -16,18 +16,24 @@
 	Rename backend_foreign_language as backend_foreign_languages,
 	and use it to record the list of foreign languages the selected
 	backend can handle.
+	Remove --use-foreign-language as it doesn't do anything right now.
 
 compiler/foreign.m:
 	Update code to use the list of backend foreign languages.
-	Add compare_foreign_language function, to compute the preferred
+	Add prefer_foreign_language function, to compute the preferred
 	foreign language ordering for each backend.
+	Move simple_foreign_language_string here from globals.m,
+	and add foreign_language_file_extension and
+	foreign_language_module_name functions.
+
 	(much of the rest of the code in this module is intended to deal with
 	the case where the backend *doesn't* handle the foreign
 	language, but we don't have any working support for that at the
 	moment).
 
 compiler/globals.m:
-	Add globals__io_get_backend_foreign_languages.
+	Add globals__io_get_backend_foreign_languages and
+	globals__get_backend_foreign_languages.
 
 compiler/make_hlds.m:
 	Handle selection of foreign_proc code depending upon the preferred
@@ -42,6 +48,14 @@
 	one language is selected for each predicate, but there can be
 	multiple languages in the onle module).
 	and put them in a map which is indexed on foreign language.
+
+compiler/modules.m:
+	Generate appropriate dependencies for foreign language modules.
+	We now record which languages a list of items uses (taking into
+	account the preferred foreign language for foreign_proc).
+	We also allow for the fact that some foreign_proc declarations
+	won't generate any external modules.
+


diff -u compiler/foreign.m compiler/foreign.m
--- compiler/foreign.m
+++ compiler/foreign.m
@@ -22,7 +22,7 @@
 :- import_module hlds_module, hlds_pred.
 :- import_module llds.
 
-:- import_module list.
+:- import_module list, bool.
 
 	% Filter the decls for the given foreign language. 
 	% The first return value is the list of matches, the second is
@@ -77,20 +77,40 @@
 	% Therefore, foreign languages have an order of preference, from most
 	% preferred to least perferred.
 	% prefer_foreign_language(Globals, Target, Lang1, Lang2) returns the
-	% result of comparison of Lang1 and Lang2 (given the supplied globals
-	% and compilation target).
+	% yes if Lang2 is preferred over Lang1.
 	%
-	% If neither language is preferred over the other, (=) will be
-	% returned.  This may be considered an error for many purposes.
-:- func foreign__compare_foreign_language(globals, compilation_target, 
-	foreign_language, foreign_language) = comparison_result.
+	% Otherwise it will return no.
+	
+:- func foreign__prefer_foreign_language(globals, compilation_target, 
+	foreign_language, foreign_language) = bool.
+
+	% A string representation of the foreign language suitable 
+	% for use in human-readable error messages
+:- func foreign_language_string(foreign_language) = string.
+
+	% A string representation of the foreign language suitable 
+	% for use in machine-readable name mangling.
+:- func simple_foreign_language_string(foreign_language) = string.
+
+	% The file extension used for this foreign language (including
+	% the dot).
+	% Not all foreign languages generate external files,
+	% so this function only succeeds for those that do.
+:- func foreign_language_file_extension(foreign_language) = string
+		is semidet.
+
+	% The module name used for this foreign language.
+	% Not all foreign languages generate external modules 
+	% so this function only succeeds for those that do.
+:- func foreign_language_module_name(module_name, foreign_language) =
+		module_name is semidet.
 
 :- implementation.
 
 :- import_module list, map, assoc_list, std_util, string, varset, int.
 :- import_module require.
 
-:- import_module hlds_pred, hlds_module, type_util, mode_util.
+:- import_module hlds_pred, hlds_module, type_util, mode_util, error_util.
 :- import_module code_model, globals.
 
 	% Currently we don't use the globals to compare foreign language
@@ -98,37 +118,39 @@
 	% to do this later.
 
 	% C is always preferred over any other language.
-compare_foreign_language(_Globals, c, Lang1, Lang2) = 
-	( Lang1 = c ->
-		(>)
-	; Lang2 = c ->
-		(<)
+prefer_foreign_language(_Globals, c, Lang1, Lang2) = 
+	( Lang2 = c, not Lang1 = c ->
+		yes
 	; 
-		(=)
+		no
 	).
 
 	% Same as for C
-compare_foreign_language(Globals, asm, Lang1, Lang2) = 
-	compare_foreign_language(Globals, c, Lang1, Lang2).
+prefer_foreign_language(Globals, asm, Lang1, Lang2) = 
+	prefer_foreign_language(Globals, c, Lang1, Lang2).
 
-	% First prefer csharp, then prefer managed_cplusplus, after
+	% First prefer il, then csharp, then prefer managed_cplusplus, after
 	% that we don't care.
-compare_foreign_language(_Globals, il, Lang1, Lang2) = 
-	( Lang1 = csharp ->
-		(>)
-	; Lang2 = csharp ->
-		(<)
-	; Lang1 = managed_cplusplus ->
-		(>)
-	; Lang1 = managed_cplusplus ->
-		(<)
+prefer_foreign_language(_Globals, il, Lang1, Lang2) = Comp :-
+	PreferredList = [il, csharp, managed_cplusplus],
+
+	FindLangPriority = (func(L) = X :-
+		( list__nth_member_search(PreferredList, L, X0) ->
+			X = X0
+		;
+			X = list__length(PreferredList) + 1
+		)),
+	N1 = FindLangPriority(Lang1),
+	N2 = FindLangPriority(Lang2),
+	( N2 < N1 ->
+		Comp = yes
 	;
-		(=)
+		Comp = no
 	).
 
 	% Nothing useful to do here, but when we add Java as a
 	% foreign language, we should add it here.
-compare_foreign_language(_Globals, java, _Lang1, _Lang2) = (=).
+prefer_foreign_language(_Globals, java, _Lang1, _Lang2) = no.
 
 
 foreign__filter_decls(WantedLang, Decls0, LangDecls, NotLangDecls) :-
@@ -141,88 +163,120 @@
 			WantedLang = Lang),
 		Bodys0, LangBodys, NotLangBodys).
 	
-foreign__extrude_pragma_implementation(TargetLang, _PragmaVars,
-		_PredName, _PredOrFunc, _Context,
+foreign__extrude_pragma_implementation([], _PragmaVars,
+	_PredName, _PredOrFunc, _Context, _ModuleInfo0, _Attributes, _Impl0, 
+	_ModuleInfo, _NewAttributes, _Impl) :-
+	unexpected(this_file, "no suitable target languages available").
+
+	% We just use the first target language for now, it might be nice
+	% to try a few others if the backend supports multiple ones.
+foreign__extrude_pragma_implementation([TargetLang | TargetLangs], 
+		_PragmaVars, _PredName, _PredOrFunc, _Context,
 		ModuleInfo0, Attributes, Impl0, 
 		ModuleInfo, NewAttributes, Impl) :-
 	foreign_language(Attributes, ForeignLanguage),
-	set_foreign_language(Attributes, TargetLang, NewAttributes),
-	( TargetLang = c ->
-		( ForeignLanguage = managed_cplusplus,
-			% This isn't finished yet, and we probably won't
-			% implement it for C calling MC++.
-			% For C calling normal C++ we would generate a proxy
-			% function in C++ (implemented in a piece of C++
-			% body code) with C linkage, and import that
-			% function.
-			% The backend would spit the C++ body code into
-			% a separate file.
-			% The code would look a little like this:
-			/*
-			NewName = make_pred_name(ForeignLanguage, PredName),
-			( PredOrFunc = predicate ->
-				ReturnCode = ""
-			;
-				ReturnCode = "ReturnVal = "
-			),
-			C_ExtraCode = "Some Extra Code To Run",
-			create_pragma_import_c_code(PragmaVars, ModuleInfo0,
-				"", VarString),
-			module_add_foreign_body_code(cplusplus, 
-				C_ExtraCode, Context, ModuleInfo0, ModuleInfo),
-			Impl = import(NewName, ReturnCode, VarString, no)
-			*/
-			error("unimplemented: calling MC++ foreign code from C backend")
-
-				
-		; ForeignLanguage = csharp,
-			error("unimplemented: calling C# foreign code from C backend")
-		; ForeignLanguage = il,
-			error("unimplemented: calling IL foreign code from C backend")
-		; ForeignLanguage = c,
-			Impl = Impl0,
-			ModuleInfo = ModuleInfo0
-		)
-	; TargetLang = managed_cplusplus ->
-			% Don't do anything - C and MC++ are embedded
-			% inside MC++ without any changes.
-		( ForeignLanguage = managed_cplusplus,
-			Impl = Impl0,
-			ModuleInfo = ModuleInfo0
-		; ForeignLanguage = csharp,
-			error("unimplemented: calling C# foreign code from MC++ backend")
-		; ForeignLanguage = il,
-			error("unimplemented: calling IL foreign code from MC++ backend")
-		; ForeignLanguage = c,
-			Impl = Impl0,
-			ModuleInfo = ModuleInfo0
-		)
-	; TargetLang = csharp ->
-		( ForeignLanguage = managed_cplusplus,
-			error("unimplemented: calling MC++ foreign code from MC++ backend")
-		; ForeignLanguage = csharp,
-			Impl = Impl0,
-			ModuleInfo = ModuleInfo0
-		; ForeignLanguage = c,
-			error("unimplemented: calling C foreign code from MC++ backend")
-		; ForeignLanguage = il,
-			error("unimplemented: calling IL foreign code from MC++ backend")
-		)
-	; TargetLang = il ->
-		( ForeignLanguage = managed_cplusplus,
-			error("unimplemented: calling MC++ foreign code from IL backend")
-		; ForeignLanguage = csharp,
-			error("unimplemented: calling C# foreign code from MC++ backend")
-		; ForeignLanguage = c,
-			error("unimplemented: calling C foreign code from MC++ backend")
-		; ForeignLanguage = il,
-			Impl = Impl0,
-			ModuleInfo = ModuleInfo0
-		)
+
+		% If the foreign language is available as a target language, 
+		% we don't need to do anything.
+	( list__member(ForeignLanguage, [TargetLang | TargetLangs]) ->
+		Impl = Impl0,
+		ModuleInfo = ModuleInfo0,
+		NewAttributes = Attributes
 	;
-		error("extrude_pragma_implementation: unsupported foreign language")
+		set_foreign_language(Attributes, TargetLang, NewAttributes),
+		extrude_pragma_implementation_2(TargetLang, ForeignLanguage,
+			ModuleInfo0, Impl0, ModuleInfo, Impl)
 	).
 
+
+:- pred extrude_pragma_implementation_2(
+	foreign_language::in, foreign_language::in,
+	module_info::in, pragma_foreign_code_impl::in,
+	module_info::out, pragma_foreign_code_impl::out) is det.
+
+	% This isn't finished yet, and we probably won't implement it for C
+	% calling MC++.  For C calling normal C++ we would generate a proxy
+	% function in C++ (implemented in a piece of C++ body code) with C
+	% linkage, and import that function.  The backend would spit the C++
+	% body code into a separate file.
+	% The code would look a little like this:
+	/*
+	NewName = make_pred_name(ForeignLanguage, PredName),
+	( PredOrFunc = predicate ->
+		ReturnCode = ""
+	;
+		ReturnCode = "ReturnVal = "
+	),
+	C_ExtraCode = "Some Extra Code To Run",
+	create_pragma_import_c_code(PragmaVars, ModuleInfo0, "", VarString),
+	module_add_foreign_body_code(cplusplus, 
+		C_ExtraCode, Context, ModuleInfo0, ModuleInfo),
+	Impl = import(NewName, ReturnCode, VarString, no)
+	*/
+
+extrude_pragma_implementation_2(c, managed_cplusplus, _, _, _, _) :-
+	unimplemented_combination(c, managed_cplusplus).
+
+extrude_pragma_implementation_2(c, csharp, _, _, _, _) :-
+	unimplemented_combination(c, csharp).
+
+extrude_pragma_implementation_2(c, il, _, _, _, _) :-
+	unimplemented_combination(c, il).
+
+extrude_pragma_implementation_2(c, c, ModuleInfo, Impl, ModuleInfo, Impl).
+
+
+		% Don't do anything - C and MC++ are embedded inside MC++
+		% without any changes.
+extrude_pragma_implementation_2(managed_cplusplus, managed_cplusplus,
+	ModuleInfo, Impl, ModuleInfo, Impl).
+
+extrude_pragma_implementation_2(managed_cplusplus, c,
+	ModuleInfo, Impl, ModuleInfo, Impl).
+
+extrude_pragma_implementation_2(managed_cplusplus, csharp, _, _, _, _) :-
+	unimplemented_combination(managed_cplusplus, csharp).
+
+extrude_pragma_implementation_2(managed_cplusplus, il, _, _, _, _) :-
+	unimplemented_combination(managed_cplusplus, il).
+
+
+
+extrude_pragma_implementation_2(csharp, csharp,
+	ModuleInfo, Impl, ModuleInfo, Impl).
+
+extrude_pragma_implementation_2(csharp, c, _, _, _, _) :-
+	unimplemented_combination(csharp, c).
+
+extrude_pragma_implementation_2(csharp, managed_cplusplus, _, _, _, _) :-
+	unimplemented_combination(csharp, managed_cplusplus).
+
+extrude_pragma_implementation_2(csharp, il, _, _, _, _) :-
+	unimplemented_combination(csharp, il).
+
+
+extrude_pragma_implementation_2(il, il,
+	ModuleInfo, Impl, ModuleInfo, Impl).
+
+extrude_pragma_implementation_2(il, c, _, _, _, _) :-
+	unimplemented_combination(il, c).
+
+extrude_pragma_implementation_2(il, managed_cplusplus, _, _, _, _) :-
+	unimplemented_combination(il, managed_cplusplus).
+
+extrude_pragma_implementation_2(il, csharp, _, _, _, _) :-
+	unimplemented_combination(il, csharp).
+
+
+
+:- pred unimplemented_combination(foreign_language::in, foreign_language::in)
+		is erroneous.
+
+unimplemented_combination(Lang1, Lang2) :-
+	error("unimplemented: calling " ++ foreign_language_string(Lang2)
+		++ " foreign code from " ++ foreign_language_string(Lang1)).
+
+
 	% XXX we haven't implemented these functions yet.
 	% What is here is only a guide
 :- func make_pred_name(foreign_language, sym_name) = string.
@@ -411,4 +465,36 @@
 
 	create_pragma_import_c_code(PragmaVars, ModuleInfo, C_Code3, C_Code).
 
+foreign_language_string(c) = "C".
+foreign_language_string(managed_cplusplus) = "Managed C++".
+foreign_language_string(csharp) = "C#".
+foreign_language_string(il) = "IL".
+
+simple_foreign_language_string(c) = "c".
+simple_foreign_language_string(managed_cplusplus) = "cpp". % XXX mcpp is better
+simple_foreign_language_string(csharp) = "csharp".
+simple_foreign_language_string(il) = "il".
+
+foreign_language_file_extension(c) = ".c".
+foreign_language_file_extension(managed_cplusplus) = ".cpp".
+foreign_language_file_extension(csharp) = ".cs".
+foreign_language_file_extension(il) = _ :- fail.
+
+foreign_language_module_name(M, L) = FM :-
+
+		% Only succeed if this language generates external files.
+	_ = foreign_language_file_extension(L),
+
+	Ending = "__" ++ simple_foreign_language_string(L) ++ "_code",
+	( M = unqualified(Name),
+		FM = unqualified(Name ++ Ending)
+	; M = qualified(Module, Name),
+		FM = qualified(Module, Name ++ Ending)
+	).
+
+
+
+
+:- func this_file = string.
+this_file = "foreign.m".
 
diff -u compiler/globals.m compiler/globals.m
--- compiler/globals.m
+++ compiler/globals.m
@@ -53,14 +53,6 @@
 :- pred convert_tags_method(string::in, tags_method::out) is semidet.
 :- pred convert_termination_norm(string::in, termination_norm::out) is semidet.
 
-	% A string representation of the foreign language suitable 
-	% for use in human-readable error messages
-:- func foreign_language_string(foreign_language) = string.
-
-	% A string representation of the foreign language suitable 
-	% for use in machine-readable name mangling.
-:- func simple_foreign_language_string(foreign_language) = string.
-
 %-----------------------------------------------------------------------------%
 
 	% Access predicates for the `globals' structure.
@@ -71,6 +63,8 @@
 
 :- pred globals__get_options(globals::in, option_table::out) is det.
 :- pred globals__get_target(globals::in, compilation_target::out) is det.
+:- pred globals__get_backend_foreign_languages(globals::in,
+		list(foreign_language)::out) is det.
 :- pred globals__get_gc_method(globals::in, gc_method::out) is det.
 :- pred globals__get_tags_method(globals::in, tags_method::out) is det.
 :- pred globals__get_termination_norm(globals::in, termination_norm::out) 
@@ -209,16 +203,6 @@
 convert_foreign_language_2("c sharp", csharp).
 convert_foreign_language_2("il", il).
 
-foreign_language_string(c) = "C".
-foreign_language_string(managed_cplusplus) = "Managed C++".
-foreign_language_string(csharp) = "C#".
-foreign_language_string(il) = "IL".
-
-simple_foreign_language_string(c) = "c".
-simple_foreign_language_string(managed_cplusplus) = "cpp". % XXX mcpp is better
-simple_foreign_language_string(csharp) = "csharp".
-simple_foreign_language_string(il) = "il".
-
 convert_gc_method("none", none).
 convert_gc_method("conservative", conservative).
 convert_gc_method("accurate", accurate).
@@ -258,6 +242,16 @@
 globals__get_trace_level(Globals, Globals ^ trace_level).
 globals__get_trace_suppress(Globals, Globals ^ trace_suppress_items).
 
+globals__get_backend_foreign_languages(Globals, ForeignLangs) :-
+	globals__lookup_accumulating_option(Globals, backend_foreign_languages,
+		LangStrs),
+	ForeignLangs = list__map(func(String) = ForeignLang :-
+		(convert_foreign_language(String, ForeignLang0) ->
+			ForeignLang = ForeignLang0
+		;
+			error("globals__io_get_backend_foreign_languages: invalid foreign_language string")
+		), LangStrs).
+
 globals__set_options(Globals, Options, Globals ^ options := Options).
 
 globals__set_trace_level(Globals, TraceLevel,
@@ -431,15 +425,8 @@
 	}.
 
 globals__io_get_backend_foreign_languages(ForeignLangs) -->
-	globals__io_lookup_accumulating_option(backend_foreign_languages,
-		LangStrs),
-	{ ForeignLangs = list__map(func(String) = ForeignLang :-
-		(convert_foreign_language(String, ForeignLang0) ->
-			ForeignLang = ForeignLang0
-		;
-			error("globals__io_get_backend_foreign_languages: invalid foreign_language string")
-		), LangStrs)
-	}.
+	globals__io_get_globals(Globals),
+	{ globals__get_backend_foreign_languages(Globals, ForeignLangs) }.
 
 globals__io_lookup_bool_option(Option, Value) -->
 	globals__io_get_globals(Globals),
diff -u compiler/handle_options.m compiler/handle_options.m
--- compiler/handle_options.m
+++ compiler/handle_options.m
@@ -46,7 +46,7 @@
 :- implementation.
 
 :- import_module options, globals, prog_io_util, trace_params, unify_proc.
-:- import_module prog_data.
+:- import_module prog_data, foreign.
 :- import_module char, int, string, map, set, getopt, library.
 
 handle_options(MaybeError, Args, Link) -->
@@ -701,25 +701,19 @@
 	% The preferred backend foreign language depends on the target.
 	( 	
 		{ Target = c },
-		{ BackendForeignLanguages = ["c"] },
-		{ DefaultForeignLanguage = foreign_language_string(c) }
+		{ BackendForeignLanguages = ["c"] }
 	;
 		{ Target = il },
-		{ BackendForeignLanguages = ["csharp", "mc++"] },
-		{ DefaultForeignLanguage =
-			foreign_language_string(managed_cplusplus) }
+		{ BackendForeignLanguages = ["csharp", "mc++"] }
 	;
 		{ Target = asm },
-		% Should add asm here too when it becomes available.
-		{ BackendForeignLanguages = ["c"] },
 		% XXX This is wrong!  It should be asm.
-		{ DefaultForeignLanguage = foreign_language_string(c) }
+		{ BackendForeignLanguages = ["c"] }
 	;
 		% XXX We don't generate java or handle it as a foreign
 		% language just yet, but if we did, we should fix this
 		{ Target = java },
-		{ BackendForeignLanguages = [] },
-		{ DefaultForeignLanguage = foreign_language_string(c) }
+		{ BackendForeignLanguages = [] }
 	),
 
 		% only set the backend foreign languages if they are unset
@@ -732,26 +726,6 @@
 			accumulating(BackendForeignLanguages))
 	;
 		[]
-	),
-
-	globals__io_lookup_string_option(use_foreign_language,
-		UseForeignLanguage),
-	( 
-		{ UseForeignLanguage = "" }
-	->
-		globals__io_set_option(use_foreign_language, 
-			string(DefaultForeignLanguage))
-	; 
-		{ convert_foreign_language(UseForeignLanguage, FL) }
-	->
-		{ CanonicalLangName = foreign_language_string(FL) },
-		globals__io_set_option(use_foreign_language, 
-			string(CanonicalLangName))
-	;
-		usage_error(
-			string__format(
-			"unrecognized foreign language argument `%s' for --use-foreign-language",
-			[s(UseForeignLanguage)]))
 	),
 
 	( { HighLevel = no } ->
diff -u compiler/hlds_out.m compiler/hlds_out.m
--- compiler/hlds_out.m
+++ compiler/hlds_out.m
@@ -260,7 +260,7 @@
 :- import_module code_util, llds, llds_out, trace.
 
 % Misc
-:- import_module globals, options.
+:- import_module globals, options, foreign.
 
 % Standard library modules
 :- import_module int, string, set, assoc_list, map, multi_map.
diff -u compiler/make_hlds.m compiler/make_hlds.m
--- compiler/make_hlds.m
+++ compiler/make_hlds.m
@@ -5296,12 +5296,12 @@
 		LangClauses = [ForeignLang - ClauseNumber | Rest], 
 		ForeignLang = foreign_language(OldLang),
 		( Rest = [] ->
-			Compare = foreign__compare_foreign_language(Globals,
+			Compare = foreign__prefer_foreign_language(Globals,
 				Target, OldLang, NewLang),
 			( 
 				% This language is preferred to the old
 				% language, so we should replace it
-				Compare = (<) ->
+				Compare = yes ->
 				UpdateClauses = 
 					(pred(NewCl::in, Cs::out) is det :-
 					list__replace_nth_det(ClauseList,
diff -u compiler/options.m compiler/options.m
--- compiler/options.m
+++ compiler/options.m
@@ -200,12 +200,6 @@
 		;       unboxed_no_tag_types
 		;	sync_term_size % in words
 		;	type_layout
-	% Foreign language interface options
-				% The foreign language that the user has
-				% selected for use in this module
-				% (defaults to the value of backend
-				% foreign target).
-		;	use_foreign_language
 	% Options for internal use only
 	% (the values of these options are implied by the
 	% settings of other options)
@@ -621,7 +615,6 @@
 					% of writing) - will usually be over-
 					% ridden by a value from configure.
 	type_layout		-	bool(yes),
-	use_foreign_language	-	string(""),
 	backend_foreign_languages-	accumulating([]),
 					% The previous two options
 					% depend on the target and are
@@ -1030,7 +1023,6 @@
 long_option("bytes-per-word",		bytes_per_word).
 long_option("conf-low-tag-bits",	conf_low_tag_bits).
 long_option("type-layout",		type_layout).
-long_option("use-foreign-language",	use_foreign_language).
 long_option("backend-foreign-languages",
 					backend_foreign_languages).
 long_option("agc-stack-layout",		agc_stack_layout).
only in patch2:
--- compiler/modules.m	2001/07/18 12:08:43	1.178
+++ compiler/modules.m	2001/07/19 15:23:33
@@ -276,7 +276,7 @@
 				% in this module.
 		foreign_code :: contains_foreign_code,
 				% Whether or not the module contains
-				% foreign code
+				% foreign code (and which languages if it does)
 		items :: item_list,
 				% The contents of the module and its imports
 		error :: module_error,
@@ -290,7 +290,7 @@
 	).
 
 :- type contains_foreign_code
-	--->	contains_foreign_code
+	--->	contains_foreign_code(set(foreign_language))
 	;	no_foreign_code
 	;	unknown.
 
@@ -614,7 +614,7 @@
 
 :- implementation.
 :- import_module llds_out, passes_aux, prog_out, prog_util, mercury_to_mercury.
-:- import_module prog_io_util, options, module_qual.
+:- import_module prog_io_util, options, module_qual, foreign.
 :- import_module recompilation_version.
 
 :- import_module string, map, term, varset, dir, library.
@@ -2032,60 +2032,23 @@
 				SourceFileName, "\n\n"
 		]),
 
-		% Generate the following dependency.  This dependency is
-		% needed because module__cpp_code.dll might refer to
-		% high level data in any of the mercury modules it
-		% imports plus itself.
-		%
-		% 	module__cpp_code.dll : module.dll imports.dll
-		% 
-		%
-		% Generate the following sequence of rules which state
-		% how to generate the module__cpp_code.dll.
-		%
-		%	module__cpp_code.dll : module__cpp_code.cpp
-		%	module__cpp_code.cpp : module.il
-		%
 		globals__io_get_target(Target),
+		globals__io_get_globals(Globals),
 		(
 			{ Target = il },
 			{
-				ContainsForeignCode = contains_foreign_code
+				ContainsForeignCode = 
+					contains_foreign_code(LangSet)
 			;
 				ContainsForeignCode = unknown,
-				item_list_contains_foreign_code(Items)
+				get_item_list_foreign_code(Globals, Items,
+					LangSet),
+				not set__empty(LangSet)
 			}
 		->
-			globals__io_lookup_foreign_language_option(
-					backend_foreign_language, ForeignLang),
-			{ ForeignExt = simple_foreign_language_string(
-					ForeignLang) },
-			{ ForeignCodeExt = "__" ++ ForeignExt ++ "_code." },
-			module_name_to_file_name(ModuleName,
-					ForeignCodeExt ++ ForeignExt,
-					no, ForeignFileName),
-			module_name_to_file_name(ModuleName, ".il", no,
-					IlFileName),
-			module_name_to_file_name(ModuleName, ".dll", no,
-					DllFileName),
-			module_name_to_file_name(ModuleName,
-					ForeignCodeExt ++ "dll",
-					no, ForeignDllFileName),
-
-			io__write_strings(DepStream, [
-				ForeignDllFileName, " : ", DllFileName]),
-			% XXX This change doesn't work correctly because
-			% mmake can't find the dlls which don't reside
-			% in the current directory.
-			/*
-			write_dll_dependencies_list(ModuleName,
-					AllDeps, DepStream),
-			*/
-			io__nl(DepStream),
-
-			io__write_strings(DepStream, [
-				ForeignDllFileName, " : ", ForeignFileName,"\n",
-				ForeignFileName, " : ", IlFileName, "\n\n"])
+			{ Langs = set__to_sorted_list(LangSet) },
+			list__foldl(write_foreign_dependency_for_il(DepStream,
+				ModuleName), Langs)
 		;
 			[]
 		),
@@ -2236,6 +2199,58 @@
 		)
 	).
 
+	% Generate the following dependency.  This dependency is
+	% needed because module__cpp_code.dll might refer to
+	% high level data in any of the mercury modules it
+	% imports plus itself.
+	%
+	% For example, for MC++ we generate:
+	%
+	% 	<module>__cpp_code.dll : <module>.dll <imports>.dll
+	% 
+	%
+	% Generate the following sequence of rules which state
+	% how to generate the module__cpp_code.dll.
+	%
+	% For example, for MC++ we generate:
+	%
+	%	<module>__cpp_code.dll : <module>__cpp_code.cpp
+	%	<module>__cpp_code.cpp : <module>.il
+	%
+:- pred write_foreign_dependency_for_il(io__output_stream::in, sym_name::in,
+		foreign_language::in, io__state::di, io__state::uo) is det.
+write_foreign_dependency_for_il(DepStream, ModuleName, ForeignLang) -->
+	( 
+		{ ForeignModuleName = foreign_language_module_name(
+			ModuleName, ForeignLang) },
+		{ ForeignExt = foreign_language_file_extension(ForeignLang) }
+	->
+		module_name_to_file_name(ForeignModuleName, ForeignExt, no,
+			ForeignFileName),
+		module_name_to_file_name(ModuleName, ".il", no, IlFileName),
+		module_name_to_file_name(ModuleName, ".dll", no, DllFileName),
+		module_name_to_file_name(ForeignModuleName, ".dll", no,
+			ForeignDllFileName),
+
+		io__write_strings(DepStream, [ForeignDllFileName,
+			" : ", DllFileName]),
+			% XXX This change doesn't work correctly because
+			% mmake can't find the dlls which don't reside
+			% in the current directory.
+		/*
+		write_dll_dependencies_list(ModuleName, AllDeps, DepStream),
+		*/
+		io__nl(DepStream),
+
+		io__write_strings(DepStream, [
+			ForeignDllFileName, " : ", ForeignFileName,"\n",
+			ForeignFileName, " : ", IlFileName, "\n\n"])
+	;
+		% This foreign language doesn't generate an external file
+		% so there are no dependencies to generate.
+		[]
+	).
+
 maybe_read_dependency_file(ModuleName, MaybeTransOptDeps) -->
 	globals__io_lookup_bool_option(transitive_optimization, TransOpt),
 	( { TransOpt = yes } ->
@@ -2922,15 +2937,12 @@
 	io__write_string(DepStream, "\n"),
 
 	globals__io_get_target(Target),
-	globals__io_lookup_foreign_language_option(
-			backend_foreign_language, ForeignLang),
-	{ ForeignExt = "." ++ simple_foreign_language_string(ForeignLang) },
 	( { Target = il } ->
-		{ ForeignModules = foreign_modules(ForeignLang,
-				Modules, DepsMap) }
+		{ ForeignModulesAndExts = foreign_modules(Modules, DepsMap) }
 	;
-		{ ForeignModules = [] }
+		{ ForeignModulesAndExts = [] }
 	),
+	{ ForeignModules = assoc_list__keys(ForeignModulesAndExts) },
 	io__write_string(DepStream, MakeVarName),
 	io__write_string(DepStream, ".foreign ="),
 	write_dependencies_list(ForeignModules, "", DepStream),
@@ -2950,12 +2962,19 @@
 
 	{ get_extra_link_objects(Modules, DepsMap, Target, ExtraLinkObjs) },
 
+
+	{ MakeFileName = (pred(M - E::in, F::out, di, uo) is det -->
+		module_name_to_file_name(M, E, yes, F0),
+		{ F = "$(os_subdir)" ++ F0 }
+	) },
+
+	list__map_foldl(MakeFileName, ForeignModulesAndExts, ForeignFileNames),
+
 		% .foreign_cs are the source files which have had
 		% foreign code placed in them.
 	io__write_string(DepStream, MakeVarName),
 	io__write_string(DepStream, ".foreign_cs = "),
-	write_compact_dependencies_list(ForeignModules, "$(os_subdir)",
-					ForeignExt, ForeignBasis, DepStream),
+	write_file_dependencies_list(ForeignFileNames, "", DepStream),
 	io__write_string(DepStream, "\n"),
 
 		% The dlls which contain the foreign_code.
@@ -3692,30 +3711,45 @@
 modules_that_need_headers(Modules, DepsMap) =
 	list__filter(module_needs_header(DepsMap), Modules).
 
-:- func foreign_modules(foreign_language, list(module_name), deps_map)  =
-		list(module_name).
 
-foreign_modules(ForeignLang, Modules, DepsMap) = ForeignModules :-
-	P = (pred(M::in, FM::out) is semidet :-
-		Ext = "__" ++ simple_foreign_language_string(ForeignLang) ++
-				"_code",
-		module_needs_header(DepsMap, M),
-		( M = unqualified(Name),
-			FM = unqualified(Name ++ Ext)
-		; M = qualified(Module, Name),
-			FM = qualified(Module, Name ++ Ext)
-		)
+
+	% Find out which modules will generate as external foreign
+	% language files. 
+	% We return the module names and file extensions.
+:- func foreign_modules(list(module_name), deps_map) =
+		assoc_list(module_name, string).
+
+foreign_modules(Modules, DepsMap) = ForeignModules :-
+	P = (pred(M::in, FMs::out) is semidet :-
+		module_has_foreign(DepsMap, M, LangList),
+		FMs = list__filter_map((func(L) = (NewM - Ext) is semidet :-
+			NewM = foreign_language_module_name(M, L),
+			Ext = foreign_language_file_extension(L)
+		), LangList)
 	),
-	list__filter_map(P, Modules, ForeignModules).
+	list__filter_map(P, Modules, ForeignModulesList),
+	ForeignModules = list__condense(ForeignModulesList).
 
 	% Succeed iff we need to generate a C header file for the specified
 	% module, assuming we're compiling with `--target asm'.
 :- pred module_needs_header(deps_map::in, module_name::in) is semidet.
 
 module_needs_header(DepsMap, Module) :-
+	map__lookup(DepsMap, Module, deps(_, ModuleImports)),
+	ModuleImports ^ foreign_code = contains_foreign_code(Langs),
+	set__member(c, Langs).
+
+	% Succeed iff we need to generate a foreign language output file 
+	% for the specified module.
+:- pred module_has_foreign(deps_map::in, module_name::in,
+		list(foreign_language)::out) is semidet.
+
+module_has_foreign(DepsMap, Module, LangList) :-
 	map__lookup(DepsMap, Module, deps(_, ModuleImports)),
-	ModuleImports ^ foreign_code = contains_foreign_code.
+	ModuleImports ^ foreign_code = contains_foreign_code(Langs),
+	LangList = set__to_sorted_list(Langs).
 
+
 	% get_extra_link_objects(Modules, DepsMap, Target, ExtraLinkObjs) },
 	% Find any extra .$O files that should be linked into the executable.
 	% These include fact table object files and object files for foreign
@@ -3755,7 +3789,8 @@
 	%
 	(
 		Target = asm,
-		( ModuleImports ^ foreign_code = contains_foreign_code
+		( ModuleImports ^ foreign_code = contains_foreign_code(Langs),
+		  set__member(c, Langs)
 		; FactTableObjs \= []
 		)
 	->
@@ -3769,33 +3804,85 @@
 	get_extra_link_objects_2(Modules, DepsMap, Target, ExtraLinkObjs1, 
 		ExtraLinkObjs).
 
-:- pred item_list_contains_foreign_code(item_list::in) is semidet.
+:- pred get_item_list_foreign_code(globals::in, item_list::in,
+		set(foreign_language)::out) is det.
 
-item_list_contains_foreign_code([Item|Items]) :-
-	(
-		Item = pragma(Pragma) - _Context,
-		% The code here should match the way that mlds_to_gcc.m
-		% decides whether or not to call mlds_to_c.m.
-		% XXX Note that we do NOT count foreign_decls here.
-		% We only link in a foreign object file if mlds_to_gcc
-		% called mlds_to_c.m to generate it, which it will only
-		% do if there is some foreign_code, not just foreign_decls.
-		% Counting foreign_decls here causes problems with
-		% intermodule optimization.
-		(	Pragma = foreign_code(_Lang, _)
-		;	Pragma = foreign_proc(_, _, _, _, _, _)
-		;	% XXX `pragma export' should not be treated as
-			% foreign, but currently mlds_to_gcc.m doesn't
-			% handle that declaration, and instead just punts
-			% it on to mlds_to_c.m, thus generating C code for
-			% it, rather than assembler code.  So we need to
-			% treat `pragma export' like the other pragmas for
-			% foreign code.
-			Pragma = export(_, _, _, _)
-		)
-	;
-		item_list_contains_foreign_code(Items)
-	).
+get_item_list_foreign_code(Globals, Items, LangSet) :-
+	globals__get_backend_foreign_languages(Globals, BackendLangs),
+	globals__get_target(Globals, Target),
+	list__foldl2((pred(Item::in, Set0::in, Set::out, Seen0::in, Seen::out)
+			is det :-
+		(
+			Item = pragma(Pragma) - _Context
+		->
+			% The code here should match the way that mlds_to_gcc.m
+			% decides whether or not to call mlds_to_c.m.  XXX Note
+			% that we do NOT count foreign_decls here.  We only
+			% link in a foreign object file if mlds_to_gcc called
+			% mlds_to_c.m to generate it, which it will only do if
+			% there is some foreign_code, not just foreign_decls.
+			% Counting foreign_decls here causes problems with
+			% intermodule optimization.
+			(	
+				Pragma = foreign_code(Lang, _) 
+			->
+				set__insert(Set0, Lang, Set),
+				Seen = Seen0
+			;	
+				Pragma = foreign_proc(Attrs, Name, _, _, _, _)
+			->
+				foreign_language(Attrs, NewLang),
+				( OldLang = map__search(Seen0, Name) ->
+						% is it better than an existing
+					( 
+					  yes = prefer_foreign_language(
+						Globals, Target, OldLang,
+						NewLang)
+					->
+						map__set(Seen0, Name,
+							NewLang, Seen)
+					;
+						Seen = Seen0
+					)
+				;
+						% is it one of the languages
+						% we support?
+					( 
+						list__member(NewLang,
+							BackendLangs)
+					->
+						map__det_insert(Seen0, Name,
+							NewLang, Seen)
+					;
+						Seen = Seen0
+					)
+				),
+				Set = Set0
+			;	
+				% XXX `pragma export' should not be treated as
+				% foreign, but currently mlds_to_gcc.m doesn't
+				% handle that declaration, and instead just
+				% punts it on to mlds_to_c.m, thus generating C
+				% code for it, rather than assembler code.  So
+				% we need to treat `pragma export' like the
+				% other pragmas for foreign code.
+				Pragma = export(_, _, _, _)
+			->
+				% XXX we assume lang = c for exports
+				Lang = c,
+				set__insert(Set0, Lang, Set),
+				Seen = Seen0
+			;
+				Set = Set0,
+				Seen = Seen0
+			)
+		;
+			Set = Set0,
+			Seen = Seen0
+		)), Items, set__init, LangSet0, map__init, LangMap),
+		Values = map__values(LangMap),
+		LangSet = set__insert_list(LangSet0, Values).
 
 %-----------------------------------------------------------------------------%
 
@@ -4060,8 +4147,12 @@
 	globals__get_target(Globals, Target),
only in patch2:
--- compiler/mlds_to_il.m	2001/07/18 10:20:55	1.54
+++ compiler/mlds_to_il.m	2001/07/19 15:23:30
@@ -138,7 +138,7 @@
 :- import_module globals, options, passes_aux.
 :- import_module builtin_ops, c_util, modules, tree.
 :- import_module prog_data, prog_out, llds_out.
-:- import_module rtti, type_util, code_model.
+:- import_module rtti, type_util, code_model, foreign.
 
 :- import_module ilasm, il_peephole.
 :- import_module ml_util, ml_code_util, error_util.
@@ -2671,7 +2671,7 @@
 :- mode mangle_foreign_code_module(in, in, out) is det.
 
 mangle_foreign_code_module(ModuleName0, Lang, ModuleName) :-
-	LangStr = globals__simple_foreign_language_string(Lang),
+	LangStr = simple_foreign_language_string(Lang),
 	PackageName0 = mlds_module_name_to_package_name(ModuleName0),
 	( 
 		PackageName0 = qualified(Q, M0),
only in patch2:
--- compiler/mercury_to_mercury.m	2001/06/27 05:04:14	1.188
+++ compiler/mercury_to_mercury.m	2001/07/19 15:23:24
@@ -226,7 +226,7 @@
 
 :- import_module prog_out, prog_util, hlds_pred, hlds_out, instmap.
 :- import_module recompilation_version, purity, term_util.
-:- import_module globals, options, termination.
+:- import_module globals, options, termination, foreign.
 
 :- import_module assoc_list, char, int, string, set, lexer, require.
 :- import_module term, term_io, varset.
only in patch2:
--- compiler/mercury_compile.m	2001/07/16 08:21:00	1.211
+++ compiler/mercury_compile.m	2001/07/19 15:23:24
@@ -2937,9 +2937,8 @@
 	% XXX this should perhaps be part of backend_pass
 	% rather than output_pass.
 	%
-	globals__io_lookup_foreign_language_option(use_foreign_language,
-		UseForeignLanguage),
-	{ get_c_interface_info(HLDS, UseForeignLanguage, C_InterfaceInfo) },
+	% XXX We assume that the foreign language we use is C
+	{ get_c_interface_info(HLDS, c, C_InterfaceInfo) },
 	{ global_data_get_all_proc_vars(GlobalData, GlobalVars) },
 	{ global_data_get_all_non_common_static_data(GlobalData,
 		NonCommonStaticData) },

 compiler/hlds_pred.m:
 	Add an extra field to clause which records which language this


--------------------------------------------------------------------------
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