[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