[m-dev.] C++ interface

Tyson Dowd trd at cs.mu.OZ.AU
Thu Jun 13 12:46:53 AEST 2002


On 08-Jun-2002, Roberto Bagnara <bagnara at cs.unipr.it> wrote:
> 
> Hi there,
> 
> I thought the message I sent to mercury-developers on March 9 was left
> unanswered, but I was wrong: simply the answers were sent to the list only.
> So, please accept my apologies for this long delay.
> 
> Yes, I am interested in directly interfacing a C++ library with Mercury,
> and I am willing to work with an experimental version as long as I can
> be reasonably confident that the experimental features I am using will be
> available in, say, the next Mercury release.
> If you could direct me to the sources/patches I should use, I am willing
> to start working as soon as possible.
> All the best

Code that does this on the current CVS Mercury compiler (should apply
pretty cleanly to any recent release of the day) is attached.

It is does not yet work cleanly with Mmake, but it works reasonably well
with the mmc command line compiler.

I suspect it will make it into the next release of the Mercury compiler,
but it's not clear how much work is remaining before it can pass review.

-- 
       Tyson Dowd           # 
                            #  Surreal humour isn't everyone's cup of fur.
     trd at cs.mu.oz.au        # 
http://www.cs.mu.oz.au/~trd #
-------------- next part --------------
Index: compiler/compile_target_code.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/compile_target_code.m,v
retrieving revision 1.12
diff -u -r1.12 compile_target_code.m
--- compiler/compile_target_code.m	12 Jun 2002 14:26:47 -0000	1.12
+++ compiler/compile_target_code.m	13 Jun 2002 01:02:00 -0000
@@ -64,6 +64,17 @@
 		file_name, file_name, bool, io__state, io__state).
 :- mode compile_managed_cplusplus_file(in, in, in, out, di, uo) is det.
 
+	% compile_cplusplus_file(ErrorStream, ModuleName, Succeeded).
+:- pred compile_cplusplus_file(io__output_stream, module_name,
+		bool, io__state, io__state).
+:- mode compile_cplusplus_file(in, in, out, di, uo) is det.
+
+	% compile_cplusplus_file(ErrorStream,
+	%		CPPFile, OFile, Succeeded).
+:- pred compile_cplusplus_file(io__output_stream,
+		file_name, file_name, bool, io__state, io__state).
+:- mode compile_cplusplus_file(in, in, in, out, di, uo) is det.
+
 	% compile_csharp_file(ErrorStream, C#File, DLLFile, Succeeded).
 :- pred compile_csharp_file(io__output_stream, file_name, file_name,
 		bool, io__state, io__state).
@@ -197,6 +208,35 @@
 	{ string__append_list([ILASM, " ", SignOpt, VerboseOpt, DebugOpt,
 		TargetOpt, ILASMFlags, " /out=", TargetFile,
 		" ", IL_File], Command) },
+	invoke_system_command(ErrorStream, verbose_commands,
+		Command, Succeeded).
+
+compile_cplusplus_file(ErrorStream, ModuleName, Succeeded) -->
+	module_name_to_file_name(ModuleName, "__cpp_code.cpp", yes, C_File),
+	globals__io_lookup_string_option(object_file_extension, ObjExt),
+	module_name_to_file_name(ModuleName, ObjExt, yes, O_File),
+	compile_cplusplus_file(ErrorStream, C_File, O_File, Succeeded).
+
+compile_cplusplus_file(ErrorStream,
+		CPPFileName, OFileName, Succeeded) -->
+	globals__io_lookup_bool_option(verbose, Verbose),
+	maybe_write_string(Verbose, "% Compiling `"),
+	maybe_write_string(Verbose, CPPFileName),
+	maybe_write_string(Verbose, "':\n"),
+	globals__io_lookup_string_option(cpp_compiler, CPP),
+	globals__io_lookup_accumulating_option(cpp_flags, CPPFlagsList),
+	{ join_string_list(CPPFlagsList, "", "", " ", CPPFlags) },
+
+	globals__io_lookup_accumulating_option(c_include_directory,
+	 	C_Incl_Dirs),
+	{ InclOpts = string__append_list(list__condense(list__map(
+	 	(func(C_INCL) = ["-I", C_INCL, " "]), C_Incl_Dirs))) },
+
+	globals__io_lookup_string_option(c_flag_to_name_object_file,
+			NameObjectFile),
+	{ string__append_list([CPP, " ", InclOpts, CPPFlags,
+		" -c ", CPPFileName, " ", NameObjectFile, OFileName],
+		Command) },
 	invoke_system_command(ErrorStream, verbose_commands,
 		Command, Succeeded).
 
Index: compiler/foreign.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/foreign.m,v
retrieving revision 1.16
diff -u -r1.16 foreign.m
--- compiler/foreign.m	30 May 2002 08:00:01 -0000	1.16
+++ compiler/foreign.m	13 Jun 2002 00:47:00 -0000
@@ -1,4 +1,4 @@
-%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------
 % Copyright (C) 2000-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.
@@ -21,7 +21,21 @@
 :- import_module parse_tree__prog_data, libs__globals.
 :- import_module hlds__hlds_module, hlds__hlds_pred.
 
-:- import_module bool, list, string, term.
+:- import_module bool, list, string, term, io, assoc_list, std_util.
+
+% foreign_interface_info holds information used when generating
+% code that uses the foreign language interface.
+:- type foreign_interface_info
+	---> foreign_interface_info(
+		module_name,
+		% info about stuff imported from C:
+		foreign_decl_info,
+		foreign_import_module_info,
+		foreign_body_info,
+		% info about stuff exported to C:
+		foreign_export_decls,
+		foreign_export_defns
+	).
 
 :- type foreign_decl_info ==	list(foreign_decl_code).	
 		% in reverse order
@@ -31,12 +45,17 @@
 		% in reverse order
 
 :- type foreign_decl_code	--->	
-		foreign_decl_code(foreign_language, string, prog_context).
+		foreign_decl_code(foreign_language, foreign_code_fragments).
+
 :- type foreign_import_module	--->
 		foreign_import_module(foreign_language, module_name,
 			prog_context).
+
 :- type foreign_body_code	--->
-		foreign_body_code(foreign_language, string, prog_context).
+		foreign_body_code(foreign_language, 
+			foreign_code_fragments).
+
+:- type foreign_code_fragments == assoc_list(string, maybe(prog_context)).
 
 :- type foreign_export_defns == list(foreign_export).
 :- type foreign_export_decls == list(foreign_export_decl).
@@ -117,13 +136,14 @@
 	% code.
 	% XXX This implementation is currently incomplete, so in future
 	% this interface may change.
-:- pred foreign__extrude_pragma_implementation(list(foreign_language),
-		list(pragma_var), sym_name, pred_or_func, prog_context,
+:- pred foreign__piggyback_pragma_implementation(list(foreign_language),
+		list(pragma_var), list(type), 
+		sym_name, pred_or_func, prog_context,
 		module_info, pragma_foreign_proc_attributes,
 		pragma_foreign_code_impl, 
 		module_info, pragma_foreign_proc_attributes,
 		pragma_foreign_code_impl).
-:- mode foreign__extrude_pragma_implementation(in, in, in, in, in,
+:- mode foreign__piggyback_pragma_implementation(in, in, in, in, in, in,
 		in, in, in, out, out, out) is det.
 
 	% make_pragma_import turns pragma imports into pragma foreign_code.
@@ -160,11 +180,16 @@
 	% for use in machine-readable name mangling.
 :- func simple_foreign_language_string(foreign_language) = string.
 
+	% A string representation of the foreign language which can
+	% be used to specify the foreign language in Mercury syntax
+:- func foreign_language_specification_string(foreign_language) = string.
+
 	% Sub-type of foreign_language for languages for which
 	% we generate external files for foreign code.
 :- inst lang_gen_ext_file 
 	--->	c
 	;	managed_cplusplus
+	;	cplusplus
 	;	csharp
 	.
 
@@ -184,15 +209,220 @@
 :- mode foreign_language_module_name(in, in) = out is semidet.
 :- mode foreign_language_module_name(in, in(lang_gen_ext_file)) = out is det.
 
+:- pred piggyback_languages(list(foreign_language)::in, 
+		list(foreign_language)::out) is det.
+
+	% can_piggyback_language(X, Y) is true iff we can generate code to 
+	% call language Y from language X
+:- pred can_piggyback_language(foreign_language, foreign_language).
+:- mode can_piggyback_language(in, out) is multi.
+:- mode can_piggyback_language(in, in) is semidet.
+
+
+	% XXX TYSE should these two preds really live here?
+:- pred foreign__output_interface_info(
+	foreign_language::in, foreign_interface_info::in,
+	io__state::di, io__state::uo) is det.
+
+:- pred foreign__output_c_code_fragments(foreign_code_fragments,
+		io, io).
+:- mode foreign__output_c_code_fragments(in, di, uo) is det.
+
+:- func foreign__fragments_to_string(foreign_code_fragments) = string.
+
+:- pred foreign__compile_foreign_file(io__output_stream::in,
+		foreign_language::in, module_name::in, bool::out,
+		io__state::di, io__state::uo) is det.
+
+:- pred foreign__interface_info_generates_output(
+		foreign_interface_info::in) is semidet.
+
+:- func foreign__body_info_to_body_code(foreign_language, foreign_body_info) = 
+		list(user_foreign_code).
+
 :- implementation.
 
 :- import_module list, map, assoc_list, std_util, string, varset, int, term.
-:- import_module require.
+:- import_module require, library, getopt.
 
 :- import_module hlds__hlds_pred, hlds__hlds_module, check_hlds__type_util.
 :- import_module check_hlds__mode_util, hlds__error_util.
 :- import_module hlds__hlds_data, parse_tree__prog_out.
-:- import_module backend_libs__code_model, libs__globals.
+:- import_module hlds__passes_aux, parse_tree__modules.
+:- import_module backend_libs__code_model, libs__globals, libs__options.
+:- import_module backend_libs__c_util, backend_libs__compile_target_code.
+
+%-----------------------------------------------------------------------------%
+
+	% XXX reuse the code below to generate names of _c_code and
+	% stuff more elegantly.
+foreign__compile_foreign_file(ErrorStream, Lang, ModuleName, Succeeded) -->
+	foreign_language_external_filename(Lang, ModuleName, InFile),
+	(
+		{ Lang = c },
+		globals__io_lookup_string_option(object_file_extension,
+			ObjExt)
+	; 	
+		{ Lang = cplusplus },
+		globals__io_lookup_string_option(object_file_extension,
+			ObjExt)
+	; 
+		{ Lang = csharp },
+		{ ObjExt = ".dll" }
+	;	
+		{ Lang = managed_cplusplus },
+		{ ObjExt = ".dll" }
+	;	
+		{ Lang = il },
+		{ error("no support for IL in external files") }
+	),
+	foreign_language_external_filename(Lang, ModuleName, ObjExt, OutFile),
+	( 
+		{ Lang = c },
+		compile_c_file(ErrorStream, non_pic, InFile, OutFile,
+			Succeeded),
+		globals__io_lookup_accumulating_option(link_objects,
+			LinkObjects),
+		globals__io_set_option(link_objects, accumulating([OutFile |
+			LinkObjects]))
+	;
+		{ Lang = cplusplus },
+		compile_cplusplus_file(ErrorStream, InFile, OutFile,
+			Succeeded),
+		globals__io_lookup_accumulating_option(link_objects,
+			LinkObjects),
+		globals__io_set_option(link_objects, accumulating([OutFile |
+			LinkObjects]))
+	;
+		{ Lang = csharp },
+		compile_csharp_file(ErrorStream, InFile, OutFile, Succeeded)
+	;
+
+		{ Lang = managed_cplusplus },
+		compile_managed_cplusplus_file(ErrorStream, InFile, OutFile,
+			Succeeded)
+	;
+		{ Lang = il },
+		{ error("no support for IL in external files") }
+	).
+
+
+foreign__interface_info_generates_output(Info) :-
+	Info = foreign_interface_info(_, DeclCodes, _, BodyCodes, _, _),
+		% If there is a decl or a body code we are going to
+		% generate output
+	( DeclCodes = [_|_] ; BodyCodes = [_|_] ).
+
+%-----------------------------------------------------------------------------%
+
+foreign__output_interface_info(Lang, Info) -->
+	{ Info = foreign_interface_info(ModuleName, _, _, _, _, _) },
+	foreign_language_external_filename(Lang, ModuleName, FileName),
+	output_to_file(FileName, output_interface_info_2(Lang, Info)).
+
+:- pred foreign_language_external_filename(foreign_language::in,
+		module_name::in, string::out, io__state::di, io__state::uo)
+		is det.
+foreign_language_external_filename(Lang, ModuleName, FileName) -->
+	(
+		{ Ext = foreign_language_file_extension(Lang) }
+	->
+		foreign_language_external_filename(
+			Lang, ModuleName, Ext, FileName)
+	;
+		{ error("foreign language " ++ foreign_language_string(Lang)
+			++ " does not generate an external output file.") }
+	).
+
+:- pred foreign_language_external_filename(foreign_language::in, 
+		module_name::in, string::in, string::out,
+		io__state::di, io__state::uo) is det.
+foreign_language_external_filename(Lang, ModuleName, Ext, FileName) -->
+	(
+		{ ForeignModuleName = foreign_language_module_name(
+			ModuleName, Lang) }
+	->
+		module_name_to_file_name(ForeignModuleName, Ext, yes,
+			FileName)
+	;
+		{ error("foreign language " ++ foreign_language_string(Lang)
+			++ " does not generate an external output file.") }
+	).
+
+
+:- pred foreign__output_interface_info_2(
+	foreign_language::in, foreign_interface_info::in,
+	io__state::di, io__state::uo) is det.
+foreign__output_interface_info_2(cplusplus, Info) -->
+	{ Info = foreign_interface_info(ModuleName,
+		DeclCodes, _, BodyCodes, _, _) },
+
+	output_src_start(ModuleName),
+
+	io__write_string("#include <mercury_types.h>\n"),
+	io__write_list(DeclCodes, "\n", (pred(X::in, di, uo) is det -->
+		{ X = foreign_decl_code(_, CodeList) },
+		foreign__output_c_code_fragments(CodeList)
+	)),
+	io__nl,
+
+	io__write_string("extern ""C"" {\n"),
+
+	io__write_list(BodyCodes, "\n", (pred(X::in, di, uo) is det -->
+		{ X = foreign_body_code(_, CodeList) },
+		foreign__output_c_code_fragments(CodeList)
+		)),
+	io__nl,
+	io__write_string("}\n"),
+	output_src_end(ModuleName).
+foreign__output_interface_info_2(c, _) -->
+	{ error("output_interface_info_2: c not handled here") }.
+foreign__output_interface_info_2(csharp, _) -->
+	{ error("output_interface_info_2: csharp not handled here") }.
+foreign__output_interface_info_2(managed_cplusplus, _) -->
+	{ error("output_interface_info_2: managed_cplusplus not handled here")
+		}.
+foreign__output_interface_info_2(il, _) -->
+	{ error("output_interface_info_2: il not handled here") }.
+
+
+foreign__output_c_code_fragments(CodeList) -->
+	io__write_list(CodeList, "", (pred(C::in, di, uo) is det -->
+		( { C = CodeStr - no },
+			io__write_string(CodeStr)
+		; { C = CodeStr - yes(Context) },
+			{ term__context_file(Context, FileName) },
+			{ term__context_line(Context, LineNumber) },
+			c_util__set_line_num(FileName, LineNumber),
+			io__write_string(CodeStr),
+			c_util__reset_line_num
+		))).
+
+:- pred output_src_start(module_name, io__state, io__state).
+:- mode output_src_start(in, di, uo) is det.
+
+output_src_start(ModuleName) -->
+	{ library__version(Version) },
+	{ prog_out__sym_name_to_string(ModuleName, ModuleNameStr) },
+	io__write_strings(
+		["//\n// Automatically generated from `", 
+		ModuleNameStr,
+		".m' by the\n",
+		"// Mercury compiler, version ", 
+		Version,
+		".\n",
+		"// Do not edit.\n",
+		"\n\n"]).
+
+:- pred output_src_end(module_name, io__state, io__state).
+:- mode output_src_end(in, di, uo) is det.
+output_src_end(ModuleName) -->
+	io__write_string("// End of module: "),
+	prog_out__write_sym_name(ModuleName),
+	io__write_string(". \n").
+
+
+%-----------------------------------------------------------------------------%
 
 	% Currently we don't use the globals to compare foreign language
 	% interfaces, but if we added appropriate options we might want
@@ -239,7 +469,7 @@
 
 
 foreign__filter_decls(WantedLang, Decls0, LangDecls, NotLangDecls) :-
-	list__filter((pred(foreign_decl_code(Lang, _, _)::in) is semidet :-
+	list__filter((pred(foreign_decl_code(Lang, _)::in) is semidet :-
 			WantedLang = Lang),
 		Decls0, LangDecls, NotLangDecls).
 
@@ -250,114 +480,210 @@
 		Imports0, LangImports, NotLangImports).
 
 foreign__filter_bodys(WantedLang, Bodys0, LangBodys, NotLangBodys) :-
-	list__filter((pred(foreign_body_code(Lang, _, _)::in) is semidet :-
+	list__filter((pred(foreign_body_code(Lang, _)::in) is semidet :-
 			WantedLang = Lang),
 		Bodys0, LangBodys, NotLangBodys).
 	
-foreign__extrude_pragma_implementation([], _PragmaVars,
+foreign__piggyback_pragma_implementation([], _PragmaVars, _ArgTypes,
 	_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
+	% We just use the first foreign 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,
+foreign__piggyback_pragma_implementation([BackendForeignLang | BackendLangs], 
+		PragmaVars, ArgTypes, PredName, PredOrFunc, Context,
 		ModuleInfo0, Attributes, Impl0, 
 		ModuleInfo, NewAttributes, Impl) :-
 	foreign_language(Attributes, ForeignLanguage),
 
 		% If the foreign language is available as a target language, 
 		% we don't need to do anything.
-	( list__member(ForeignLanguage, [TargetLang | TargetLangs]) ->
+	( list__member(ForeignLanguage, [BackendForeignLang | BackendLangs]) ->
 		Impl = Impl0,
 		ModuleInfo = ModuleInfo0,
 		NewAttributes = Attributes
 	;
-		set_foreign_language(Attributes, TargetLang, NewAttributes),
-		extrude_pragma_implementation_2(TargetLang, ForeignLanguage,
-			ModuleInfo0, Impl0, ModuleInfo, Impl)
+		set_foreign_language(Attributes, BackendForeignLang,
+			NewAttributes),
+		piggyback_pragma_implementation2(BackendForeignLang,
+			ForeignLanguage, ModuleInfo0, Impl0, 
+			PragmaVars, ArgTypes, PredName, PredOrFunc, Context, 
+			ModuleInfo, Impl)
 	).
 
 
-:- pred extrude_pragma_implementation_2(
+can_piggyback_language(X, X).
+can_piggyback_language(c, cplusplus).
+
+piggyback_languages(BackendLangs, PossibleMatches) :-
+	solutions((pred(Y::out) is nondet :-
+		list__member(Lang, BackendLangs),
+		can_piggyback_language(Lang, Y)
+	), PossibleMatches).
+
+:- pred piggyback_pragma_implementation2(
 	foreign_language::in, foreign_language::in,
 	module_info::in, pragma_foreign_code_impl::in,
+	list(pragma_var)::in, list(type)::in,
+	sym_name::in, pred_or_func::in, prog_context::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).
+piggyback_pragma_implementation2(c, Lang, ModuleInfo0, Impl0,
+		PragmaVars, ArgTypes, PredName, PredOrFunc, Context,
+		ModuleInfo, Impl) :-
+	( Lang = cplusplus ->
+		NewName = make_pred_name(Lang, PredName),
+		ReturnCode = "",
+		assoc_list__from_corresponding_lists(PragmaVars, ArgTypes,
+			Args0),
+		list__filter(include_import_arg(ModuleInfo0), Args0, Args,
+			DummyArgs),
+		create_pragma_import_c_code(assoc_list__keys(Args),
+			ModuleInfo0, "", VarString),
+		Impl = import(NewName, ReturnCode, VarString, no),
+
+		( Impl0 = ordinary(UserCode, _) ->
+			create_new_implementation(NewName, ModuleInfo0,
+				Args, DummyArgs, PredOrFunc,
+				UserCode, Context, DeclCode, BodyCode),
+
+			% Add a C++ foreign_code which contains a
+			% C++ function definition
 
-extrude_pragma_implementation_2(c, il, _, _, _, _) :-
-	unimplemented_combination(c, il).
+			module_add_foreign_body_code(cplusplus, 
+				BodyCode, ModuleInfo0, ModuleInfo1),
 
-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).
+			% Add a C foreign_decl which has a prototype
+			% for the C++ function
 
+			module_add_foreign_decl(c, 
+				DeclCode, ModuleInfo1, ModuleInfo)
+		;
+			error("unimplemented: piggybacking anything but "
+				++ "ordinary code")
+		)
+	;
+		unimplemented_combination(c, Lang)
+	).
 
 
-extrude_pragma_implementation_2(csharp, csharp,
-	ModuleInfo, Impl, ModuleInfo, Impl).
+:- pred create_new_implementation(string::in, module_info::in,
+		list(pair(pragma_var, type))::in, 
+		list(pair(pragma_var, type))::in,
+		pred_or_func::in, string::in, context::in,
+		foreign_code_fragments::out,
+		foreign_code_fragments::out) is det.
+create_new_implementation(NewName, ModuleInfo, Args, DummyArgs,
+	_PredOrFunc, UserCode, Context, NewDecl, NewImpl) :-
+	( Args = [] ->
+		DeclString = "void"
+	;
+		DeclString = create_pragma_var_decl_string(Args, ModuleInfo)
+	),
 
-extrude_pragma_implementation_2(csharp, c, _, _, _, _) :-
-	unimplemented_combination(csharp, c).
+	DummyDeclString = create_arg_decls(DummyArgs, ModuleInfo),
+	MarshalInputString = create_marshal_inputs_string(Args, ModuleInfo),
+	MarshalOutputString = create_marshal_outputs_string(Args, ModuleInfo),
+
+	HeadCode = "void " ++ NewName ++ "(" ++ DeclString ++ ")",
+	NewDecl = [(HeadCode ++ ";\n") - no],
+	NewImpl1 = HeadCode ++ "\n" ++ "{\n" 
+		++ DummyDeclString ++ "\n" 
+		++ MarshalInputString ++ "\n",
+
+	NewImpl2 = "\n" ++ MarshalOutputString ++ "\n}\n",
+	NewImpl = [NewImpl1 - no, UserCode - yes(Context), NewImpl2 - no].
+
+:- func create_marshal_inputs_string(list(pair(pragma_var, type)),
+		module_info) = string.
+
+create_marshal_inputs_string(Args, ModuleInfo) = Str :-
+	Strs = list__map((func(PragmaVar - VarType) = S :-
+		PragmaVar = pragma_var(_Var, ArgName, Mode),
+		S = ( mode_is_output(ModuleInfo, Mode) ->
+			to_type_string(c, ModuleInfo, VarType) ++ " " ++
+				ArgName ++ ";\n"
+		;
+			to_type_string(c, ModuleInfo, VarType) ++ " " 
+				++ ArgName ++ " = " ++ ArgName ++ "_param;\n"
+		)
+	), Args),
+	Str = string__append_list(Strs).
 
-extrude_pragma_implementation_2(csharp, managed_cplusplus, _, _, _, _) :-
-	unimplemented_combination(csharp, managed_cplusplus).
+:- func create_marshal_outputs_string(list(pair(pragma_var, type)),
+		module_info) = string.
 
-extrude_pragma_implementation_2(csharp, il, _, _, _, _) :-
-	unimplemented_combination(csharp, il).
+create_marshal_outputs_string(Args, ModuleInfo) = Str :-
+	Strs = list__map((func(PragmaVar - _VarType) = S :-
+		PragmaVar = pragma_var(_Var, ArgName, Mode),
+		S = ( mode_is_output(ModuleInfo, Mode) ->
+			"*" ++ ArgName ++ "_param = " ++ ArgName ++ ";\n"
+		;
+			""
+		)
+	), Args),
+	Str = string__append_list(Strs).
 
+:- func create_arg_decls(list(pair(pragma_var, type)), module_info) = string.
 
-extrude_pragma_implementation_2(il, il,
-	ModuleInfo, Impl, ModuleInfo, Impl).
+create_arg_decls(Args, ModuleInfo) = Str :-
+	Strs = list__map((func(PragmaVar - VarType) = S :-
+		PragmaVar = pragma_var(_Var, ArgName, _Mode),
+		S = to_type_string(c, ModuleInfo, VarType) ++ " "
+			++ ArgName ++ ";\n"
+	), Args),
+	Str = string__append_list(Strs).
+
+
+:- func create_pragma_var_decl_string(list(pair(pragma_var, type)),
+		module_info) = string.
+
+create_pragma_var_decl_string(Args, ModuleInfo) = Str :-
+	Commas = list__duplicate(list__length(Args) - 1, ", "),
+	Strs0 = list__map((func(PragmaVar - VarType) = S :-
+		PragmaVar = pragma_var(_Var, ArgName, Mode),
+
+		%
+		% Construct the C code fragment for passing this argument,
+		% and append it to C_Code0.
+		% Note that C handles output arguments by passing the variable'
+		% address, so if the mode is output, we need to put an `&'
+		% before the variable name.
+		%
+		S = to_type_string(c, ModuleInfo, VarType) ++ " " ++
+		( mode_is_output(ModuleInfo, Mode) ->
+			"*"
+		;
+			""
+		) ++ ArgName ++ "_param"
+	), Args),
+	Strs = list__zip(Strs0, Commas),
+	Str = string__append_list(Strs).
 
-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).
 
+piggyback_pragma_implementation2(csharp, Lang, _ModuleInfo0, _Impl0,
+		_PragmaVars, _ArgTypes, _PredName, _PredOrFunc, _Context,
+		_ModuleInfo, _Impl) :-
+	unimplemented_combination(csharp, Lang).
+
+piggyback_pragma_implementation2(il, Lang, _ModuleInfo0, _Impl0,
+		_PragmaVars, _ArgTypes, _PredName, _PredOrFunc, _Context,
+		_ModuleInfo, _Impl) :-
+	unimplemented_combination(il, Lang).
+
+piggyback_pragma_implementation2(cplusplus, Lang, _ModuleInfo0, _Impl0,
+		_PragmaVars, _ArgTypes, _PredName, _PredOrFunc, _Context,
+		_ModuleInfo, _Impl) :-
+	unimplemented_combination(cplusplus, Lang).
+
+piggyback_pragma_implementation2(managed_cplusplus, Lang, _ModuleInfo0, _Impl0,
+		_PragmaVars, _ArgTypes, _PredName, _PredOrFunc, _Context,
+		_ModuleInfo, _Impl) :-
+	unimplemented_combination(managed_cplusplus, Lang).
 
 
 :- pred unimplemented_combination(foreign_language::in, foreign_language::in)
@@ -377,12 +703,16 @@
 
 :- func make_pred_name_rest(foreign_language, sym_name) = string.
 make_pred_name_rest(c, _SymName) = "some_c_name".
+make_pred_name_rest(csharp, _SymName) = "some_csharp_name".
+make_pred_name_rest(il, _SymName) = "some_il_name".
+
 make_pred_name_rest(managed_cplusplus, qualified(ModuleSpec, Name)) = 
 	make_pred_name_rest(managed_cplusplus, ModuleSpec) ++ "__" ++ Name.
 make_pred_name_rest(managed_cplusplus, unqualified(Name)) = Name.
-make_pred_name_rest(csharp, _SymName) = "some_csharp_name".
-make_pred_name_rest(il, _SymName) = "some_il_name".
 
+make_pred_name_rest(cplusplus, qualified(ModuleSpec, Name)) = 
+	make_pred_name_rest(managed_cplusplus, ModuleSpec) ++ "__" ++ Name.
+make_pred_name_rest(cplusplus, unqualified(Name)) = Name.
 
 make_pragma_import(PredInfo, ProcInfo, C_Function, Context,
 		ModuleInfo, PragmaImpl, VarSet, PragmaVars, ArgTypes, 
@@ -560,15 +890,24 @@
 foreign_language_string(managed_cplusplus) = "Managed C++".
 foreign_language_string(csharp) = "C#".
 foreign_language_string(il) = "IL".
+foreign_language_string(cplusplus) = "C++".
 
 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".
+simple_foreign_language_string(cplusplus) = "cpp".
+
+foreign_language_specification_string(c) = "c".
+foreign_language_specification_string(managed_cplusplus) = "mc++".
+foreign_language_specification_string(csharp) = "csharp".
+foreign_language_specification_string(il) = "il".
+foreign_language_specification_string(cplusplus) = "c++".
 
 foreign_language_file_extension(c) = ".c".
 foreign_language_file_extension(managed_cplusplus) = ".cpp".
 foreign_language_file_extension(csharp) = ".cs".
+foreign_language_file_extension(cplusplus) = ".cpp".
 foreign_language_file_extension(il) = _ :- fail.
 
 foreign_language_module_name(M, L) = FM :-
@@ -583,6 +922,26 @@
 		FM = qualified(Module, Name ++ Ending)
 	).
 
+
+%-----------------------------------------------------------------------------%
+
+foreign__body_info_to_body_code(Lang, BodyInfos) = BodyCodes :-
+	BodyCodes = list__condense(list__map(ConvBody, BodyInfos)),
+	ConvBody = (func(foreign_body_code(_L, Fragments)) = 
+			list__map(FragmentToBody, Fragments)),
+	FragmentToBody = (func(CodeStr - MaybeContext) = U :-
+		( MaybeContext = yes(Context),
+			U = user_foreign_code(Lang, CodeStr,
+				Context)	
+		; MaybeContext = no,
+			U = user_foreign_code(Lang, CodeStr,
+				term__context_init)	
+		)).
+
+	% XXX should we put the contexts in here?
+foreign__fragments_to_string(Frags) = 
+	string__append_list(assoc_list__keys(Frags)).
+
 %-----------------------------------------------------------------------------%
 
 :- type exported_type
@@ -645,6 +1004,12 @@
 	;
 		unexpected(this_file, "to_type_string: qualified C type")
 	).
+to_type_string(cplusplus, foreign(ForeignType)) = Result :-
+	( ForeignType = unqualified(Result0) ->
+		Result = Result0
+	;
+		unexpected(this_file, "to_type_string: qualified C++ type")
+	).
 to_type_string(csharp, foreign(ForeignType)) = Result :-
 	sym_name_to_string(ForeignType, ".", Result).
 to_type_string(managed_cplusplus, foreign(ForeignType)) = Result ++ " *":-
@@ -677,6 +1042,8 @@
 	).
 to_type_string(il, mercury(_Type)) = _ :-
 	sorry(this_file, "to_type_string for il").
+to_type_string(cplusplus, mercury(Type)) 
+	= to_type_string(managed_cplusplus, mercury(Type)).
 
 %-----------------------------------------------------------------------------%
 
Index: compiler/globals.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/globals.m,v
retrieving revision 1.50
diff -u -r1.50 globals.m
--- compiler/globals.m	15 Apr 2002 05:04:02 -0000	1.50
+++ compiler/globals.m	12 Jun 2002 02:27:15 -0000
@@ -35,7 +35,7 @@
 
 :- type foreign_language
 	--->	c
-% 	;	cplusplus
+ 	;	cplusplus
  	;	csharp
  	;	managed_cplusplus
 % 	;	java
@@ -86,6 +86,8 @@
 :- 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_supported_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) 
@@ -151,8 +153,15 @@
 :- pred globals__io_get_target(compilation_target::out,
 	io__state::di, io__state::uo) is det.
 
+	% The list of foreign languages out backend supports directly
 :- pred globals__io_get_backend_foreign_languages(list(foreign_language)::out,
 	io__state::di, io__state::uo) is det.
+
+	% The list of foreign languages we can support with this backend
+	% (directly or indirectly)
+:- pred globals__io_get_supported_foreign_languages(
+		list(foreign_language)::out,
+		io__state::di, io__state::uo) is det.
 	
 :- pred globals__io_lookup_foreign_language_option(option::in,
 	foreign_language::out, io__state::di, io__state::uo) is det.
@@ -233,6 +242,7 @@
 	is semidet.
 
 convert_foreign_language_2("c", c).
+convert_foreign_language_2("c++", cplusplus).
 convert_foreign_language_2("mc++", managed_cplusplus).
 convert_foreign_language_2("managedc++", managed_cplusplus).
 convert_foreign_language_2("managed c++", managed_cplusplus).
@@ -282,6 +292,15 @@
 globals__get_trace_suppress(Globals, Globals ^ trace_suppress_items).
 globals__get_source_file_map(Globals, Globals ^ source_file_map).
 
+globals__get_supported_foreign_languages(Globals, ForeignLangs) :-
+	globals__lookup_accumulating_option(Globals,
+		supported_foreign_languages, LangStrs),
+	ForeignLangs = list__map(func(String) = ForeignLang :-
+		( convert_foreign_language(String, ForeignLang0) ->
+			ForeignLang = ForeignLang0
+		;
+			error("globals__io_get_supported_foreign_languages: invalid foreign_language string")
+		), LangStrs).
 globals__get_backend_foreign_languages(Globals, ForeignLangs) :-
 	globals__lookup_accumulating_option(Globals, backend_foreign_languages,
 		LangStrs),
@@ -490,6 +509,10 @@
 globals__io_get_backend_foreign_languages(ForeignLangs) -->
 	globals__io_get_globals(Globals),
 	{ globals__get_backend_foreign_languages(Globals, ForeignLangs) }.
+
+globals__io_get_supported_foreign_languages(ForeignLangs) -->
+	globals__io_get_globals(Globals),
+	{ globals__get_supported_foreign_languages(Globals, ForeignLangs) }.
 
 globals__io_lookup_bool_option(Option, Value) -->
 	globals__io_get_globals(Globals),
Index: compiler/handle_options.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/handle_options.m,v
retrieving revision 1.140
diff -u -r1.140 handle_options.m
--- compiler/handle_options.m	30 May 2002 12:54:56 -0000	1.140
+++ compiler/handle_options.m	12 Jun 2002 02:27:15 -0000
@@ -978,6 +978,25 @@
 		[]
 	),
 
+	globals__io_get_backend_foreign_languages(BackendFLs),
+	{ piggyback_languages(BackendFLs, SupportedForeignLanguages) },
+
+	{ SupportedForeignLanguageStrs = list__map(
+		foreign_language_specification_string,
+		SupportedForeignLanguages) },
+
+		% only set the supported foreign languages if they are unset
+	globals__io_lookup_accumulating_option(supported_foreign_languages,
+		CurrentSupportedForeignLanguage),
+	( 
+		{ CurrentSupportedForeignLanguage = [] }
+	->
+		globals__io_set_option(supported_foreign_languages,
+			accumulating(SupportedForeignLanguageStrs))
+	;
+		[]
+	),
+
 	globals__io_lookup_int_option(compare_specialization, CompareSpec),
 	( { CompareSpec < 0 } ->
 		% This indicates that the option was not set by the user;
Index: compiler/hlds_module.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/hlds_module.m,v
retrieving revision 1.74
diff -u -r1.74 hlds_module.m
--- compiler/hlds_module.m	7 Apr 2002 10:22:30 -0000	1.74
+++ compiler/hlds_module.m	12 Jun 2002 02:27:15 -0000
@@ -289,17 +289,17 @@
 		foreign_import_module_info, module_info).
 :- mode module_info_set_foreign_import_module(in, in, out) is det.
 
-:- pred module_add_foreign_decl(foreign_language, string, prog_context,
+:- pred module_add_foreign_decl(foreign_language, foreign_code_fragments,
 		module_info, module_info).
-:- mode module_add_foreign_decl(in, in, in, in, out) is det.
+:- mode module_add_foreign_decl(in, in, in, out) is det.
 
 :- pred module_add_foreign_import_module(foreign_language,
 		module_name, prog_context, module_info, module_info).
 :- mode module_add_foreign_import_module(in, in, in, in, out) is det.
 
-:- pred module_add_foreign_body_code(foreign_language, string, prog_context,
+:- pred module_add_foreign_body_code(foreign_language, foreign_code_fragments,
 		module_info, module_info).
-:- mode module_add_foreign_body_code(in, in, in, in, out) is det.
+:- mode module_add_foreign_body_code(in, in, in, out) is det.
 
 	% Please see module_info_ensure_dependency_info for the
 	% constraints on this dependency_info.
@@ -912,12 +912,12 @@
 	AllImports = (IndirectImports `set__union` DirectImports)
 			`set__union` set__list_to_set(Parents).
 
-module_add_foreign_decl(Lang, ForeignDecl, Context, Module0, Module) :-
+module_add_foreign_decl(Lang, ForeignDecl, Module0, Module) :-
 	module_info_get_foreign_decl(Module0, ForeignDeclIndex0),
 		% store the decls in reverse order and reverse them later
 		% for efficiency
-	ForeignDeclIndex1 = [foreign_decl_code(Lang, ForeignDecl, Context) |
-		ForeignDeclIndex0],
+	ForeignDeclIndex1 = [foreign_decl_code(Lang, ForeignDecl)
+		| ForeignDeclIndex0],
 	module_info_set_foreign_decl(Module0, ForeignDeclIndex1, Module).
 
 module_add_foreign_import_module(Lang, ModuleName, Context, Module0, Module) :-
@@ -930,13 +930,12 @@
 	module_info_set_foreign_import_module(Module0,
 		ForeignImportIndex1, Module).
 
-module_add_foreign_body_code(Lang, Foreign_Body_Code, Context,
-		Module0, Module) :-
+module_add_foreign_body_code(Lang, Foreign_Body_Code, Module0, Module) :-
 	module_info_get_foreign_body_code(Module0, Foreign_Body_List0),
 		% store the decls in reverse order and reverse them later
 		% for efficiency
 	Foreign_Body_List = 
-		[foreign_body_code(Lang, Foreign_Body_Code, Context) |
+		[foreign_body_code(Lang, Foreign_Body_Code) |
 			Foreign_Body_List0],
 	module_info_set_foreign_body_code(Module0, Foreign_Body_List, Module).
 
Index: compiler/intermod.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/intermod.m,v
retrieving revision 1.121
diff -u -r1.121 intermod.m
--- compiler/intermod.m	10 May 2002 14:03:58 -0000	1.121
+++ compiler/intermod.m	13 Jun 2002 00:47:45 -0000
@@ -98,7 +98,7 @@
 :- import_module parse_tree__prog_util.
 :- import_module hlds__special_pred, check_hlds__typecheck.
 :- import_module check_hlds__type_util, hlds__instmap, (parse_tree__inst).
-:- import_module backend_libs__foreign.
+:- import_module backend_libs, backend_libs__foreign.
 
 %-----------------------------------------------------------------------------%
 
@@ -1144,8 +1144,9 @@
 
 		list__foldl(
 		    (pred(ForeignDecl::in, di, uo) is det -->
-		    	{ ForeignDecl = foreign_decl_code(Lang, Header, _) },
-		    	mercury_output_pragma_foreign_decl(Lang, Header)
+		    	{ ForeignDecl = foreign_decl_code(Lang, CodeFrags) },
+			{ Str = foreign__fragments_to_string(CodeFrags) },
+		    	mercury_output_pragma_foreign_decl(Lang, Str)
 		    ), ForeignDecls)
 	;
 		[]
Index: compiler/llds.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/llds.m,v
retrieving revision 1.286
diff -u -r1.286 llds.m
--- compiler/llds.m	9 May 2002 16:30:53 -0000	1.286
+++ compiler/llds.m	12 Jun 2002 02:27:15 -0000
@@ -25,21 +25,6 @@
 
 :- import_module bool, list, assoc_list, map, set, std_util, counter, term.
 
-%-----------------------------------------------------------------------------%
-
-% foreign_interface_info holds information used when generating
-% code that uses the foreign language interface.
-:- type foreign_interface_info
-	---> foreign_interface_info(
-		module_name,
-		% info about stuff imported from C:
-		foreign_decl_info,
-		foreign_import_module_info,
-		foreign_body_info,
-		% info about stuff exported to C:
-		foreign_export_decls,
-		foreign_export_defns
-	).
 
 %-----------------------------------------------------------------------------%
 
Index: compiler/llds_out.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/llds_out.m,v
retrieving revision 1.194
diff -u -r1.194 llds_out.m
--- compiler/llds_out.m	30 May 2002 08:00:01 -0000	1.194
+++ compiler/llds_out.m	13 Jun 2002 00:45:17 -0000
@@ -1089,22 +1089,38 @@
 
 output_foreign_header_include_lines_2([]) --> [].
 output_foreign_header_include_lines_2(
-		[foreign_decl_code(Lang, Code, Context) | Hs]) -->
+		[foreign_decl_code(Lang, CodeAndContexts) | Hs]) -->
 	( { Lang = c } ->
 		globals__io_lookup_bool_option(auto_comments, PrintComments),
 		( { PrintComments = yes } ->
 			io__write_string("/* "),
-			prog_out__write_context(Context),
+				% if there is a context on the first element,
+				% consider this the context to put in the
+				% comments
+			( { CodeAndContexts = [_ - yes(Context0) | _] } ->
+				prog_out__write_context(Context0)
+			;
+				[]
+			),
 			io__write_string(" pragma foreign_decl_code( "),
 			io__write(Lang),
 			io__write_string(" */\n")
 		;
 			[]
 		),
-		output_set_line_num(Context),
-		io__write_string(Code),
-		io__write_string("\n"),
-		output_reset_line_num
+		list__foldl((pred((Code - MaybeContext)::in, di, uo) is det -->
+			( { MaybeContext = yes(Context1) } ->
+				output_set_line_num(Context1)
+			;
+				[]
+			),
+			io__write_string(Code),
+			io__write_string("\n"),
+			( { MaybeContext = yes(_) } ->
+				output_reset_line_num
+			;
+				[]
+			)), CodeAndContexts)
 	;
 		{ error("llds_out__output_user_foreign_code: unexpected: foreign code other than C") }
 	),
Index: compiler/make.module_target.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/make.module_target.m,v
retrieving revision 1.7
diff -u -r1.7 make.module_target.m
--- compiler/make.module_target.m	30 May 2002 12:55:01 -0000	1.7
+++ compiler/make.module_target.m	12 Jun 2002 02:27:15 -0000
@@ -319,6 +319,11 @@
 		Succeeded) -->
 	compile_target_code__compile_csharp_file(ErrorStream,
 		CSharpFile, DLLFile, Succeeded).
+		% XXX TYSE this might need to be fixed!!!!
+compile_foreign_code_file(ErrorStream, Pic,
+		foreign_code_file(cplusplus, CppFile, ObjFile), Succeeded) -->
+	compile_target_code__compile_c_file(ErrorStream, Pic,
+		CppFile, ObjFile, Succeeded).
 
 %-----------------------------------------------------------------------------%
 
Index: compiler/make_hlds.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/make_hlds.m,v
retrieving revision 1.414
diff -u -r1.414 make_hlds.m
--- compiler/make_hlds.m	10 Jun 2002 15:58:05 -0000	1.414
+++ compiler/make_hlds.m	13 Jun 2002 00:56:42 -0000
@@ -393,11 +393,11 @@
 		{ Module = Module0 }
 	;
 		{ Pragma = foreign_code(Lang, Body_Code) },
-		{ module_add_foreign_body_code(Lang, Body_Code, Context,
-			Module0, Module) }
+		{ module_add_foreign_body_code(Lang,
+			[Body_Code - yes(Context)], Module0, Module) }
 	;
-		{ Pragma  = foreign_decl(Lang, C_Header) },
-		{ module_add_foreign_decl(Lang, C_Header, Context,
+		{ Pragma  = foreign_decl(Lang, Decl_Code) },
+		{ module_add_foreign_decl(Lang, [Decl_Code - yes(Context)],
 			Module0, Module) }
 	;
 		{ Pragma  = foreign_import_module(Lang, Import) },
@@ -4345,7 +4345,7 @@
 		[]
 	),
 
-	globals__io_get_backend_foreign_languages(BackendForeignLangs),
+	globals__io_get_supported_foreign_languages(SupportedForeignLangs),
 
 		% Lookup the pred declaration in the predicate table.
 		% (If it's not there, print an error message and insert
@@ -4413,7 +4413,8 @@
 	;	
 			% Don't add clauses for foreign languages other
 			% than the ones we can generate code for.
-		{ not list__member(PragmaForeignLanguage, BackendForeignLangs) }
+		{ not list__member(PragmaForeignLanguage,
+			SupportedForeignLangs) }
 	->
 		{ ModuleInfo = ModuleInfo1 },
 		{ Info = Info0 }
@@ -5594,6 +5595,7 @@
 
 
 	globals__io_get_backend_foreign_languages(BackendForeignLanguages),
+	globals__io_get_supported_foreign_languages(SupportedForeignLanguages),
 	{ 
 	pragma_get_vars(PVars, Args0),
 	pragma_get_var_infos(PVars, ArgInfo),
@@ -5603,10 +5605,22 @@
 	% languages, we will have to generate an interface to it in a
 	% backend language.
 	%
-	foreign__extrude_pragma_implementation(BackendForeignLanguages,
-		PVars, PredName, PredOrFunc, Context,
-		ModuleInfo0, Attributes0, PragmaImpl0,
-		ModuleInfo1, Attributes, PragmaImpl),
+
+	foreign_language(Attributes0, PragmaLang),
+
+	( 
+		list__member(PragmaLang, SupportedForeignLanguages)
+	->
+			% we might need to generate piggyback code for it
+		foreign__piggyback_pragma_implementation(
+			BackendForeignLanguages, PVars, OrigArgTypes,
+			PredName, PredOrFunc, Context, ModuleInfo0,
+			Attributes0, PragmaImpl0, ModuleInfo1, Attributes,
+			PragmaImpl)
+	;
+			% XXX crummy error message
+		error("sorry, foreign_proc not compatible")
+	),
 
 	%
 	% Check for arguments occurring multiple times.
@@ -8375,7 +8389,7 @@
 		{ adjust_func_arity(PredOrFunc, Arity, NumArgs) },
 
 		    % create pragma c_header_code to declare extern variables
-		{ module_add_foreign_decl(c, C_HeaderCode, Context,
+		{ module_add_foreign_decl(c, [C_HeaderCode - yes(Context)],
 			Module1, Module2) },
 
 		io__get_exit_status(ExitStatus),
@@ -8465,7 +8479,7 @@
 	->
 		Module2 = Module1
 	;
-		module_add_foreign_body_code(c, C_ExtraCode, Context,
+		module_add_foreign_body_code(c, [C_ExtraCode - yes(Context)],
 			Module1, Module2)
 	},
 	%
Index: compiler/maybe_mlds_to_gcc.pp
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/maybe_mlds_to_gcc.pp,v
retrieving revision 1.5
diff -u -r1.5 maybe_mlds_to_gcc.pp
--- compiler/maybe_mlds_to_gcc.pp	20 Mar 2002 12:35:47 -0000	1.5
+++ compiler/maybe_mlds_to_gcc.pp	12 Jun 2002 14:10:25 -0000
@@ -17,7 +17,7 @@
 :- module ml_backend__maybe_mlds_to_gcc.
 :- interface.
 
-:- import_module ml_backend__mlds, bool.
+:- import_module ml_backend__mlds, libs__globals, set.
 :- use_module io.
 
 :- type frontend_callback(T) == pred(T, io__state, io__state).
@@ -33,9 +33,9 @@
 
 	% Either invoke mlds_to_gcc__compile_to_asm, or report an error
 	% message, depending on whether the gcc back-end interface has
-	% been enabled.  In the former case,
-	% the bool returned is `yes' iff the module contained C code.
-:- pred maybe_mlds_to_gcc__compile_to_asm(mlds__mlds, bool,
+	% been enabled.  The set of foreign languages used in the code is
+	% returned.
+:- pred maybe_mlds_to_gcc__compile_to_asm(mlds__mlds, set(foreign_language),
 		io__state, io__state).
 :- mode maybe_mlds_to_gcc__compile_to_asm(in, out, di, uo) is det.
 
@@ -61,7 +61,7 @@
 maybe_mlds_to_gcc__run_gcc_backend(_ModuleName, CallBack, CallBackOutput) -->
 	CallBack(CallBackOutput).
 
-maybe_mlds_to_gcc__compile_to_asm(_MLDS, no) -->
+maybe_mlds_to_gcc__compile_to_asm(_MLDS, set__init) -->
 	report_error(
 "Sorry, `--target asm' not supported: this installation of the Mercury\n" ++
 "compiler was built without support for the GCC back-end interface.").
Index: compiler/mercury_compile.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mercury_compile.m,v
retrieving revision 1.253
diff -u -r1.253 mercury_compile.m
--- compiler/mercury_compile.m	10 Jun 2002 10:05:47 -0000	1.253
+++ compiler/mercury_compile.m	13 Jun 2002 00:55:51 -0000
@@ -1164,7 +1164,7 @@
 			{ HLDS = HLDS50 },
 			mercury_compile__mlds_backend(HLDS, MLDS),
 			mercury_compile__maybe_mlds_to_gcc(MLDS,
-				ContainsCCode),
+				_ForeignLangSet),
 			( { TargetCodeOnly = yes } ->
 				[]
 			;
@@ -1177,7 +1177,24 @@
 				% separate C file.  We need to invoke the
 				% C compiler on that.
 				%
-				( { ContainsCCode = yes } ->
+				get_all_foreign_language_interface_info(
+					HLDS, ForeignLangInfoMap),
+					% don't generate files for C
+					% because we already did that
+					% when generating code
+					% XXX better to do it all in the
+					% one place though
+				create_all_foreign_language_files([c],
+					ForeignLangInfoMap),
+
+				io__output_stream(OutputStream),
+				compile_all_foreign_language_files(
+					OutputStream, ModuleName, [c],
+					ForeignLangInfoMap)
+/*
+		% XXX I don't think we need this any more
+
+				( { set__member(c, ForeignLangSet) } ->
 					module_name_to_file_name(ModuleName,
 						".c", no, CCode_C_File),
 					globals__io_lookup_string_option(
@@ -1203,6 +1220,7 @@
 				;
 					[]
 				)
+*/
 			)
 		    ; { HighLevelCode = yes } ->
 			{ HLDS = HLDS50 },
@@ -1220,7 +1238,24 @@
 				io__output_stream(OutputStream),
 				compile_target_code__compile_c_file(
 					OutputStream, non_pic, C_File, O_File,
-					_CompileOK)
+					_CompileOK),
+
+				%
+				% Create all the other foreign language files
+				%
+
+				get_all_foreign_language_interface_info(
+					HLDS, ForeignLangInfoMap),
+				create_all_foreign_language_files([c],
+					ForeignLangInfoMap),
+	
+				%
+				% Compile all the other foreign language files
+				%
+	
+				compile_all_foreign_language_files(
+					OutputStream, ModuleName, [c],
+					ForeignLangInfoMap)
 			)
 		    ;
 			mercury_compile__backend_pass(HLDS50, HLDS,
@@ -3251,18 +3286,89 @@
 					C_ExportDecls, _) },
 	export__produce_header_file(C_ExportDecls, ModuleName),
 
+
+
 	%
 	% Finally we invoke the C compiler to compile it.
 	%
 	globals__io_lookup_bool_option(target_code_only, TargetCodeOnly),
+	io__output_stream(OutputStream),
 	( { TargetCodeOnly = no } ->
-		io__output_stream(OutputStream),
 		mercury_compile__c_to_obj(OutputStream,
 			ModuleName, NumChunks, CompileOK),
 		{ bool__not(CompileOK, CompileErrors) }
 	;
 		{ CompileErrors = no }
-	).
+	),
+
+	% 
+	% XXX TYSE
+	% If there are other (non-C) foreign languages code, we output them
+	% to the appropriate files.
+	% 
+
+	get_all_foreign_language_interface_info(HLDS, ForeignLangInfoMap),
+	create_all_foreign_language_files([c], ForeignLangInfoMap),
+	
+	%
+	% Compile all the other foreign language files
+	%
+	
+	compile_all_foreign_language_files(OutputStream, ModuleName, [c],
+		ForeignLangInfoMap).
+
+:- pred create_all_foreign_language_files(list(foreign_language)::in,
+		map(foreign_language, foreign_interface_info)::in,
+		io__state::di, io__state::uo) is det.
+create_all_foreign_language_files(ExcludeList, ForeignLangInfoMap) -->
+	map__foldl((pred(Lang::in, InterfaceInfo::in, di, uo) is det -->
+		( 
+			{ not list__member(Lang, ExcludeList) }
+		->
+			foreign__output_interface_info(Lang, InterfaceInfo)
+		;
+			[]
+		)
+		), ForeignLangInfoMap).
+
+:- pred compile_all_foreign_language_files(io__output_stream::in,
+		module_name::in, list(foreign_language)::in,
+		map(foreign_language, foreign_interface_info)::in,
+		io__state::di, io__state::uo) is det.
+compile_all_foreign_language_files(OutputStream, ModuleName, ExcludeList,
+		ForeignLangInfoMap) -->
+	map__foldl((pred(Lang::in, _InterfaceInfo::in, di, uo) is det -->
+		( 
+			{ not list__member(Lang, ExcludeList) }
+		->
+			foreign__compile_foreign_file(
+				OutputStream, Lang, ModuleName, _CompileOK)
+				% XXX we ignore status
+		;
+			[]
+		)
+		), ForeignLangInfoMap).
+
+:- pred get_all_foreign_language_interface_info(module_info::in,
+		map(foreign_language, foreign_interface_info)::out,
+		io__state::di, io__state::uo) is det.
+get_all_foreign_language_interface_info(HLDS, Map) -->
+	globals__io_get_supported_foreign_languages(SupportedForeignLangs),
+	{ map__init(EmptyMap) },
+	{ list__foldl((pred(Lang::in, Map0::in, Map1::out) is det :-
+		get_c_interface_info(HLDS, Lang, Lang_InterfaceInfo),
+		( 
+			foreign__interface_info_generates_output(
+				Lang_InterfaceInfo)
+		->
+			map__det_insert(Map0, Lang, Lang_InterfaceInfo, Map1)
+		;
+			Map0 = Map1
+		)
+	), SupportedForeignLangs, EmptyMap, Map) }.
+
+
+
 
 	% Split the code up into bite-size chunks for the C compiler.
 
@@ -3275,12 +3381,12 @@
 mercury_compile__construct_c_file(C_InterfaceInfo, Procedures, GlobalVars,
 		AllData, CFile, ComponentCount) -->
 	{ C_InterfaceInfo = foreign_interface_info(ModuleSymName,
-		C_HeaderCode0, C_Includes, C_BodyCode0,
+		C_HeaderCode0, C_Includes, C_BodyInfo,
 		_C_ExportDecls, C_ExportDefns) },
 	{ llds_out__sym_name_mangle(ModuleSymName, MangledModuleName) },
 	{ string__append(MangledModuleName, "_module", ModuleName) },
 	globals__io_lookup_int_option(procs_per_c_function, ProcsPerFunc),
-	{ get_c_body_code(C_BodyCode0, C_BodyCode) },
+	{ C_BodyCode = foreign__body_info_to_body_code(c, C_BodyInfo) },
 	( { ProcsPerFunc = 0 } ->
 		% ProcsPerFunc = 0 really means infinity -
 		% we store all the procs in a single function.
@@ -3318,7 +3424,11 @@
 		{ string__append_list(
 			["#include """, HeaderFileName, """\n"],
 			IncludeString) },
-		{ Include = foreign_decl_code(c, IncludeString, Context) }
+		{ Include = foreign_decl_code(c, [IncludeString -
+			yes(Context)]) }
+	;
+		{ Lang = cplusplus },
+		{ error("sorry, not yet implemented: `:- pragma foreign_import_module' for C++") }
 	;
 		{ Lang = csharp },
 		{ error("sorry.
@@ -3333,13 +3443,6 @@
 :- import_module not yet implemented: `:- pragma foreign_import_module' for IL") }
 	).
 
-:- pred get_c_body_code(foreign_body_info, list(user_foreign_code)).
-:- mode get_c_body_code(in, out) is det.
-
-get_c_body_code([], []).
-get_c_body_code([foreign_body_code(Lang, Code, Context) | CodesAndContexts],
-		[user_foreign_code(Lang, Code, Context) | C_Modules]) :-
-	get_c_body_code(CodesAndContexts, C_Modules).
 
 :- pred mercury_compile__combine_chunks(list(list(c_procedure)), string,
 	list(comp_gen_c_module)).
@@ -3598,16 +3701,17 @@
 	maybe_write_string(Verbose, "% Finished converting MLDS to Java.\n"),
 	maybe_report_stats(Stats).
 
-:- pred mercury_compile__maybe_mlds_to_gcc(mlds, bool, io__state, io__state).
+:- pred mercury_compile__maybe_mlds_to_gcc(mlds, set(foreign_language),
+		io__state, io__state).
 :- mode mercury_compile__maybe_mlds_to_gcc(in, out, di, uo) is det.
 
-mercury_compile__maybe_mlds_to_gcc(MLDS, ContainsCCode) -->
+mercury_compile__maybe_mlds_to_gcc(MLDS, ForeignLangSet) -->
 	globals__io_lookup_bool_option(verbose, Verbose),
 	globals__io_lookup_bool_option(statistics, Stats),
 
 	maybe_write_string(Verbose,
 		"% Passing MLDS to GCC and compiling to assembler...\n"),
-	maybe_mlds_to_gcc__compile_to_asm(MLDS, ContainsCCode),
+	maybe_mlds_to_gcc__compile_to_asm(MLDS, ForeignLangSet),
 	maybe_write_string(Verbose, "% Finished compiling to assembler.\n"),
 	maybe_report_stats(Stats).
 
Index: compiler/ml_code_gen.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/ml_code_gen.m,v
retrieving revision 1.118
diff -u -r1.118 ml_code_gen.m
--- compiler/ml_code_gen.m	4 Jun 2002 14:56:02 -0000	1.118
+++ compiler/ml_code_gen.m	13 Jun 2002 00:54:43 -0000
@@ -829,10 +829,9 @@
 			foreign__filter_bodys(Lang,
 				ForeignBodys, WantedForeignBodys,
 				_OtherForeignBodys),
-			ConvBody = (func(foreign_body_code(L, S, C)) = 
-				user_foreign_code(L, S, C)),
-			MLDSWantedForeignBodys = list__map(ConvBody, 
-				WantedForeignBodys),
+			MLDSWantedForeignBodys= 
+				foreign__body_info_to_body_code(Lang,
+					WantedForeignBodys),
 			 	% XXX exports are only implemented for
 				% C and IL at the moment
 			( ( Lang = c ; Lang = il ) ->
@@ -2350,6 +2349,11 @@
 		Foreign_Code, Context, MLDS_Decls, MLDS_Statements) -->
 	{ foreign_language(Attributes, Lang) },
 	( { Lang = c },
+		ml_gen_ordinary_pragma_c_proc(CodeModel, Attributes,
+			PredId, ProcId, ArgVars, ArgDatas, OrigArgTypes,
+			Foreign_Code, Context, MLDS_Decls, MLDS_Statements)
+		% XXX is this right for C++?	
+	; { Lang = cplusplus },
 		ml_gen_ordinary_pragma_c_proc(CodeModel, Attributes,
 			PredId, ProcId, ArgVars, ArgDatas, OrigArgTypes,
 			Foreign_Code, Context, MLDS_Decls, MLDS_Statements)
Index: compiler/mlds.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mlds.m,v
retrieving revision 1.92
diff -u -r1.92 mlds.m
--- compiler/mlds.m	30 May 2002 12:55:05 -0000	1.92
+++ compiler/mlds.m	12 Jun 2002 02:27:15 -0000
@@ -293,7 +293,7 @@
 :- import_module backend_libs__foreign, check_hlds__type_util.
 :- import_module libs__globals.
 
-:- import_module bool, list, std_util, map.
+:- import_module bool, list, std_util, map, set.
 
 %-----------------------------------------------------------------------------%
 
@@ -811,6 +811,8 @@
 		mlds__context
 	).
 
+:- func mlds__get_foreign_language_set(mlds) = set(foreign_language).
+
 %-----------------------------------------------------------------------------%
 %
 % Attributes
@@ -1765,6 +1767,11 @@
 	= name(Package, qualified(Module, Name)).
 
 wrapper_class_name = "mercury_code".
+
+%-----------------------------------------------------------------------------%
+
+mlds__get_foreign_language_set(MLDS)
+	= set__list_to_set(map__keys(MLDS ^ foreign_code)).
 
 %-----------------------------------------------------------------------------%
 
Index: compiler/mlds_to_c.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mlds_to_c.m,v
retrieving revision 1.131
diff -u -r1.131 mlds_to_c.m
--- compiler/mlds_to_c.m	7 Jun 2002 00:48:45 -0000	1.131
+++ compiler/mlds_to_c.m	12 Jun 2002 02:27:15 -0000
@@ -59,6 +59,7 @@
 :- import_module ml_backend__ml_code_util.	% for ml_gen_public_field_decl_flags, which is
 				% used by the code that handles derived classes
 :- import_module ml_backend__ml_type_gen.	% for ml_gen_type_name
+:- import_module backend_libs.
 :- import_module backend_libs__foreign.
 :- import_module libs__globals, libs__options, hlds__passes_aux.
 :- import_module backend_libs__builtin_ops, backend_libs__c_util.
@@ -557,11 +558,10 @@
 	foreign_decl_code, io__state, io__state).
 :- mode mlds_output_c_hdr_decl(in, in, di, uo) is det.
 
-mlds_output_c_hdr_decl(_Indent, foreign_decl_code(Lang, Code, Context)) -->
+mlds_output_c_hdr_decl(_Indent, foreign_decl_code(Lang, CodeFragments)) -->
 		% only output C code in the C header file.
 	( { Lang = c } ->
-		mlds_to_c__output_context(mlds__make_context(Context)),
-		io__write_string(Code)
+		foreign__output_c_code_fragments(CodeFragments)
 	;
 		{ sorry(this_file, "foreign code other than C") }
 	).
@@ -610,6 +610,8 @@
 mlds_output_c_defn(_Indent, user_foreign_code(csharp, _, _)) -->
 	{ sorry(this_file, "foreign code other than C") }.
 mlds_output_c_defn(_Indent, user_foreign_code(il, _, _)) -->
+	{ sorry(this_file, "foreign code other than C") }.
+mlds_output_c_defn(_Indent, user_foreign_code(cplusplus, _, _)) -->
 	{ sorry(this_file, "foreign code other than C") }.
 
 :- pred mlds_output_pragma_export_defn(mlds_module_name, indent,
Index: compiler/mlds_to_csharp.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mlds_to_csharp.m,v
retrieving revision 1.22
diff -u -r1.22 mlds_to_csharp.m
--- compiler/mlds_to_csharp.m	20 Mar 2002 12:36:50 -0000	1.22
+++ compiler/mlds_to_csharp.m	12 Jun 2002 02:27:15 -0000
@@ -184,15 +184,25 @@
 			_ExportDefns)) -->
 	{ HeaderCode = list__reverse(RevHeaderCode) },
 	io__write_list(HeaderCode, "\n", 
-		(pred(foreign_decl_code(Lang, Code, _Context)::in,
+		(pred(foreign_decl_code(Lang, CodeFragments)::in,
 			di, uo) is det -->
 			( { Lang = csharp } ->
-				io__write_string(Code)
+				output_csharp_code_fragments(CodeFragments)
 			;
 				{ sorry(this_file, 
 					"foreign code other than MC++") }
 			)					
 	)).
+
+:- pred output_csharp_code_fragments(foreign_code_fragments, io, io).
+:- mode output_csharp_code_fragments(in, di, uo) is det.
+output_csharp_code_fragments(CodeList) -->
+	io__write_list(CodeList, "",
+		(pred(C::in, di, uo) is det -->
+			% XXX we ignore the context
+			{ C = CodeStr - _ },
+			io__write_string(CodeStr)
+		)).
 
 :- pred generate_method_csharp_code(mlds_module_name, mlds__defn,
 		io__state, io__state).
Index: compiler/mlds_to_gcc.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mlds_to_gcc.m,v
retrieving revision 1.71
diff -u -r1.71 mlds_to_gcc.m
--- compiler/mlds_to_gcc.m	7 May 2002 11:03:06 -0000	1.71
+++ compiler/mlds_to_gcc.m	12 Jun 2002 02:27:15 -0000
@@ -92,7 +92,7 @@
 :- interface.
 
 :- import_module ml_backend.
-:- import_module ml_backend__mlds, ml_backend__maybe_mlds_to_gcc, bool.
+:- import_module ml_backend__mlds, ml_backend__maybe_mlds_to_gcc, set.
 :- use_module io.
 
 	% run_gcc_backend(ModuleName, CallBack, CallBackOutput):
@@ -122,19 +122,11 @@
 	% try to use the GCC back-end before it has been properly
 	% initialized.
 	%
-	% The ContainsCCode bool returned is `yes' iff the module contained
-	% C code. In that case, we will have output a separate C file which
-	% needs to be compiled with the C compiler.
-	%
-	% XXX Currently the only foreign language we handle is C.
-	%     To make it work properly we'd need to change the
-	%     `ContainsCCode' boolean that we return to instead be a list
-	%     of the foreign languages used, so that mercury_compile.m
-	%     will know which foreign language files have been generated
-	%     which foreign language compilers it needs to invoke,
-	%     and which object files to link into the executable.
+	% The set of foreign languages contained in the code is returned, as
+	% these languages will be output into separate files.
 
-:- pred mlds_to_gcc__compile_to_asm(mlds__mlds, bool, io__state, io__state).
+:- pred mlds_to_gcc__compile_to_asm(mlds__mlds, set(foreign_language),
+		io__state, io__state).
 :- mode mlds_to_gcc__compile_to_asm(in, out, di, uo) is det.
 
 %-----------------------------------------------------------------------------%
@@ -224,7 +216,7 @@
 		maybe_write_string(Verbose, "% GCC back-end done.\n")
 	).
 
-mlds_to_gcc__compile_to_asm(MLDS, ContainsCCode) -->
+mlds_to_gcc__compile_to_asm(MLDS, ForeignLangSet) -->
 	{ MLDS = mlds(ModuleName, AllForeignCode, Imports, Defns0) },
 
 	%
@@ -262,7 +254,7 @@
 		{ ForeignCode = mlds__foreign_code(_Decls, _Imports, [], []) },
 		{ ForeignDefns = [] }
 	->
-		{ ContainsCCode = no },
+		{ ForeignLangSet = set__init },
 		% there's no foreign code, so we don't need to
 		% do anything special
 		{ NeedInitFn = yes }
@@ -274,9 +266,8 @@
 			list__map(make_public, ForeignDefns)) },
 		mlds_to_c__output_mlds(ForeignMLDS, ""),
 		% XXX currently the only foreign code we handle is C;
-		%     see comments above (at the declaration for
-		%     mlds_to_c__compile_to_asm)
-		{ ContainsCCode = yes },
+		% but if we handled others we could just place them here
+		{ ForeignLangSet = set__insert(set__init, c) },
 		{ NeedInitFn = no }
 	),
 
Index: compiler/mlds_to_ilasm.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mlds_to_ilasm.m,v
retrieving revision 1.17
diff -u -r1.17 mlds_to_ilasm.m
--- compiler/mlds_to_ilasm.m	20 Mar 2002 12:36:52 -0000	1.17
+++ compiler/mlds_to_ilasm.m	12 Jun 2002 02:27:15 -0000
@@ -87,6 +87,8 @@
 	sorry(this_file, "language C foreign code not supported").
 handle_foreign_lang(il, _, _) :-
 	sorry(this_file, "language IL foreign code not supported").
+handle_foreign_lang(cplusplus, _, _) :-
+	sorry(this_file, "language C++ foreign code not supported").
 
 	%
 	% Generate the `.il' file.
Index: compiler/mlds_to_mcpp.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mlds_to_mcpp.m,v
retrieving revision 1.26
diff -u -r1.26 mlds_to_mcpp.m
--- compiler/mlds_to_mcpp.m	20 Mar 2002 12:36:53 -0000	1.26
+++ compiler/mlds_to_mcpp.m	12 Jun 2002 02:27:15 -0000
@@ -52,6 +52,8 @@
 :- import_module ml_backend__ilds, ml_backend__ilasm, ml_backend__il_peephole.
 :- import_module ml_backend__ml_util, ml_backend__ml_code_util.
 :- import_module ml_backend__mlds_to_c. /* to output C code for .cpp files */
+:- import_module backend_libs.
+:- import_module backend_libs__foreign.
 :- use_module ll_backend__llds. /* for user_c_code */
 
 :- import_module bool, int, map, string, list, assoc_list, term, std_util.
@@ -200,10 +202,11 @@
 			_ExportDefns)) -->
 	{ HeaderCode = list__reverse(RevHeaderCode) },
 	io__write_list(HeaderCode, "\n", 
-		(pred(foreign_decl_code(Lang, Code, _Context)::in,
+		(pred(foreign_decl_code(Lang, CodeFragments)::in,
 			di, uo) is det -->
 			( { Lang = managed_cplusplus } ->
-				io__write_string(Code)
+				foreign__output_c_code_fragments(
+					CodeFragments)
 			;
 				% ignore it if it isn't MC++
 				[]
Index: compiler/modules.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/modules.m,v
retrieving revision 1.234
diff -u -r1.234 modules.m
--- compiler/modules.m	10 Jun 2002 10:05:50 -0000	1.234
+++ compiler/modules.m	12 Jun 2002 02:27:15 -0000
@@ -2307,6 +2307,13 @@
 			list__foldl(write_foreign_dependency_for_il(DepStream,
 				ModuleName, AllDeps), Langs)
 		;
+			{ Target = c },
+			{ not set__empty(LangSet) }
+		->
+			{ Langs = set__to_sorted_list(LangSet) },
+			list__foldl(write_foreign_dependency_for_c(DepStream,
+				ModuleName, AllDeps), Langs)
+		;
 			[]
 		),
 
@@ -2515,6 +2522,31 @@
 		)
 	).
 
+:- pred write_foreign_dependency_for_c(io__output_stream::in,
+		sym_name::in, list(module_name)::in, foreign_language::in,
+		io__state::di, io__state::uo) is det.
+write_foreign_dependency_for_c(DepStream, ModuleName, _AllDeps, ForeignLang)
+		-->
+	( 
+		{ ForeignModuleName = foreign_language_module_name(
+			ModuleName, ForeignLang) },
+
+			% XXX not a great way to test for creating an external
+			% file
+		{ ForeignExt = foreign_language_file_extension(ForeignLang) }
+	->
+		module_name_to_file_name(ForeignModuleName, ForeignExt, no,
+			ForeignFileName),
+		module_name_to_file_name(ModuleName, ".c", no, CFileName),
+
+		io__write_strings(DepStream, [
+			ForeignFileName, " : ", CFileName, "\n\n"])
+	;
+		% This foreign language doesn't generate an external file
+		% so there are no dependencies to generate.
+		[]
+	).
+
 	% 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
@@ -2531,8 +2563,8 @@
 	% (the rule to generate .dll from .cpp is a pattern rule in
 	% scripts/Mmake.rules).
 	% 
-:- pred write_foreign_dependency_for_il(io__output_stream::in,sym_name::in,
-		list(module_name)::in, foreign_language::in,
+:- pred write_foreign_dependency_for_il(io__output_stream::in,
+		sym_name::in, list(module_name)::in, foreign_language::in,
 		io__state::di, io__state::uo) is det.
 write_foreign_dependency_for_il(DepStream, ModuleName, AllDeps, ForeignLang)
 		-->
@@ -3378,6 +3410,8 @@
 	globals__io_get_target(Target),
 	( { Target = il } ->
 		{ ForeignModulesAndExts = foreign_modules(Modules, DepsMap) }
+	; { Target = c } ->
+		{ ForeignModulesAndExts = foreign_modules(Modules, DepsMap) }
 	;
 		{ ForeignModulesAndExts = [] }
 	),
@@ -3423,6 +3457,13 @@
 					".dll", ForeignBasis, DepStream),
 	io__write_string(DepStream, "\n"),
 
+		% The .os which contain the foreign_code.
+	io__write_string(DepStream, MakeVarName),
+	io__write_string(DepStream, ".foreign_os = "),
+	write_compact_dependencies_list(ForeignModules, "$(os_subdir)",
+					".o", ForeignBasis, DepStream),
+	io__write_string(DepStream, "\n"),
+
 	io__write_string(DepStream, MakeVarName),
 	io__write_string(DepStream, ".init_cs = "),
 	write_compact_dependencies_list(Modules, "$(cs_subdir)", ".c",
@@ -3471,6 +3512,7 @@
 	write_compact_dependencies_list(Modules, "$(os_subdir)", ".$O",
 		Basis, DepStream),
 	write_extra_link_dependencies_list(ExtraLinkObjs, ".$O", DepStream),
+	io__write_string(DepStream, " $(short_example.foreign_os)"),
 	io__write_string(DepStream, "\n"),
 
 	io__write_string(DepStream, MakeVarName),
@@ -4432,7 +4474,7 @@
 
 get_item_foreign_code(Globals, Item, Info0, Info) :-
     ( Item = pragma(Pragma) - Context ->
-	globals__get_backend_foreign_languages(Globals, BackendLangs),
+	globals__get_supported_foreign_languages(Globals, SupportedLangs),
 	globals__get_target(Globals, Target),
 
 	% The code here should match the way that mlds_to_gcc.m
@@ -4445,7 +4487,7 @@
 	% intermodule optimization.
 	(	
 	Pragma = foreign_code(Lang, _),
-		list__member(Lang, BackendLangs)
+		list__member(Lang, SupportedLangs)
 	->
 		Info = Info0 ^ used_foreign_languages :=
 			set__insert(Info0 ^ used_foreign_languages, Lang)
@@ -4466,7 +4508,7 @@
 			)
 		;
 			% is it one of the languages we support?
-			( list__member(NewLang, BackendLangs) ->
+			( list__member(NewLang, SupportedLangs) ->
 				Info = Info0 ^ foreign_proc_languages
 						^ elem(Name) := NewLang
 			;
@@ -4482,7 +4524,7 @@
 		% we need to treat `pragma export' like the
 		% other pragmas for foreign code.
 		Pragma = export(_, _, _, _),
-		list__member(c, BackendLangs)
+		list__member(c, SupportedLangs)
 	->
 		% XXX we assume lang = c for exports
 		Lang = c,
@@ -4495,7 +4537,7 @@
 		% `:- pragma foreign_import_module'.
 		Pragma = foreign_import_module(Lang, Import),
 		Lang = c,
-		list__member(c, BackendLangs)
+		list__member(c, SupportedLangs)
 	->
 		Info = Info0 ^ all_foreign_import_module_info :=
 	    		[foreign_import_module(Lang, Import, Context) | 	
Index: compiler/options.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/options.m,v
retrieving revision 1.374
diff -u -r1.374 options.m
--- compiler/options.m	12 Jun 2002 14:26:50 -0000	1.374
+++ compiler/options.m	13 Jun 2002 01:02:14 -0000
@@ -259,8 +259,12 @@
 	% (the values of these options are implied by the
 	% settings of other options)
 				% The foreign programming languages that this
-				% backend can interface to.
+				% backend can interface to directly.
 		; 	backend_foreign_languages
+				% The foreign programming languages that this
+				% backend can interface to directly or
+				% indirectly.
+		; 	supported_foreign_languages
 				% Stack layout information required to do
 				% a stack trace.
 		;       basic_stack_layout
@@ -504,6 +508,10 @@
 		;	dotnet_library_version
 		;	support_ms_clr
 
+			% C++
+		;	cpp_compiler
+		;	cpp_flags
+
 			% Managed C++
 		;	mcpp_compiler
 		;	mcpp_flags
@@ -810,6 +818,10 @@
 					% The backend_foreign_languages option
 					% depends on the target and is set in
 					% handle_options.
+	supported_foreign_languages-	accumulating([]),
+					% The supported_foreign_languages option
+					% depends on the target and is set in
+					% handle_options.
 	basic_stack_layout	-	bool(no),
 	agc_stack_layout	-	bool(no),
 	procid_stack_layout	-	bool(no),
@@ -1028,6 +1040,10 @@
 	dotnet_library_version	-	string("1.0.3300.0"),
 	support_ms_clr		-	bool(yes),
 
+% C++
+	cpp_compiler		-	string("gcc"),
+	cpp_flags		-	accumulating([]),
+
 % Managed C++
 	mcpp_compiler		-	string("cl"),
 	mcpp_flags		-	accumulating([]),
@@ -1356,6 +1372,8 @@
 % internal use options
 long_option("backend-foreign-languages",
 					backend_foreign_languages).
+long_option("supported-foreign-languages",
+					supported_foreign_languages).
 long_option("agc-stack-layout",		agc_stack_layout).
 long_option("basic-stack-layout",	basic_stack_layout).
 long_option("procid-stack-layout",	procid_stack_layout).
@@ -1621,6 +1639,10 @@
 
 long_option("csharp-compiler",		csharp_compiler).
 long_option("csharp-flags",		csharp_flags).
+
+long_option("cpp-compiler",		cpp_compiler).
+long_option("cpp-flags",		cpp_flags).
+
 
 % link options
 long_option("output-file",		output_file_name).
Index: compiler/prog_io_pragma.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/prog_io_pragma.m,v
retrieving revision 1.50
diff -u -r1.50 prog_io_pragma.m
--- compiler/prog_io_pragma.m	7 May 2002 11:03:12 -0000	1.50
+++ compiler/prog_io_pragma.m	12 Jun 2002 02:27:15 -0000
@@ -1205,6 +1205,7 @@
 
 check_required_attributes(c, Attrs, _Term) = ok(Attrs).
 check_required_attributes(managed_cplusplus, Attrs, _Term) = ok(Attrs).
+check_required_attributes(cplusplus, Attrs, _Term) = ok(Attrs).
 check_required_attributes(csharp, Attrs, _Term) = ok(Attrs).
 check_required_attributes(il, Attrs, Term) = Res :-
 	( [] = list__filter_map(
Index: doc/user_guide.texi
===================================================================
RCS file: /home/mercury1/repository/mercury/doc/user_guide.texi,v
retrieving revision 1.314
diff -u -r1.314 user_guide.texi
--- doc/user_guide.texi	12 Jun 2002 14:26:55 -0000	1.314
+++ doc/user_guide.texi	13 Jun 2002 01:02:25 -0000
@@ -5821,6 +5821,18 @@
 Specify options to be passed to the C compiler.
 
 @sp 1
+ at item --cppflags @var{options}
+ at findex --cppflags
+ at cindex C++ compiler options
+Specify options to be passed to the C++ compiler.
+
+ at sp 1
+ at item --cpp-compiler @var{options}
+ at findex --cppflags
+ at cindex C++ compiler options
+Specify which C++ compiler to use.
+
+ at sp 1
 @item --javac @var{compiler-name}
 @item --java-compiler @var{compiler-name}
 @findex --javac
Index: library/list.m
===================================================================
RCS file: /home/mercury1/repository/mercury/library/list.m,v
retrieving revision 1.105
diff -u -r1.105 list.m
--- library/list.m	12 Mar 2002 16:33:23 -0000	1.105
+++ library/list.m	12 Jun 2002 02:27:15 -0000
@@ -1392,7 +1392,7 @@
 		M = [H0|M1]
         ),
         list__filter_map(P, T0, L1, M1).
-
+	
 list__takewhile(_, [], [], []).
 list__takewhile(P, [X|Xs], Ins, Outs) :-
 	( call(P, X) ->
Index: scripts/Mmake.rules
===================================================================
RCS file: /home/mercury1/repository/mercury/scripts/Mmake.rules,v
retrieving revision 1.125
diff -u -r1.125 Mmake.rules
--- scripts/Mmake.rules	10 Jun 2002 07:03:14 -0000	1.125
+++ scripts/Mmake.rules	12 Jun 2002 02:27:15 -0000
@@ -227,6 +227,22 @@
 endif
 
 # C back-end
+#
+
+# C++ interface -- <module>__cpp_code.o should depend on <module>.c
+# as generating the __cpp_code.cpp file is a side-effect of generating
+# the .c file.
+# XXX but this won't work with gcc backend -- it should depend on 
+# .s instead.
+
+$(os_subdir)%__cpp_code.$O : $(cs_subdir)%.c
+	$(MGNUC) $(ALL_GRADEFLAGS) $(ALL_MGNUCFLAGS) \
+		-c $(cs_subdir)$*__cpp_code.cpp $(OBJFILE_OPT)$@
+
+$(os_subdir)%__cpp_code.pic_o : $(cs_subdir)%.c
+	$(MGNUC) $(ALL_GRADEFLAGS) $(ALL_MGNUCFLAGS) $(CFLAGS_FOR_PIC) \
+		-c $(cs_subdir)$*__cpp_code.cpp $(OBJFILE_OPT)$@
+
 
 # When smart recompilation finds that a module does not need to be
 # recompiled, it only touches the `.c_date' file.



More information about the developers mailing list