[m-rev.] for review: mmc --make for csharp, etc.

Peter Wang novalazy at gmail.com
Wed Sep 29 14:35:25 AEST 2010


This will force an upgrade of the bootstrap compiler.

Branches: main

Add support for the `csharp' grade to `mmc --make', and make it possible to
install the `csharp' grade with `mmake install'.

Also some miscellaneous fixes.


configure.in:
        Require a recent enough bootstrap compiler that recognises C# as a
        language for `pragma foreign_type'.

Mmakefile:
        Use `mmc --make' to install the standard library in csharp grade.

aclocal.m4:
        Search for the Mono C# compiler `gmcs', which is required for generics
        at this time.  Prefer it over the DotGNU C# compiler, which I have not
        tested.

        Search for `mono'.  If found, it will be used in shell scripts to
        launch executables generated via the csharp backend.

        Remove "MS_" prefixes on the variables MS_CSC and MS_ILASM, which are
        not Microsoft-specific.  More importantly, it should be less likely to
        make the mistake of adding an extra underscore to CSCFLAGS and
        ILASMFLAGS.

README.DotNet:
        Conform to variable renamings.

compiler/compile_target_code.m:
        Add new linked target types `csharp_executable', `java_launcher' and
        `erlang_launcher', instead of overloading `executable'.

        Link with `mer_std.dll' and other libraries when generating C#
        executables.  There is no `mer_rt.dll'.

        Pass "/debug" to the C# compiler if `--target-debug' is set.

        Create a shell script to launch the executable if necessary.

        Delete an unused predicate `standard_library_directory_option'.

compiler/file_names.m:
        `.cs' and `.cs_date' are grade-dependent.

compiler/handle_options.m:
        Force `.exe' as the executable file extension in csharp grades.

        Make the `erlang' grade component imply the same options as MLDS
        grades.

compiler/make.m:
        Classify executable target types based on the compilation target.

compiler/make.module_target.m:
        Handle `mmc --grade csharp --make <target>.dll'.

compiler/make.program_target.m:
        Install library DLLs in csharp grades.
        
        Make clean targets remove files for csharp grades.

        Conform to changes.

compiler/make.util.m:
        Add a stub foreign type.

        Conform to changes.

compiler/module_cmds.m:
        Factor out code to generate the shell scripts which launch programs
        compiled in Java, Erlang and C# grades.

compiler/options.m:
        Add `cli_interpreter' option to remember the name of the program which
        should be used to run CLI (.NET) programs.

        Add C#-related options to the help message.

compiler/options_file.m:
        Remove "MS_" prefixes on MS_ILASM_FLAGS and MS_CSC_FLAGS, and remove
        the extra underscore before "FLAGS".  In all uses of the variables,
        they were spelt without the extra underscore.

doc/user_guide.texi:
        Document options and file types related to the C# grade.

library/Mmakefile:
        Pass `mercury_dotnet.cs' to the C# compiler when building the standard
        library.  Suppress some warnings.

        Allow stubs in this directory for csharp grade.

        Conform to variable renamings.

library/builtin.m:
        Uncomment foreign language pragmas for C#.

        Handle null values in C# implementation of `deep_copy'.

library/private_builtin.m:
library/string.m:
        Compare strings by ordinals in C#, instead of culture-specific rules.
        Although the latter is allowed according to the documentation, it is
        likely to slower, and cause confusion when porting between backends.

        Handle negative index in string.set_char.

library/rtti_implementation.m:
        Uncomment foreign language pragmas for C#.

        `System.Type.GetType' only searches the current executing assembly or
        in mscorlib for a type.  As we have to be able to find types in other
        assemblies (e.g. mer_std.dll or user DLLs), explicitly search through
        a list of assemblies.

library/thread.semaphore.m:
        Uncomment foreign language pragmas for C#.

        Fix missing class qualification.

library/array.m:
library/bitmap.m:
library/bool.m:
library/dir.m:
library/exception.m:
library/io.m:
library/mutvar.m:
library/par_builtin.m:
library/region_builtin.m:
library/store.m:
library/thread.m:
library/time.m:
library/univ.m:
library/version_array.m:
        Uncomment foreign language pragmas for C#.

mdbcomp/rtti_access.m:
        Add type and procedure stubs.

runtime/mercury_dotnet.cs.in:
        Override `Equals(object)' methods in `TypeCtorInfo_Struct' and
        `TypeInfo_Struct' classes.  This requires we override `GetHashCode' as
        well.

        Handle nulls arguments to `Equals' methods as is the expected behaviour.

        Override `ToString' in `TypeCtorInfo_Struct' to produce more useful
        output during debugging.

scripts/Mercury.config.in:
        Record the configured CLI_INTERPRETER and pass that to the compiler as
        a flag.

        Conform to variable renamings.

scripts/Mmake.vars.in:
        Pass value of CSCFLAGS from Mmake through to `mmc --make'.

        Conform to variable renamings.

scripts/Mercury.config.bootstrap.in:
scripts/Mmake.rules:
        Conform to variable renaming.

scripts/canonical_grade.sh-subr:
scripts/final_grade_options.sh-subr:
scripts/init_grade_options.sh-subr:
scripts/parse_grade_options.sh-subr:
        Canonicalise high-level code, high-level-data, C# target code to the
        `csharp' grade.

        Handle erlang grades like other grades.

scripts/prepare_install_dir.in:
        Copy `.cs' files from the runtime directory when preparing an install
        directory.

browser/Mmakefile:
compiler/Mmakefile:
deep_profiler/Mmakefile:
mdbcomp/Mmakefile:
profiler/Mmakefile:
runtime/Mmakefile:
slice/Mmakefile:
ssdb/Mmakefile:
trace/Mmakefile:
        Do as other non-C grades in this directory.

        Conform to variable renamings.

tests/hard_coded/foreign_enum_dummy.m:
tests/hard_coded/sub-modules/non_word_mutable.m:
tests/hard_coded/sub-modules/sm_exp_bug.m:
        Make these tests work in C#.

tests/mmc_make/Mmakefile:
        Update a regular expression to account for `mmc --make' writing
        "Making rebuild.exe" on platforms where the .exe suffix is not normally
        used.

tests/mmc_make/complex_test.exp2:
        Add alternative output (minor difference in floating point precision).

tests/debugger/Mmakefile:
tests/debugger/declarative/Mmakefile:
tests/general/structure_reuse/Mmakefile:
tests/hard_coded/Mmakefile:
tests/hard_coded/sub-modules/Mmakefile:
tests/par_conj/Mmakefile:
tests/stm/Mmakefile:
        Disable some tests in the csharp grade.

tests/invalid/Mmakefile:
        Disable some tests in the csharp grade.

        Enable a test which should work in java grades.

tests/valid/Mmakefile:
        Do as other non-C grades in this directory.

        When testing the csharp grade in this directory, produce only the C#
        target files for now.

tests/run_one_test:
        Don't compress a failing test case executable when the executable is
        actually only a shell script.

diff --git a/Mmakefile b/Mmakefile
index 04d25ed..1daf5a6 100644
--- a/Mmakefile
+++ b/Mmakefile
@@ -622,7 +622,7 @@ install_grades: install_main
 	    IWS=`/bin/pwd`/install_grade_dir.$${grade};                       \
 	    (                                                                 \
 		case $${grade} in                                             \
-			java*|erlang*) MMAKE_USE_MMC_MAKE=yes;                \
+			csharp*|java*|erlang*) MMAKE_USE_MMC_MAKE=yes;        \
 		esac;                                                         \
 		scripts/prepare_install_dir $${IWS} &&                        \
 		( cd $${IWS}/boehm_gc &&                                      \
diff --git a/README.DotNet b/README.DotNet
index d3d0114..be6c1ee 100644
--- a/README.DotNet
+++ b/README.DotNet
@@ -158,9 +158,9 @@ C++, C#, Visual Basic, Cobol, Eiffel, SmallTalk, ML, Haskell, Scheme,
 Python, Perl, Component Pascal and others).  
 
 Add a 
-	MS_CSCFLAGS-<modulename>_csharp_code=/reference:<foreignmodulename>.dll
+	CSCFLAGS-<modulename>_csharp_code=/reference:<foreignmodulename>.dll
 or
-	MS_CSCFLAGS-<modulename>_csharp_code=/addmodule:<foreignmodulename>.dll
+	CSCFLAGS-<modulename>_csharp_code=/addmodule:<foreignmodulename>.dll
 
 to your Mmakefile to pass the appropriate flag to the C# compiler so
 that you can reference another DLL from the C# code.
diff --git a/aclocal.m4 b/aclocal.m4
index 6fc261e..0c4c8bf 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -248,15 +248,15 @@ ILASM=`basename "$ILASM"`
 GACUTIL=`basename "$GACUTIL"`
 
 # Check for the C# (C sharp) compiler.
+# gmcs is the Mono C# compiler targeting the 2.0 runtime (with generics).
 # cscc is the DotGNU C# compiler.
-# mcs is the mono C# compiler.
-AC_PATH_PROGS(MS_CSC, csc cscc mcs)
-MS_CSC=`basename "$MS_CSC"`
+AC_PATH_PROGS(CSC, csc gmcs cscc)
+CSC=`basename "$CSC"`
 
 # We default to the Beta 2 version of the library
 mercury_cv_microsoft_dotnet_library_version=1.0.2411.0
 if	test $mercury_cv_microsoft_dotnet = "yes" &&
-	test "$MS_CSC" != "";
+	test "$CSC" != "";
 then
 	AC_MSG_CHECKING(version of .NET libraries)
 	cat > conftest.cs << EOF
@@ -274,8 +274,8 @@ then
 	}
 EOF
 	if
-		echo $MS_CSC conftest.cs >&AC_FD_CC 2>&1 && \
-			$MS_CSC conftest.cs  >&AC_FD_CC 2>&1 && \
+		echo $CSC conftest.cs >&AC_FD_CC 2>&1 && \
+			$CSC conftest.cs  >&AC_FD_CC 2>&1 && \
 			./conftest > conftest.out 2>&1
 	then
 		mercury_cv_microsoft_dotnet_library_version=`cat conftest.out`
@@ -298,13 +298,18 @@ MS_DOTNET_LIBRARY_VERSION=$mercury_cv_microsoft_dotnet_library_version
 AC_PATH_PROGS(MS_AL, al ilalink)
 MS_AL=`basename "$MS_AL"`
 
+# Check for an implementation of the Common Language Infrastructure.
+AC_PATH_PROGS(CLI_INTERPRETER, mono)
+MONO=`basename "$CLI_INTERPRETER"`
+
 AC_SUBST(ILASM)
 AC_SUBST(GACUTIL)
-AC_SUBST(MS_CSC)
+AC_SUBST(CSC)
 AC_SUBST(MS_AL)
 AC_SUBST(MS_DOTNET_SDK_DIR)
 AC_SUBST(MS_DOTNET_LIBRARY_VERSION)
 AC_SUBST(MS_VISUALCPP_DIR)
+AC_SUBST(CLI_INTERPRETER)
 ])
 
 #-----------------------------------------------------------------------------#
diff --git a/browser/Mmakefile b/browser/Mmakefile
index aa80c8a..6e8e726 100644
--- a/browser/Mmakefile
+++ b/browser/Mmakefile
@@ -99,7 +99,7 @@ LN	= ln
 # complete, so we need to pass `--allow-stubs' to get them to compile.
 # Since the standard library is compiled with `--halt-at-warn',
 # we also need `--no-warn-stubs'.
-ifneq ("$(filter il% java% erlang%,$(GRADE))","")
+ifneq ("$(filter il% csharp% java% erlang%,$(GRADE))","")
 MCFLAGS += --allow-stubs --no-warn-stubs
 endif
 
@@ -252,7 +252,7 @@ realclean_local:
 .PHONY: install
 install: install_library
 
-ifneq ("$(filter il% erlang%,$(GRADE))","")
+ifneq ("$(filter il% csharp% erlang%,$(GRADE))","")
 
 # there is no browser in the .NET or Erlang backends
 
diff --git a/compiler/Mmakefile b/compiler/Mmakefile
index 737e19a..8a42466 100644
--- a/compiler/Mmakefile
+++ b/compiler/Mmakefile
@@ -218,7 +218,7 @@ mercury_compile_init.$O: $(MC_PROG)_init.$O
 # (We used to just build mlds_to_gcc.err, but that caused bootstrapping problems
 # with the source distribution; using the .c files is little more robust.)
 
-ifeq ("$(filter il% java% erlang%,$(GRADE))","")
+ifeq ("$(filter il% csharp% java% erlang%,$(GRADE))","")
 
 .PHONY: depend
 depend:		COMP_FLAGS mlds_to_gcc.depend
@@ -239,7 +239,7 @@ endif
 # compiler if one of the libraries changes.
 
 ifeq ($(findstring il,$(GRADE)),il)        
-MS_CSCFLAGS=/lib
+CSCFLAGS=/lib
 
 # This line works around an Mmake bug: mmake doesn't record
 # dependencies properly with --transitive-intermodule-optimization
diff --git a/compiler/compile_target_code.m b/compiler/compile_target_code.m
index 2b6881f..4d0b126 100644
--- a/compiler/compile_target_code.m
+++ b/compiler/compile_target_code.m
@@ -119,8 +119,11 @@
     --->    executable
     ;       static_library
     ;       shared_library
+    ;       csharp_executable
     ;       csharp_library
+    ;       java_launcher
     ;       java_archive
+    ;       erlang_launcher
     ;       erlang_archive.
 
     % link(TargetType, MainModuleName, ObjectFileNames, Globals, Succeeded,
@@ -1687,53 +1690,43 @@ link(ErrorStream, LinkTargetType, ModuleName, ObjectsList, Globals, Succeeded,
         !IO) :-
     globals.lookup_bool_option(Globals, verbose, Verbose),
     globals.lookup_bool_option(Globals, statistics, Stats),
-    globals.get_target(Globals, Target),
 
     maybe_write_string(Verbose, "% Linking...\n", !IO),
     link_output_filename(Globals, LinkTargetType, ModuleName, _Ext,
         OutputFileName, !IO),
     (
+        LinkTargetType = executable,
+        link_exe_or_shared_lib(Globals, ErrorStream, LinkTargetType,
+            ModuleName, OutputFileName, ObjectsList, LinkSucceeded, !IO)
+    ;
         LinkTargetType = static_library,
         create_archive(Globals, ErrorStream, OutputFileName, yes, ObjectsList,
             LinkSucceeded, !IO)
     ;
-        LinkTargetType = csharp_library,
+        LinkTargetType = shared_library,
+        link_exe_or_shared_lib(Globals, ErrorStream, LinkTargetType,
+            ModuleName, OutputFileName, ObjectsList, LinkSucceeded, !IO)
+    ;
+        ( LinkTargetType = csharp_executable
+        ; LinkTargetType = csharp_library
+        ),
         % XXX C# see also older predicate compile_csharp_file
         create_csharp_exe_or_lib(Globals, ErrorStream, LinkTargetType,
-            OutputFileName, ObjectsList, LinkSucceeded, !IO)
+            ModuleName, OutputFileName, ObjectsList, LinkSucceeded, !IO)
+    ;
+        LinkTargetType = java_launcher,
+        create_java_shell_script(Globals, ModuleName, LinkSucceeded, !IO)
     ;
         LinkTargetType = java_archive,
         create_java_archive(Globals, ErrorStream, OutputFileName, ObjectsList,
             LinkSucceeded, !IO)
     ;
+        LinkTargetType = erlang_launcher,
+        create_erlang_shell_script(Globals, ModuleName, LinkSucceeded, !IO)
+    ;
         LinkTargetType = erlang_archive,
         create_erlang_archive(Globals, ErrorStream, ModuleName, OutputFileName,
             ObjectsList, LinkSucceeded, !IO)
-    ;
-        LinkTargetType = executable,
-        (
-            Target = target_erlang,
-            create_erlang_shell_script(Globals, ModuleName, LinkSucceeded, !IO)
-        ;
-            Target = target_java,
-            create_java_shell_script(Globals, ModuleName, LinkSucceeded, !IO)
-        ;
-            Target = target_csharp,
-            create_csharp_exe_or_lib(Globals, ErrorStream, LinkTargetType,
-                OutputFileName, ObjectsList, LinkSucceeded, !IO)
-        ;
-            ( Target = target_c
-            ; Target = target_il
-            ; Target = target_asm
-            ; Target = target_x86_64
-            ),
-            link_exe_or_shared_lib(Globals, ErrorStream, LinkTargetType,
-                ModuleName, OutputFileName, ObjectsList, LinkSucceeded, !IO)
-        )
-    ;
-        LinkTargetType = shared_library,
-        link_exe_or_shared_lib(Globals, ErrorStream, LinkTargetType,
-            ModuleName, OutputFileName, ObjectsList, LinkSucceeded, !IO)
     ),
     maybe_report_stats(Stats, !IO),
     (
@@ -1751,6 +1744,11 @@ link(ErrorStream, LinkTargetType, ModuleName, ObjectsList, Globals, Succeeded,
 link_output_filename(Globals, LinkTargetType, ModuleName, Ext, OutputFileName,
         !IO) :-
     (
+        LinkTargetType = executable,
+        globals.lookup_string_option(Globals, executable_file_extension, Ext),
+        module_name_to_file_name(Globals, ModuleName, Ext, do_create_dirs,
+            OutputFileName, !IO)
+    ;
         LinkTargetType = static_library,
         globals.lookup_string_option(Globals, library_extension, Ext),
         module_name_to_lib_file_name(Globals, "lib", ModuleName, Ext,
@@ -1761,11 +1759,24 @@ link_output_filename(Globals, LinkTargetType, ModuleName, Ext, OutputFileName,
         module_name_to_lib_file_name(Globals, "lib", ModuleName, Ext,
             do_create_dirs, OutputFileName, !IO)
     ;
+        LinkTargetType = csharp_executable,
+        Ext = ".exe",
+        module_name_to_file_name(Globals, ModuleName, Ext,
+            do_create_dirs, OutputFileName, !IO)
+    ;
         LinkTargetType = csharp_library,
         Ext = ".dll",
         module_name_to_file_name(Globals, ModuleName, Ext,
             do_create_dirs, OutputFileName, !IO)
     ;
+        ( LinkTargetType = java_launcher
+        ; LinkTargetType = erlang_launcher
+        ),
+        % These are shell scripts.
+        Ext = "",
+        module_name_to_file_name(Globals, ModuleName, Ext,
+            do_create_dirs, OutputFileName, !IO)
+    ;
         LinkTargetType = java_archive,
         Ext = ".jar",
         module_name_to_file_name(Globals, ModuleName, Ext,
@@ -1775,29 +1786,6 @@ link_output_filename(Globals, LinkTargetType, ModuleName, Ext, OutputFileName,
         Ext = ".beams",
         module_name_to_lib_file_name(Globals, "lib", ModuleName, Ext,
             do_create_dirs, OutputFileName, !IO)
-    ;
-        LinkTargetType = executable,
-        globals.get_target(Globals, Target),
-        (
-            ( Target = target_erlang
-            ; Target = target_java
-            ),
-            % These are shell scripts.
-            Ext = ""
-        ;
-            Target = target_csharp,
-            Ext = ".exe"
-        ;
-            ( Target = target_c
-            ; Target = target_il
-            ; Target = target_asm
-            ; Target = target_x86_64
-            ),
-            globals.lookup_string_option(Globals, executable_file_extension,
-                Ext)
-        ),
-        module_name_to_file_name(Globals, ModuleName, Ext, do_create_dirs,
-            OutputFileName, !IO)
     ).
 
 :- pred link_exe_or_shared_lib(globals::in, io.output_stream::in,
@@ -2029,16 +2017,23 @@ get_mercury_std_libs(Globals, TargetType, StdLibs) :-
             ; TargetType = static_library
             ; TargetType = shared_library
             ),
-            globals.lookup_string_option(Globals, library_extension, LibExt)
-        ;
-            TargetType = csharp_library,
-            unexpected(this_file, "get_mercury_std_libs: csharp_library")
+            globals.lookup_string_option(Globals, library_extension, LibExt),
+            globals.lookup_string_option(Globals, mercury_linkage,
+                MercuryLinkage)
         ;
-            TargetType = java_archive,
-            unexpected(this_file, "get_mercury_std_libs: java_archive")
+            ( TargetType = csharp_executable
+            ; TargetType = csharp_library
+            ),
+            LibExt = ".dll",
+            MercuryLinkage = "csharp"
         ;
-            TargetType = erlang_archive,
-            unexpected(this_file, "get_mercury_std_libs: erlang_archive")
+            ( TargetType = java_launcher
+            ; TargetType = java_archive
+            ; TargetType = erlang_launcher
+            ; TargetType = erlang_archive
+            ),
+            unexpected(this_file,
+                "get_mercury_std_libs: " ++ string(TargetType))
         ),
         grade_directory_component(Globals, GradeDir),
 
@@ -2137,7 +2132,6 @@ get_mercury_std_libs(Globals, TargetType, StdLibs) :-
             SharedSourceDebugLibs = ""
         ),
 
-        globals.lookup_string_option(Globals, mercury_linkage, MercuryLinkage),
         link_lib_args(Globals, TargetType, StdLibDir, GradeDir, LibExt,
             "mer_std", StaticStdLib, StdLib),
         link_lib_args(Globals, TargetType, StdLibDir, GradeDir, LibExt,
@@ -2158,6 +2152,12 @@ get_mercury_std_libs(Globals, TargetType, StdLibs) :-
                 RuntimeLib,
                 SharedGCLibs
             ])
+        ; MercuryLinkage = "csharp" ->
+            StdLibs = string.join_list(" ", [
+                SharedTraceLibs,
+                SharedSourceDebugLibs,
+                StdLib
+            ])
         ;
             unexpected(this_file, "unknown linkage " ++ MercuryLinkage)
         )
@@ -2171,7 +2171,26 @@ get_mercury_std_libs(Globals, TargetType, StdLibs) :-
 
 link_lib_args(Globals, TargetType, StdLibDir, GradeDir, LibExt, Name,
         StaticArg, SharedArg) :-
-    StaticLibName = "lib" ++ Name ++ LibExt,
+    (
+        ( TargetType = executable
+        ; TargetType = shared_library
+        ; TargetType = static_library
+        ),
+        LibPrefix = "lib"
+    ;
+        ( TargetType = csharp_executable
+        ; TargetType = csharp_library
+        ),
+        LibPrefix = ""
+    ;
+        ( TargetType = java_launcher
+        ; TargetType = java_archive
+        ; TargetType = erlang_launcher
+        ; TargetType = erlang_archive
+        ),
+        unexpected(this_file, "link_lib_args: " ++ string(TargetType))
+    ),
+    StaticLibName = LibPrefix ++ Name ++ LibExt,
     StaticArg = quote_arg(StdLibDir/"lib"/GradeDir/StaticLibName),
     make_link_lib(Globals, TargetType, Name, SharedArg).
 
@@ -2218,17 +2237,20 @@ make_link_lib(Globals, TargetType, LibName, LinkOpt) :-
         globals.lookup_string_option(Globals, LinkLibSuffix, Suffix),
         LinkOpt = quote_arg(LinkLibOpt ++ LibName ++ Suffix)
     ;
-        TargetType = csharp_library,
-        unexpected(this_file, "make_link_lib: csharp_library")
-    ;
-        TargetType = java_archive,
-        unexpected(this_file, "make_link_lib: java_archive")
-    ;
-        TargetType = erlang_archive,
-        unexpected(this_file, "make_link_lib: erlang_archive")
+        ( TargetType = csharp_executable
+        ; TargetType = csharp_library
+        ),
+        LinkLibOpt = "/r:",
+        Suffix = ".dll",
+        LinkOpt = quote_arg(LinkLibOpt ++ LibName ++ Suffix)
     ;
-        TargetType = static_library,
-        unexpected(this_file, "make_link_lib: static_library")
+        ( TargetType = static_library
+        ; TargetType = java_launcher
+        ; TargetType = java_archive
+        ; TargetType = erlang_launcher
+        ; TargetType = erlang_archive
+        ),
+        unexpected(this_file, "make_link_lib: " ++ string(TargetType))
     ).
 
 :- pred get_runtime_library_path_opts(globals::in, linked_target_type::in,
@@ -2302,20 +2324,18 @@ get_system_libs(Globals, TargetType, SystemLibs) :-
         TargetType = shared_library,
         globals.lookup_string_option(Globals, shared_libs, OtherSystemLibs)
     ;
-        TargetType = static_library,
-        unexpected(this_file, "get_std_libs: static library")
-    ;
-        TargetType = csharp_library,
-        unexpected(this_file, "get_std_libs: csharp library")
-    ;
-        TargetType = java_archive,
-        unexpected(this_file, "get_std_libs: java archive")
-    ;
-        TargetType = erlang_archive,
-        unexpected(this_file, "get_std_libs: erlang archive")
-    ;
         TargetType = executable,
         globals.lookup_string_option(Globals, math_lib, OtherSystemLibs)
+    ;
+        ( TargetType = static_library
+        ; TargetType = csharp_executable
+        ; TargetType = csharp_library
+        ; TargetType = java_launcher
+        ; TargetType = java_archive
+        ; TargetType = erlang_launcher
+        ; TargetType = erlang_archive
+        ),
+        unexpected(this_file, "get_std_libs: " ++ string(TargetType))
     ),
 
     SystemLibs = string.join_list(" ",
@@ -2341,14 +2361,18 @@ post_link_make_symlink_or_copy(ErrorStream, LinkTargetType, ModuleName,
         globals.set_option(use_grade_subdirs, bool(no),
             NoSubdirGlobals0, NoSubdirGlobals),
         ( 
-            LinkTargetType = executable,
+            ( LinkTargetType = executable
+            ; LinkTargetType = csharp_executable
+            ; LinkTargetType = csharp_library
+            ; LinkTargetType = java_launcher
+            ; LinkTargetType = java_archive
+            ; LinkTargetType = erlang_launcher
+            ),
             module_name_to_file_name(NoSubdirGlobals, ModuleName, Ext,
                 do_not_create_dirs, UserDirFileName, !IO)
         ;
             ( LinkTargetType = static_library
             ; LinkTargetType = shared_library
-            ; LinkTargetType = csharp_library
-            ; LinkTargetType = java_archive
             ; LinkTargetType = erlang_archive
             ),
             module_name_to_lib_file_name(NoSubdirGlobals, "lib", ModuleName,
@@ -2402,7 +2426,29 @@ shared_libraries_supported(Globals, Supported) :-
 
 process_link_library(Globals, MercuryLibDirs, LibName, LinkerOpt, !Succeeded,
         !IO) :-
+    globals.get_target(Globals, Target),
+    (
+        ( Target = target_c
+        ; Target = target_asm
+        ; Target = target_x86_64
+        ),
     globals.lookup_string_option(Globals, mercury_linkage, MercuryLinkage),
+        LinkOpt = "-l"
+    ;
+        Target = target_csharp,
+        MercuryLinkage = "shared",
+        LinkOpt = "/r:"
+    ;
+        Target = target_il,
+        unexpected(this_file, "process_link_library: target_java")
+    ;
+        Target = target_java,
+        unexpected(this_file, "process_link_library: target_java")
+    ;
+        Target = target_erlang,
+        unexpected(this_file, "process_link_library: target_erlang")
+    ),
+
     globals.lookup_accumulating_option(Globals, mercury_libraries,
         MercuryLibs),
     (
@@ -2432,7 +2478,7 @@ process_link_library(Globals, MercuryLibDirs, LibName, LinkerOpt, !Succeeded,
             !:Succeeded = no
         )
     ;
-        LinkerOpt = "-l" ++ LibName
+        LinkerOpt = LinkOpt ++ LibName
     ).
 
 :- pred create_archive(globals::in, io.output_stream::in, file_name::in,
@@ -2478,11 +2524,11 @@ create_archive(Globals, ErrorStream, LibFileName, Quote, ObjectList,
     ).
 
 :- pred create_csharp_exe_or_lib(globals::in, io.output_stream::in,
-    linked_target_type::in, file_name::in, list(file_name)::in, bool::out,
-    io::di, io::uo) is det.
+    linked_target_type::in, module_name::in, file_name::in, list(file_name)::in,
+    bool::out, io::di, io::uo) is det.
 
-create_csharp_exe_or_lib(Globals, ErrorStream, LinkTargetType, OutputFileName,
-        SourceList, Succeeded, !IO) :-
+create_csharp_exe_or_lib(Globals, ErrorStream, LinkTargetType, MainModuleName,
+        OutputFileName, SourceList, Succeeded, !IO) :-
     globals.lookup_string_option(Globals, csharp_compiler, CSharpCompiler),
     globals.lookup_bool_option(Globals, highlevel_data, HighLevelData),
     (
@@ -2492,26 +2538,95 @@ create_csharp_exe_or_lib(Globals, ErrorStream, LinkTargetType, OutputFileName,
         HighLevelData = no,
         HighLevelDataOpt = ""
     ),
+    globals.lookup_bool_option(Globals, target_debug, Debug),
+    (
+        Debug = yes,
+        DebugOpt = "/debug "
+    ;
+        Debug = no,
+        DebugOpt = ""
+    ),
     globals.lookup_accumulating_option(Globals, csharp_flags, CSCFlagsList),
     (
-        LinkTargetType = executable,
+        LinkTargetType = csharp_executable,
         TargetOption = "/target:exe"
     ;
         LinkTargetType = csharp_library,
         TargetOption = "/target:library"
     ;
-        ( LinkTargetType = static_library
+        ( LinkTargetType = executable
+        ; LinkTargetType = static_library
         ; LinkTargetType = shared_library
+        ; LinkTargetType = java_launcher
         ; LinkTargetType = java_archive
+        ; LinkTargetType = erlang_launcher
         ; LinkTargetType = erlang_archive
         ),
         unexpected(this_file, "create_csharp_exe_or_lib: wrong target type")
     ),
-    Cmd = string.join_list(" ", [CSharpCompiler, HighLevelDataOpt,
-        TargetOption, "/out:" ++ OutputFileName
-        | CSCFlagsList ++ SourceList]),
+
+    globals.lookup_accumulating_option(Globals, link_library_directories,
+        LinkLibraryDirectoriesList),
+    LinkerPathFlag = "/lib:",
+    join_quoted_string_list(LinkLibraryDirectoriesList, LinkerPathFlag, "",
+        " ", LinkLibraryDirectories),
+
+    get_link_libraries(Globals, MaybeLinkLibraries, !IO),
+    (   
+        MaybeLinkLibraries = yes(LinkLibrariesList),
+        join_quoted_string_list(LinkLibrariesList, "", "", " ",
+            LinkLibraries)
+    ;
+        MaybeLinkLibraries = no,
+        LinkLibraries = ""
+    ),
+
+    get_mercury_std_libs(Globals, LinkTargetType, MercuryStdLibs),
+
+    Cmd = string.join_list(" ", [
+        CSharpCompiler,
+        HighLevelDataOpt,
+        DebugOpt,
+        TargetOption,
+        "/out:" ++ OutputFileName,
+        LinkLibraryDirectories,
+        LinkLibraries,
+        MercuryStdLibs] ++
+        CSCFlagsList ++
+        SourceList),
     invoke_system_command(Globals, ErrorStream, cmd_verbose_commands, Cmd,
-        Succeeded, !IO).
+        Succeeded0, !IO),
+
+    % Also create a shell script to launch it if necessary.
+    (
+        Succeeded0 = yes,
+        LinkTargetType = csharp_executable,
+        globals.lookup_string_option(Globals, cli_interpreter, CLI),
+        CLI \= ""
+    ->
+        create_launcher_shell_script(Globals, MainModuleName,
+            write_cli_shell_script(Globals, OutputFileName),
+            Succeeded, !IO)
+    ;
+        Succeeded = Succeeded0
+    ).
+
+:- pred write_cli_shell_script(globals::in, string::in, io.output_stream::in,
+    io::di, io::uo) is det.
+
+write_cli_shell_script(Globals, ExeFileName, Stream, !IO) :-
+    globals.lookup_string_option(Globals, cli_interpreter, CLI),
+    globals.lookup_accumulating_option(Globals, link_library_directories,
+        LinkLibraryDirectoriesList),
+    join_quoted_string_list(LinkLibraryDirectoriesList, "", "",
+        ":", LinkLibraryDirectories),
+    list.foldl(io.write_string(Stream), [
+        "#!/bin/sh\n",
+        "MONO_PATH=$MONO_PATH:", LinkLibraryDirectories, "\n",
+        "export MONO_PATH\n",
+        "CLI_INTERPRETER=${CLI_INTERPRETER:-", CLI, "}\n",
+        "exec $CLI_INTERPRETER ", ExeFileName, " \"$@\"\n"
+    ], !IO).
 
 :- pred create_java_archive(globals::in, io.output_stream::in, file_name::in,
     list(file_name)::in, bool::out, io::di, io::uo) is det.
@@ -2653,8 +2768,11 @@ get_object_code_type(Globals, FileType, ObjectCodeType) :-
         PIC = no,
         (
             ( FileType = static_library
+            ; FileType = csharp_executable
             ; FileType = csharp_library
+            ; FileType = java_launcher
             ; FileType = java_archive
+            ; FileType = erlang_launcher
             ; FileType = erlang_archive
             ),
             ObjectCodeType = non_pic
@@ -2702,33 +2820,6 @@ get_linked_target_type(Globals, LinkedTargetType) :-
 
 %-----------------------------------------------------------------------------%
 
-:- pred standard_library_directory_option(globals::in, string::out,
-    io::di, io::uo) is det.
-
-standard_library_directory_option(Globals, Opt, !IO) :-
-    globals.lookup_maybe_string_option(Globals,
-        mercury_standard_library_directory, MaybeStdLibDir),
-    globals.lookup_maybe_string_option(Globals,
-        mercury_configuration_directory, MaybeConfDir),
-    (
-        MaybeStdLibDir = yes(StdLibDir),
-        Opt0 = "--mercury-standard-library-directory " ++ StdLibDir ++ " ",
-        (
-            MaybeConfDir = yes(ConfDir),
-            ConfDir \= StdLibDir
-        ->
-            Opt = Opt0 ++
-                "--mercury-configuration-directory " ++ ConfDir ++ " "
-        ;
-            Opt = Opt0
-        )
-    ;
-        MaybeStdLibDir = no,
-        Opt = "--no-mercury-standard-library-directory "
-    ).
-
-%-----------------------------------------------------------------------------%
-
     % join_string_list(Strings, Prefix, Suffix, Separator, Result):
     %
     % Appends the strings in the list `Strings' together into the string
diff --git a/compiler/file_names.m b/compiler/file_names.m
index f5f6ed4..401b0ec 100644
--- a/compiler/file_names.m
+++ b/compiler/file_names.m
@@ -548,6 +548,8 @@ file_is_arch_or_grade_dependent_2(".pic_s").
 file_is_arch_or_grade_dependent_2(".pic_s_date").
 file_is_arch_or_grade_dependent_2(".il").
 file_is_arch_or_grade_dependent_2(".il_date").
+file_is_arch_or_grade_dependent_2(".cs").
+file_is_arch_or_grade_dependent_2(".cs_date").
 file_is_arch_or_grade_dependent_2(".java").
 file_is_arch_or_grade_dependent_2(".java_date").
 file_is_arch_or_grade_dependent_2(".class").
diff --git a/compiler/handle_options.m b/compiler/handle_options.m
index f333de3..86b83e2 100644
--- a/compiler/handle_options.m
+++ b/compiler/handle_options.m
@@ -754,7 +754,14 @@ convert_options_to_globals(OptionTable0, Target, GC_Method, TagsMethod0,
         globals.set_option(pretest_equality_cast_pointers, bool(yes),
             !Globals),
         globals.set_option(libgrade_install_check, bool(no), !Globals),
-        globals.set_option(cross_compiling, bool(yes), !Globals)
+        globals.set_option(cross_compiling, bool(yes), !Globals),
+        (
+            Target = target_csharp,
+            globals.set_option(executable_file_extension, string(".exe"),
+                !Globals)
+        ;
+            Target = target_java
+        )
     ;
         ( Target = target_c
         ; Target = target_il
@@ -2785,7 +2792,13 @@ grade_component_table("csharp", comp_gcc_ext, [
         highlevel_code          - bool(yes),
         highlevel_data          - bool(yes)],
         yes([string("csharp")]), yes).
-grade_component_table("erlang", comp_gcc_ext, [],
+grade_component_table("erlang", comp_gcc_ext, [
+        asm_labels              - bool(no),
+        gcc_non_local_gotos     - bool(no),
+        gcc_global_registers    - bool(no),
+        gcc_nested_functions    - bool(no),
+        highlevel_code          - bool(yes),
+        highlevel_data          - bool(yes)],
         yes([string("erlang")]), yes).
 
     % Parallelism/multithreading components.
diff --git a/compiler/make.m b/compiler/make.m
index a60db4c..a239e27 100644
--- a/compiler/make.m
+++ b/compiler/make.m
@@ -441,7 +441,8 @@ classify_target(Globals, FileName, ModuleName - TargetType) :-
         TargetType = misc_target(misc_target_build_library),
         file_name_to_module_name(ModuleNameStr, ModuleName)
     ;
-        TargetType = linked_target(executable),
+        ExecutableType = get_executable_type(Globals),
+        TargetType = linked_target(ExecutableType),
         file_name_to_module_name(FileName, ModuleName)
     ).
 
@@ -481,7 +482,8 @@ classify_target_2(Globals, ModuleNameStr0, Suffix, ModuleName - TargetType) :-
             Suffix)
     ->
         ModuleNameStr = ModuleNameStr0,
-        TargetType = linked_target(executable)
+        ExecutableType = get_executable_type(Globals),
+        TargetType = linked_target(ExecutableType)
     ;
         Suffix = ".beams",
         string.append("lib", ModuleNameStr1, ModuleNameStr0)
@@ -554,6 +556,28 @@ search_backwards_for_dot(String, Index, DotIndex) :-
         search_backwards_for_dot(String, Index - 1, DotIndex)
     ).
 
+:- func get_executable_type(globals) = linked_target_type.
+
+get_executable_type(Globals) = ExecutableType :-
+    globals.get_target(Globals, CompilationTarget),
+    (
+        ( CompilationTarget = target_c
+        ; CompilationTarget = target_il
+        ; CompilationTarget = target_asm
+        ; CompilationTarget = target_x86_64
+        ),
+        ExecutableType = executable
+    ;
+        CompilationTarget = target_csharp,
+        ExecutableType = csharp_executable
+    ;
+        CompilationTarget = target_java,
+        ExecutableType = java_launcher
+    ;
+        CompilationTarget = target_erlang,
+        ExecutableType = erlang_launcher
+    ).
+
 %-----------------------------------------------------------------------------%
 
 :- type last_hash
diff --git a/compiler/make.module_target.m b/compiler/make.module_target.m
index 4820679..66d7cf4 100644
--- a/compiler/make.module_target.m
+++ b/compiler/make.module_target.m
@@ -538,7 +538,10 @@ build_object_code(Globals, ModuleName, Target, PIC, ErrorStream, Imports,
         compile_java_files(ErrorStream, [JavaFile], Globals, Succeeded, !IO)
     ;
         Target = target_csharp,
-        sorry(this_file, "NYI mmc --make and target csharp")
+        module_name_to_file_name(Globals, ModuleName, ".cs", do_create_dirs,
+            CsharpFile, !IO),
+        compile_target_code.link(ErrorStream, csharp_library, ModuleName,
+            [CsharpFile], Globals, Succeeded, !IO)
     ;
         Target = target_il,
         il_assemble(ErrorStream, ModuleName, Imports ^ mai_has_main,
diff --git a/compiler/make.program_target.m b/compiler/make.program_target.m
index f046684..fc41772 100644
--- a/compiler/make.program_target.m
+++ b/compiler/make.program_target.m
@@ -68,10 +68,13 @@ make_linked_target(Globals, LinkedTargetFile, LinkedTargetSucceeded,
         ExtraOptions = ["--compile-to-shared-lib"]
     ;
         ( FileType = executable
+        ; FileType = static_library
+        ; FileType = csharp_executable
         ; FileType = csharp_library
+        ; FileType = java_launcher
         ; FileType = java_archive
+        ; FileType = erlang_launcher
         ; FileType = erlang_archive
-        ; FileType = static_library
         ),
         ExtraOptions = []
     ),
@@ -268,7 +271,7 @@ make_linked_target_2(LinkedTargetFile, Globals, _, Succeeded, !Info, !IO) :-
                         CompilationTarget, PIC, DepsSuccess, BuildDepsResult)
                     ),
                 linked_target_cleanup(Globals, MainModuleName, FileType,
-                    OutputFileName, CompilationTarget),
+                    OutputFileName),
                 Succeeded, !Info, !IO)
         ;
             Succeeded = no
@@ -477,23 +480,22 @@ build_linked_target_2(Globals, MainModuleName, FileType, OutputFileName,
     AllModulesList = set.to_sorted_list(AllModules),
     (
         FileType = executable,
-        (
-            ( CompilationTarget = target_c
-            ; CompilationTarget = target_asm
-            ),
             make_init_obj_file(NoLinkObjsGlobals, ErrorStream, MainModuleName,
                 AllModulesList, InitObjectResult, !IO),
             MaybeInitObjectResult = yes(InitObjectResult)
         ;
-            CompilationTarget = target_erlang,
+        FileType = erlang_launcher,
             make_erlang_program_init_file(NoLinkObjsGlobals, ErrorStream,
                 MainModuleName, AllModulesList, InitObjectResult, !IO),
             MaybeInitObjectResult = yes(InitObjectResult)
         ;
-            ( CompilationTarget = target_il
-            ; CompilationTarget = target_csharp
-            ; CompilationTarget = target_java
-            ; CompilationTarget = target_x86_64
+        ( FileType = static_library
+        ; FileType = shared_library
+        ; FileType = csharp_executable
+        ; FileType = csharp_library
+        ; FileType = java_launcher
+        ; FileType = java_archive
+        ; FileType = erlang_archive
             ),
             MaybeInitObjectResult = no
         ),
@@ -503,7 +505,7 @@ build_linked_target_2(Globals, MainModuleName, FileType, OutputFileName,
                 InitObjectResult1 = yes(InitObject),
                 % We may need to update the timestamp of the `_init.o'
                 % or `_init.beam' file.
-                !:Info = !.Info ^ file_timestamps :=
+            !Info ^ file_timestamps :=
                     map.delete(!.Info ^ file_timestamps, InitObject),
                 InitObjects = [InitObject],
                 DepsResult2 = BuildDepsResult
@@ -516,16 +518,6 @@ build_linked_target_2(Globals, MainModuleName, FileType, OutputFileName,
             MaybeInitObjectResult = no,
             DepsResult2 = BuildDepsResult,
             InitObjects = []
-        )
-    ;
-        ( FileType = static_library
-        ; FileType = shared_library
-        ; FileType = csharp_library
-        ; FileType = java_archive
-        ; FileType = erlang_archive
-        ),
-        DepsResult2 = BuildDepsResult,
-        InitObjects = []
     ),
 
     ObjectsToCheck = InitObjects ++ LinkObjects,
@@ -702,21 +694,25 @@ join_string_list([String | Strings], Prefix, Suffix, Separator, Result) :-
     ).
 
 :- pred linked_target_cleanup(globals::in, module_name::in,
-    linked_target_type::in, file_name::in, compilation_target::in,
+    linked_target_type::in, file_name::in,
     make_info::in, make_info::out, io::di, io::uo) is det.
 
 linked_target_cleanup(Globals, MainModuleName, FileType, OutputFileName,
-        CompilationTarget, !Info, !IO) :-
+        !Info, !IO) :-
     make_remove_file(Globals, verbose_make, OutputFileName, !Info, !IO),
     (
         FileType = executable,
-        ( CompilationTarget = target_c
-        ; CompilationTarget = target_asm
-        )
-    ->
         remove_init_files(Globals, verbose_make, MainModuleName, !Info, !IO)
     ;
-        true
+        ( FileType = static_library
+        ; FileType = shared_library
+        ; FileType = csharp_executable
+        ; FileType = csharp_library
+        ; FileType = java_launcher
+        ; FileType = java_archive
+        ; FileType = erlang_launcher
+        ; FileType = erlang_archive
+        )
     ).
 
 %-----------------------------------------------------------------------------%
@@ -1589,6 +1585,8 @@ install_library_grade_files(Globals, LinkSucceeded0, GradeDir, ModuleName,
             LibFileName, !IO),
         linked_target_file_name(Globals, ModuleName, shared_library,
             SharedLibFileName, !IO),
+        linked_target_file_name(Globals, ModuleName, csharp_library,
+            DllFileName, !IO),
         linked_target_file_name(Globals, ModuleName, java_archive,
             JarFileName, !IO),
         linked_target_file_name(Globals, ModuleName, erlang_archive,
@@ -1596,7 +1594,12 @@ install_library_grade_files(Globals, LinkSucceeded0, GradeDir, ModuleName,
 
         globals.lookup_string_option(Globals, install_prefix, Prefix),
 
-        ( string.prefix(GradeDir, "java") ->
+        ( string.prefix(GradeDir, "csharp") ->
+            GradeLibDir = Prefix/"lib"/"mercury"/"lib"/GradeDir,
+            install_file(Globals, DllFileName, GradeLibDir, LibsSucceeded,
+                !IO),
+            InitSucceeded = yes
+        ; string.prefix(GradeDir, "java") ->
             GradeLibDir = Prefix/"lib"/"mercury"/"lib"/GradeDir,
             install_file(Globals, JarFileName, GradeLibDir, LibsSucceeded,
                 !IO),
@@ -1959,39 +1962,30 @@ make_main_module_realclean(Globals, ModuleName, !Info, !IO) :-
             write_sym_name(ModuleName, !IO),
             io.write_string("'.\n", !IO)
         ), !IO),
-    linked_target_file_name(Globals, ModuleName, executable,
-        ExeFileName, !IO),
-    linked_target_file_name(Globals, ModuleName, static_library,
-        LibFileName, !IO),
-    linked_target_file_name(Globals, ModuleName, shared_library,
-        SharedLibFileName, !IO),
-    linked_target_file_name(Globals, ModuleName, java_archive,
-        JarFileName, !IO),
-    linked_target_file_name(Globals, ModuleName, erlang_archive,
-        ErlangArchiveFileName, !IO),
 
+    LinkedTargetTypes = [
+        executable,
+        static_library,
+        shared_library,
+        csharp_executable,
+        csharp_library,
+        java_launcher,
+        java_archive,
+        erlang_launcher,
+        erlang_archive
+    ],
+    list.map_foldl(linked_target_file_name(Globals, ModuleName),
+        LinkedTargetTypes, FileNames, !IO),
     % Remove the symlinks created for `--use-grade-subdirs'.
     globals.set_option(use_grade_subdirs, bool(no), Globals, NoSubdirGlobals),
-    linked_target_file_name(NoSubdirGlobals, ModuleName, executable,
-        ThisDirExeFileName, !IO),
-    linked_target_file_name(NoSubdirGlobals, ModuleName, static_library,
-        ThisDirLibFileName, !IO),
-    linked_target_file_name(NoSubdirGlobals, ModuleName, shared_library,
-        ThisDirSharedLibFileName, !IO),
-    linked_target_file_name(NoSubdirGlobals, ModuleName, java_archive,
-        ThisDirJarFileName, !IO),
-    linked_target_file_name(NoSubdirGlobals, ModuleName, erlang_archive,
-        ThisDirErlangArchiveFileName, !IO),
+    list.map_foldl(linked_target_file_name(NoSubdirGlobals, ModuleName),
+        LinkedTargetTypes, ThisDirFileNames, !IO),
     % XXX This symlink should not be necessary anymore for `mmc --make'.
     module_name_to_file_name(NoSubdirGlobals, ModuleName, ".init",
         do_not_create_dirs, ThisDirInitFileName, !IO),
 
     list.foldl2(make_remove_file(Globals, very_verbose),
-        [ExeFileName, LibFileName, SharedLibFileName, JarFileName,
-        ErlangArchiveFileName,
-        ThisDirExeFileName, ThisDirLibFileName,
-        ThisDirSharedLibFileName, ThisDirJarFileName,
-        ThisDirErlangArchiveFileName, ThisDirInitFileName],
+        FileNames ++ ThisDirFileNames ++ [ThisDirInitFileName],
         !Info, !IO),
     make_remove_module_file(Globals, very_verbose, ModuleName, ".init",
         !Info, !IO),
diff --git a/compiler/make.util.m b/compiler/make.util.m
index 59c6cd9..16b8dab 100644
--- a/compiler/make.util.m
+++ b/compiler/make.util.m
@@ -734,6 +734,7 @@ MC_unlock_job_ctl(MC_JobCtl *job_ctl)
 
 :- type job_ctl.
 :- pragma foreign_type("C", job_ctl, "MC_JobCtl *").
+:- pragma foreign_type("C#", job_ctl, "object"). % stub
 :- pragma foreign_type("Java", job_ctl, "java.lang.Object"). % stub
 
 :- pred have_job_ctl_ipc is semidet.
@@ -1413,23 +1414,7 @@ target_extension_synonym(".csharp", module_target_csharp_code).
 linked_target_file_name(Globals, ModuleName, TargetType, FileName, !IO) :-
     (
         TargetType = executable,
-        globals.get_target(Globals, Target),
-        (
-            ( Target = target_erlang
-            ; Target = target_java
-            ),
-            % These are shell scripts.
-            Ext = ""
-        ;
-            ( Target = target_c
-            ; Target = target_il
-            ; Target = target_csharp
-            ; Target = target_asm
-            ; Target = target_x86_64
-            ),
-            globals.lookup_string_option(Globals, executable_file_extension,
-                Ext)
-        ),
+        globals.lookup_string_option(Globals, executable_file_extension, Ext),
         module_name_to_file_name(Globals, ModuleName, Ext,
             do_not_create_dirs, FileName, !IO)
     ;
@@ -1443,10 +1428,21 @@ linked_target_file_name(Globals, ModuleName, TargetType, FileName, !IO) :-
         module_name_to_lib_file_name(Globals, "lib", ModuleName, Ext,
             do_not_create_dirs, FileName, !IO)
     ;
+        TargetType = csharp_executable,
+        module_name_to_file_name(Globals, ModuleName, ".exe",
+            do_not_create_dirs, FileName, !IO)
+    ;
         TargetType = csharp_library,
         module_name_to_file_name(Globals, ModuleName, ".dll",
             do_not_create_dirs, FileName, !IO)
     ;
+        ( TargetType = java_launcher
+        ; TargetType = erlang_launcher
+        ),
+        % These are shell scripts.
+        module_name_to_file_name(Globals, ModuleName, "",
+            do_not_create_dirs, FileName, !IO)
+    ;
         TargetType = java_archive,
         module_name_to_file_name(Globals, ModuleName, ".jar",
             do_not_create_dirs, FileName, !IO)
diff --git a/compiler/module_cmds.m b/compiler/module_cmds.m
index 64f2e31..cc1a9d7 100644
--- a/compiler/module_cmds.m
+++ b/compiler/module_cmds.m
@@ -182,6 +182,12 @@
     io::di, io::uo) is det.
 
 %-----------------------------------------------------------------------------%
+
+:- pred create_launcher_shell_script(globals::in, module_name::in,
+    pred(io.output_stream, io, io)::in(pred(in, di, uo) is det),
+    bool::out, io::di, io::uo) is det.
+
+%-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
 
 :- implementation.
@@ -672,15 +678,14 @@ use_win32 :-
 
 create_java_shell_script(Globals, MainModuleName, Succeeded, !IO) :-
     % XXX We should also create a ".bat" on Windows.
+    create_launcher_shell_script(Globals, MainModuleName,
+        write_java_shell_script(Globals, MainModuleName),
+        Succeeded, !IO).
 
-    Extension = "",
-    module_name_to_file_name(Globals, MainModuleName, Extension,
-        do_not_create_dirs, FileName, !IO),
-
-    globals.lookup_bool_option(Globals, verbose, Verbose),
-    maybe_write_string(Verbose, "% Generating shell script `" ++
-        FileName ++ "'...\n", !IO),
+:- pred write_java_shell_script(globals::in, module_name::in,
+    io.output_stream::in, io::di, io::uo) is det.
 
+write_java_shell_script(Globals, MainModuleName, Stream, !IO) :-
     % In shell scripts always use / separators, even on Windows.
     get_class_dir_name(Globals, ClassDirName),
     string.replace_all(ClassDirName, "\\", "/", ClassDirNameUnix),
@@ -696,12 +701,7 @@ create_java_shell_script(Globals, MainModuleName, Succeeded, !IO) :-
     globals.lookup_string_option(Globals, java_interpreter, Java),
     mangle_sym_name_for_java(MainModuleName, module_qual, ".", ClassName),
 
-    % Remove symlink in the way, if any.
-    io.remove_file(FileName, _, !IO),
-    io.open_output(FileName, OpenResult, !IO),
-    (
-        OpenResult = ok(ShellScript),
-        list.foldl(io.write_string(ShellScript), [
+    list.foldl(io.write_string(Stream), [
             "#!/bin/sh\n",
             "DIR=${0%/*}\n",
             "case $WINDIR in\n",
@@ -712,28 +712,7 @@ create_java_shell_script(Globals, MainModuleName, Succeeded, !IO) :-
             "export CLASSPATH\n",
             "JAVA=${JAVA:-", Java, "}\n",
             "exec $JAVA jmercury.", ClassName, " \"$@\"\n"
-        ], !IO),
-        io.close_output(ShellScript, !IO),
-        io.call_system("chmod a+x " ++ FileName, ChmodResult, !IO),
-        (
-            ChmodResult = ok(Status),
-            ( Status = 0 ->
-                Succeeded = yes,
-                maybe_write_string(Verbose, "% done.\n", !IO)
-            ;
-                unexpected(this_file, "chmod exit status != 0"),
-                Succeeded = no
-            )
-        ;
-            ChmodResult = error(Message),
-            unexpected(this_file, io.error_message(Message)),
-            Succeeded = no
-        )
-    ;
-        OpenResult = error(Message),
-        unexpected(this_file, io.error_message(Message)),
-        Succeeded = no
-    ).
+    ], !IO).
 
     % NOTE: changes here may require changes to get_mercury_std_libs.
 get_mercury_std_libs_for_java(Globals, !:StdLibs) :-
@@ -867,15 +846,14 @@ get_env_classpath(Classpath, !IO) :-
 %
 
 create_erlang_shell_script(Globals, MainModuleName, Succeeded, !IO) :-
-    Extension = "",
-    module_name_to_file_name(Globals, MainModuleName, Extension,
-        do_not_create_dirs, ScriptFileName, !IO),
-    grade_directory_component(Globals, GradeDir),
+    create_launcher_shell_script(Globals, MainModuleName,
+        write_erlang_shell_script(Globals, MainModuleName),
+        Succeeded, !IO).
 
-    globals.lookup_bool_option(Globals, verbose, Verbose),
-    maybe_write_string(Verbose, "% Generating shell script `" ++
-        ScriptFileName ++ "'...\n", !IO),
+:- pred write_erlang_shell_script(globals::in, module_name::in,
+    io.output_stream::in, io::di, io::uo) is det.
 
+write_erlang_shell_script(Globals, MainModuleName, Stream, !IO) :-
     globals.lookup_string_option(Globals, erlang_object_file_extension,
         BeamExt),
     module_name_to_file_name(Globals, MainModuleName, BeamExt,
@@ -886,6 +864,7 @@ create_erlang_shell_script(Globals, MainModuleName, Succeeded, !IO) :-
     % Add `-pa <dir>' option to find the standard library.
     % (-pa adds the directory to the beginning of the list of paths to search
     % for .beam files)
+    grade_directory_component(Globals, GradeDir),
     globals.lookup_maybe_string_option(Globals,
         mercury_standard_library_directory, MaybeStdLibDir),
     (
@@ -907,16 +886,8 @@ create_erlang_shell_script(Globals, MainModuleName, Succeeded, !IO) :-
         MercuryLibDirs0),
     globals.lookup_accumulating_option(Globals, link_libraries,
         LinkLibrariesList0),
-    list.map_foldl2(find_erlang_library_path(Globals, MercuryLibDirs),
-        LinkLibrariesList0, LinkLibrariesList, yes, LibrariesSucceeded,
-        !IO),
-    (
-        LibrariesSucceeded = yes,
-        % Remove symlink in the way, if any.
-        io.remove_file(ScriptFileName, _, !IO),
-        io.open_output(ScriptFileName, OpenResult, !IO),
-        (
-            OpenResult = ok(ShellScript),
+    list.map_foldl(find_erlang_library_path(Globals, MercuryLibDirs),
+        LinkLibrariesList0, LinkLibrariesList, !IO),
 
             globals.lookup_string_option(Globals, erlang_interpreter, Erlang),
             SearchLibs = string.append_list(list.map(pa_option(yes),
@@ -929,7 +900,7 @@ create_erlang_shell_script(Globals, MainModuleName, Succeeded, !IO) :-
             % Write the shell script.
             % Note we need to use '-extra' instead of '--' for "-flag" and
             % "+flag" arguments to be pass through to the Mercury program.
-            io.write_strings(ShellScript, [
+    io.write_strings(Stream, [
                 "#!/bin/sh\n",
                 "# Generated by the Mercury compiler.\n",
                 "DIR=`dirname ""$0""`\n",
@@ -937,40 +908,12 @@ create_erlang_shell_script(Globals, MainModuleName, Succeeded, !IO) :-
                 SearchStdLib, SearchLibs, SearchProg,
                 " -s ", BeamBaseNameNoExt, " ", MainFunc,
                 " -s init stop -extra ""$@""\n"
-            ], !IO),
-            io.close_output(ShellScript, !IO),
-
-            % Set executable bit.
-            io.call_system("chmod a+x " ++ ScriptFileName, ChmodResult, !IO),
-            (
-                ChmodResult = ok(Status),
-                ( Status = 0 ->
-                    Succeeded = yes,
-                    maybe_write_string(Verbose, "% done.\n", !IO)
-                ;
-                    unexpected(this_file, "chmod exit status != 0"),
-                    Succeeded = no
-                )
-            ;
-                ChmodResult = error(Message),
-                unexpected(this_file, io.error_message(Message)),
-                Succeeded = no
-            )
-        ;
-            OpenResult = error(Message),
-            unexpected(this_file, io.error_message(Message)),
-            Succeeded = no
-        )
-    ;
-        LibrariesSucceeded = no,
-        Succeeded = no
-    ).
+    ], !IO).
 
 :- pred find_erlang_library_path(globals::in, list(dir_name)::in, string::in,
-    string::out, bool::in, bool::out, io::di, io::uo) is det.
+    string::out, io::di, io::uo) is det.
 
-find_erlang_library_path(Globals, MercuryLibDirs, LibName, LibPath,
-        !Succeeded, !IO) :-
+find_erlang_library_path(Globals, MercuryLibDirs, LibName, LibPath, !IO) :-
     file_name_to_module_name(LibName, LibModuleName),
     globals.set_option(use_grade_subdirs, bool(no), Globals, NoSubdirsGlobals),
     module_name_to_lib_file_name(NoSubdirsGlobals, "lib", LibModuleName,
@@ -985,8 +928,7 @@ find_erlang_library_path(Globals, MercuryLibDirs, LibName, LibPath,
         SearchResult = error(Error),
         LibPath = "",
         write_error_pieces_maybe_with_context(Globals, no, 0, [words(Error)],
-            !IO),
-        !:Succeeded = no
+            !IO)
     ).
 
 :- func pa_option(bool, dir_name) = string.
@@ -1002,6 +944,45 @@ pa_option(Quote, Dir0) = " -pa " ++ Dir ++ " \\\n" :-
 
 %-----------------------------------------------------------------------------%
 
+create_launcher_shell_script(Globals, MainModuleName, Pred, Succeeded, !IO) :-
+    Extension = "",
+    module_name_to_file_name(Globals, MainModuleName, Extension,
+        do_not_create_dirs, FileName, !IO),
+
+    globals.lookup_bool_option(Globals, verbose, Verbose),
+    maybe_write_string(Verbose, "% Generating shell script `" ++
+        FileName ++ "'...\n", !IO),
+
+    % Remove symlink in the way, if any.
+    io.remove_file(FileName, _, !IO),
+    io.open_output(FileName, OpenResult, !IO),
+    (
+        OpenResult = ok(Stream),
+        Pred(Stream, !IO),
+        io.close_output(Stream, !IO),
+        io.call_system("chmod a+x " ++ FileName, ChmodResult, !IO),
+        (
+            ChmodResult = ok(Status),
+            ( Status = 0 ->
+                Succeeded = yes,
+                maybe_write_string(Verbose, "% done.\n", !IO)
+            ;
+                unexpected(this_file, "chmod exit status != 0"),
+                Succeeded = no
+            )
+        ;
+            ChmodResult = error(Message),
+            unexpected(this_file, io.error_message(Message)),
+            Succeeded = no
+        )
+    ;
+        OpenResult = error(Message),
+        unexpected(this_file, io.error_message(Message)),
+        Succeeded = no
+    ).
+
+%-----------------------------------------------------------------------------%
+
 :- func this_file = string.
 
 this_file = "module_cmds.m".
diff --git a/compiler/options.m b/compiler/options.m
index 7b3366d..d6b0437 100644
--- a/compiler/options.m
+++ b/compiler/options.m
@@ -824,6 +824,7 @@
     ;       csharp_compiler
     ;       csharp_flags
     ;       quoted_csharp_flag
+    ;       cli_interpreter
 
     % Erlang
     ;       erlang_compiler
@@ -1670,6 +1671,7 @@ option_defaults_2(target_code_compilation_option, [
     csharp_compiler                     -   string("csc"),
     csharp_flags                        -   accumulating([]),
     quoted_csharp_flag                  -   string_special,
+    cli_interpreter                     -   string(""),
 
     % Erlang
     erlang_compiler                     -   string("erlc"),
@@ -2584,6 +2586,7 @@ long_option("support-rotor-clr",    support_rotor_clr).
 long_option("csharp-compiler",      csharp_compiler).
 long_option("csharp-flags",         csharp_flags).
 long_option("csharp-flag",          quoted_csharp_flag).
+long_option("cli-interpreter",      cli_interpreter).
 
 long_option("erlang-compiler",      erlang_compiler).
 long_option("erlang-interpreter",   erlang_interpreter).
@@ -4060,6 +4063,13 @@ options_help_compilation_model -->
         "\tUse specific workarounds for the ROTOR CLR in the generated",
         "\tcode.",
 
+        "--csharp",
+        "\tAn abbreviation for `--target csharp'.",
+        "--csharp-only",
+        "\tAn abbreviation for `--target csharp --target-code-only'.",
+        "\tGenerate C# code in `<module>.cs', but do not generate",
+        "\tobject code.",
+
         "--java",
         "\tAn abbreviation for `--target java'.",
         "--java-only",
@@ -4214,8 +4224,8 @@ options_help_compilation_model -->
     write_tabbed_lines([
         "--gc {none, boehm, hgc, mps, accurate, automatic}",
         "--garbage-collection {none, boehm, hgc, mps, accurate, automatic}",
-        "\t\t\t\t(`java', `il' and `erlang' grades use",
-        "\t\t\t\t\t`--gc automatic',",
+        "\t\t\t\t(`java', `csharp', `il' and `erlang'",
+        "\t\t\t\t\tgrades use `--gc automatic',",
         "\t\t\t\t`.gc' grades use `--gc boehm',",
         "\t\t\t\t`.hgc' grades use `--gc hgc',",
         "\t\t\t\t`.mps' grades use `--gc mps',",
@@ -4310,18 +4320,18 @@ options_help_compilation_model -->
 %       "-H, --high-level-code\t\t\t(grades: hl_nest, hlc_nest)",
 % The ilc grade is not documented because it is not useful;
 % it has been superceded by the il grade.
-        "-H, --high-level-code\t\t\t(grades: hl, hlc, il, java)",
+        "-H, --high-level-code\t\t\t(grades: hl, hlc, il, csharp, java)",
         "\tUse an alternative back-end that generates high-level code",
         "\trather than the very low-level code that is generated by our",
         "\toriginal back-end.",
 % The hl_nest grade is not yet documented,
 % because the --gcc-nested-functions option is not yet documented.
 % because it is not yet supported
-%       "--high-level-data\t\t\t(grades: hl, hl_nest, il, java)",
-        "--high-level-data\t\t\t(grades: hl, il, java)",
+%       "--high-level-data\t\t\t(grades: hl, hl_nest, il, csharp, java)",
+        "--high-level-data\t\t\t(grades: hl, il, csharp, java)",
         "\tUse an alternative higher-level data representation.",
-%       "--high-level\t\t\t(grades: hl, hl_nest, il, java)",
-        "--high-level\t\t\t(grades: hl, il, java)",
+%       "--high-level\t\t\t(grades: hl, hl_nest, il, csharp, java)",
+        "--high-level\t\t\t(grades: hl, il, csharp, java)",
         "\tAn abbreviation for `--high-level-code --high-level-data'."
 % The --gcc-nested-functions option is not yet documented,
 % because it doesn't pass our test suite, and it is
@@ -5254,6 +5264,9 @@ options_help_target_code_compilation -->
         "\tSpecify options to be passed to the C# compiler.",
         "\t`--csharp-flag' should be used for single words which need",
         "\tto be quoted when passed to the shell.",
+        "--cli-interpreter <prog>",
+        "\tSpecify the program that implements the Common Language",
+        "\tInfrastructure (CLI) execution environment, e.g. `mono'.",
 
         "--erlang-compiler <erlc>",
         "\tSpecify the name of the Erlang compiler.",
diff --git a/compiler/options_file.m b/compiler/options_file.m
index aa71ec9..aa84d87 100644
--- a/compiler/options_file.m
+++ b/compiler/options_file.m
@@ -927,8 +927,8 @@ options_variable_name(grade_flags) = "GRADEFLAGS".
 options_variable_name(mmc_flags) = "MCFLAGS".
 options_variable_name(c_flags) = "CFLAGS".
 options_variable_name(java_flags) = "JAVACFLAGS".
-options_variable_name(ilasm_flags) = "MS_ILASM_FLAGS".
-options_variable_name(csharp_flags) = "MS_CSC_FLAGS".
+options_variable_name(ilasm_flags) = "ILASMFLAGS".
+options_variable_name(csharp_flags) = "CSCFLAGS".
 options_variable_name(erlang_flags) = "ERLANG_FLAGS".
 options_variable_name(ml_objs) = "MLOBJS".
 options_variable_name(ml_libs) = "MLLIBS".
diff --git a/configure.in b/configure.in
index 8dcbb38..42073b5 100644
--- a/configure.in
+++ b/configure.in
@@ -370,6 +370,7 @@ then
         :- pragma foreign_type("C", x, "MR_Integer",
             [[can_pass_as_mercury_type, stable]]).
         :- pragma foreign_type("Erlang", x, "").
+        :- pragma foreign_type("C#", x, "object").
 
         :- pragma foreign_proc("C", return_rtti_version(Version::out),
             [[may_call_mercury, promise_pure, terminates,
diff --git a/deep_profiler/Mmakefile b/deep_profiler/Mmakefile
index fbd0743..59dfc59 100644
--- a/deep_profiler/Mmakefile
+++ b/deep_profiler/Mmakefile
@@ -104,7 +104,7 @@ $(MDBCOMP_MODULES): $(MDBCOMP_ORIG_MODULES)
 # Add some additional dependencies, so that Mmake knows to remake the
 # profiler if one of the libraries changes.
 
-ifeq ("$(filter il% java% erlang%,$(GRADE))","")
+ifeq ("$(filter il% csharp% java% erlang%,$(GRADE))","")
 mdprof_cgi:		$(RUNTIME_DIR)/lib$(RT_LIB_NAME).$A
 mdprof_cgi:		$(LIBRARY_DIR)/lib$(STD_LIB_NAME).$A
 mdprof_test:		$(RUNTIME_DIR)/lib$(RT_LIB_NAME).$A
diff --git a/doc/user_guide.texi b/doc/user_guide.texi
index 56022e5..9daa497 100644
--- a/doc/user_guide.texi
+++ b/doc/user_guide.texi
@@ -201,10 +201,11 @@ and @file{.trans_opt_date}
 files associated with the module are used as timestamp files;
 they are used when deciding whether the interface files need to be regenerated.
 
- at file{.c_date}, @file{.il_date}, @file{.java_date}, @file{.erl_date},
+ at file{.c_date}, @file{.il_date}, @file{.cs_date},
+ at file{.java_date}, @file{.erl_date},
 @file{.s_date} and @file{.pic_s_date} files
-perform a similar function for @file{.c}, @file{.il}, @file{.java},
- at file{.erl},
+perform a similar function for @file{.c}, @file{.il}, @file{.cs},
+ at file{.java}, @file{.erl},
 @file{.s} and @file{.pic_s} files respectively. When smart recompilation
 (@pxref{Auxiliary output options}) works out that a module
 does not need to be recompiled, the timestamp file for the
@@ -238,6 +239,7 @@ to avoid conflicts with system header files.
 Java bytecode and Java archives respectively.
 @file{.il} files are Intermediate Language (IL) files
 for the .NET Common Language Runtime.
+ at file{.cs} files are C# source code.
 @c XXX mention .dll and .exe?
 @file{.erl} and @file{.beam} files are Erlang source code and
 bytecode (object) files respectively.
@@ -6790,7 +6792,8 @@ Check the module for errors, but do not generate any code.
 @findex --target-code-only
 Generate target code (i.e.@: C in @file{@var{module}.c},
 assembler in @file{@var{module}.s} or @file{@var{module}.pic_s},
-IL in @file{@var{module}.il}, Java in @file{@var{module}.java}
+IL in @file{@var{module}.il}, C# in @file{@var{module}.cs},
+Java in @file{@var{module}.java}
 or Erlang in @file{@var{module}.erl}),
 but not object code.
 
@@ -7349,6 +7352,7 @@ The set of aspects and their alternatives are:
 @cindex hl (compilation grade)
 @cindex hlc (compilation grade)
 @cindex il (compilation grade)
+ at cindex csharp (compilation grade)
 @cindex java (compilation grade)
 @cindex erlang (compilation grade)
 @cindex .prof (grade modifier)
@@ -7383,7 +7387,8 @@ The set of aspects and their alternatives are:
 @table @asis
 @item What target language to use, what data representation to use, and (for C) what combination of GNU C extensions to use:
 @samp{none}, @samp{reg}, @samp{jump}, @samp{asm_jump},
- at samp{fast}, @samp{asm_fast}, @samp{hl}, @samp{hlc}, @samp{il}, @samp{java} and
+ at samp{fast}, @samp{asm_fast}, @samp{hl}, @samp{hlc}, @samp{il}, @samp{csharp},
+ at samp{java} and
 @samp{erlang}
 (the default is system dependent).
 
@@ -7445,6 +7450,7 @@ and grade modifier; they are followed by descriptions of those options.
 @findex --no-high-level-code
 @findex --target
 @findex --il
+ at findex --csharp
 @findex --java
 @findex --erlang
 @findex --gc
@@ -7486,6 +7492,9 @@ and grade modifier; they are followed by descriptions of those options.
 @item @samp{il}
 @code{--target il --high-level-code --high-level-data}.
 
+ at item @samp{csharp}
+ at code{--target csharp --high-level-code --high-level-data}.
+
 @item @samp{java}
 @code{--target java --high-level-code --high-level-data}.
 
@@ -7570,9 +7579,10 @@ and grade modifier; they are followed by descriptions of those options.
 @item @code{--target c} (grades: none, reg, jump, fast, asm_jump, asm_fast, hl, hlc)
 @item @code{--target asm} (grades: hlc)
 @itemx @code{--il}, @code{--target il} (grades: il)
+ at itemx @code{--csharp}, @code{--target csharp} (grades: csharp)
 @itemx @code{--java}, @code{--target java} (grades: java)
 @itemx @code{--erlang}, @code{--target erlang} (grades: erlang)
-Specify the target language used for compilation: C, assembler, IL, Java
+Specify the target language used for compilation: C, assembler, IL, C#, Java
 or Erlang.
 C means ANSI/ISO C, optionally with GNU C extensions (see below).
 IL means the Intermediate Language of the .NET Common Language Runtime.
@@ -7611,6 +7621,13 @@ Generate C code in @file{@var{module}.c}, but do not invoke the
 C compiler to generate object code.
 
 @sp 1
+ at item @code{--csharp-only}
+ at findex --csharp-only
+An abbreviation for @samp{--target csharp --target-code-only}.
+Generate C# code in @file{@var{module}.cs}, but do not invoke
+the C# compiler to produce CIL bytecode.
+
+ at sp 1
 @item @code{--java-only}
 @findex --java-only
 An abbreviation for @samp{--target java --target-code-only}.
@@ -7687,14 +7704,14 @@ This option is ignored if the @samp{--high-level-code} option is enabled.
 @cindex MLDS back-end compilation model options
 
 @table @asis
- at item @code{-H}, @code{--high-level-code} (grades: hl, hlc, il, java)
+ at item @code{-H}, @code{--high-level-code} (grades: hl, hlc, il, csharp, java)
 @findex -H
 @findex --high-level-code
 Use an alternative back-end that generates high-level code
 rather than the very low-level code that is generated by our
 original back-end.
 
- at item @code{--high-level-data} (grades: hl, il, java)
+ at item @code{--high-level-data} (grades: hl, il, csharp, java)
 @findex --high-level-data
 Use an alternative, higher-level data representation that uses structs
 or classes, rather than treating all objects as arrays.
@@ -7891,7 +7908,7 @@ For now, this option itself is for developers only.
 @findex --gc
 @findex --garbage-collection
 Specify which method of garbage collection to use.
-Grades containing @samp{java}, @samp{il} or @samp{erlang} use
+Grades containing @samp{csharp}, @samp{java}, @samp{il} or @samp{erlang} use
 @samp{--gc automatic},
 grades containing @samp{.gc} use @samp{--gc boehm},
 grades containing @samp{.mps} use @samp{--gc mps},
@@ -9447,6 +9464,30 @@ Set the classpath for the Java compiler.
 Specify an extension for Java object (bytecode) files.  By default this
 is @samp{.class}.
 
+
+ at sp 1
+ at item --csharp-compiler @var{compiler-name}
+ at findex --csharp-compiler
+ at cindex C# compiler
+Specify which C# compiler to use.  The default is @samp{csc}.
+
+ at sp 1
+ at item --csharp-flags @var{options}
+ at itemx --csharp-flag @var{option}
+ at findex --csharp-flags
+ at findex --csharp-flag
+ at cindex C# compiler options
+Specify options to be passed to the C# compiler.
+ at samp{--csharp-flag} should be used for single words which need
+to be quoted when passed to the shell.
+
+ at sp 1
+ at item --cil-interpreter @var{interpreter-name}
+ at findex --cil-interpreter
+ at cindex CIL interpreter
+Specify the program that implements the Common Language
+Infrastructure (CLI) execution environment, e.g. @samp{mono}.
+
 @sp 1
 @item --erlang-compiler @var{compiler-name}
 @findex --erlang-compiler
@@ -10400,7 +10441,7 @@ or assembler.
 Only available on backends that compile to C or assembler.
 
 @item @samp{C#}
-Only available on backends that compile to IL.
+Only available on backends that compile to IL or C#.
 This is the second preferred foreign language for IL code generation.
 
 @item @samp{IL}
diff --git a/library/Mmakefile b/library/Mmakefile
index ad10f3d..b705458 100644
--- a/library/Mmakefile
+++ b/library/Mmakefile
@@ -98,11 +98,11 @@ endif
 MCFLAGS += --flags LIB_FLAGS $(CONFIG_OVERRIDE)
 MCFLAGS += $(LIBRARY_TRACE_LEVEL) $(INTER_FLAGS)
 
-# The IL, Java and Erlang implementations of the standard library are not yet
-# complete, so we need to pass `--allow-stubs' to get them to compile.
+# The IL, C#, Java and Erlang implementations of the standard library are not
+# yet complete, so we need to pass `--allow-stubs' to get them to compile.
 # Since the standard library is compiled with `--halt-at-warn',
 # we also need `--no-warn-stubs'.
-ifneq ("$(filter il% java% erlang%,$(GRADE))","")
+ifneq ("$(filter il% csharp% java% erlang%,$(GRADE))","")
 MCFLAGS += --allow-stubs --no-warn-stubs
 endif
 
@@ -307,7 +307,7 @@ lib_std: mercury.dll lib$(STD_LIB_NAME)
 # We have to hardcode the names of the runtime DLL files.
 RUNTIME_DLLS=mercury_dotnet.dll mercury_il.dll
 
-MS_CSCFLAGS=/t:module
+CSCFLAGS=/t:module
 
 # If you do generate a new strong name, you had better update
 # compiler/mlds_to_il.m to generate references to it.  It is also hard-coded
@@ -355,6 +355,17 @@ endif
 
 #-----------------------------------------------------------------------------#
 
+# For C# we include the runtime module directly into mer_std.dll.
+ifneq ("$(filter csharp%,$(GRADE))","")
+LINK_LIB_OPTS :=
+MLOBJS += ../runtime/mercury_dotnet.cs
+
+# Suppress warnings about unused variables.
+CSCFLAGS += /nowarn:0219
+endif
+
+#-----------------------------------------------------------------------------#
+
 ifneq ($(MMAKE_USE_MMC_MAKE),yes)
 ifeq ("$(findstring java,$(GRADE))","java")
 lib_std: $(STD_LIB_NAME).jar $(RT_LIB_NAME).jar $(NATIVE_SO)
@@ -365,7 +376,7 @@ endif
 #
 # Some extra rules that we need for the C and asm back-ends
 #
-ifeq ("$(filter il% java% erlang%,$(GRADE))","")
+ifeq ("$(filter il% csharp% java% erlang%,$(GRADE))","")
 
 # The following dependency is just there to improve compilation speed;
 # making tree234.$O first improves effective parallelism with parallel makes.
@@ -503,8 +514,8 @@ install_library: mercury.dll install_grade_dirs install_gac \
 # To build the .NET library with debugging information, add
 # the following to ../Mmake.params:
 #
-#	EXTRA_MS_ILASMFLAGS=/debug
-#	EXTRA_MS_CSCFLAGS=/debug+ /debug:full
+#	EXTRA_ILASMFLAGS=/debug
+#	EXTRA_CSCFLAGS=/debug+ /debug:full
 #
 # XXX Unfortunately, however, this is a problem with AL, which prohibits
 # linking debuggable C# code with IL code.  The following
diff --git a/library/array.m b/library/array.m
index 6409ad3..320b9e4 100644
--- a/library/array.m
+++ b/library/array.m
@@ -482,9 +482,9 @@
     where equality is array.array_equal,
     comparison is array.array_compare.
 
-% :- pragma foreign_type("C#",  array(T), "System.Array")
-%     where equality is array.array_equal,
-%     comparison is array.array_compare.
+:- pragma foreign_type("C#",  array(T), "System.Array")
+    where equality is array.array_equal,
+    comparison is array.array_compare.
 
 :- pragma foreign_type("IL",  array(T), "class [mscorlib]System.Array")
     where equality is array.array_equal,
diff --git a/library/bitmap.m b/library/bitmap.m
index 38c7b60..1b7ea2f 100644
--- a/library/bitmap.m
+++ b/library/bitmap.m
@@ -1599,8 +1599,8 @@ public class MercuryBitmap {
     where equality is bitmap_equal, comparison is bitmap_compare.
 :- pragma foreign_type("Java", bitmap, "bitmap.MercuryBitmap")
     where equality is bitmap_equal, comparison is bitmap_compare.
-% :- pragma foreign_type("C#", bitmap, "bitmap.MercuryBitmap")
-%     where equality is bitmap_equal, comparison is bitmap_compare.
+:- pragma foreign_type("C#", bitmap, "bitmap.MercuryBitmap")
+    where equality is bitmap_equal, comparison is bitmap_compare.
 :- pragma foreign_type("IL", bitmap,
     "class [mercury]mercury.bitmap__csharp_code.mercury_code.MercuryBitmap")
     where equality is bitmap_equal, comparison is bitmap_compare.
diff --git a/library/bool.m b/library/bool.m
index 99269ec..384a5dc 100644
--- a/library/bool.m
+++ b/library/bool.m
@@ -77,11 +77,11 @@
 % The representation of bool values should correspond with the definitions of
 % MR_TRUE and MR_FALSE in runtime/mercury_std.h.
 
-% :- pragma foreign_export_enum("C#", bool/0, [],
-%     [
-%         no  - "NO",
-%         yes - "YES"
-%     ]).
+:- pragma foreign_export_enum("C#", bool/0, [],
+    [
+        no  - "NO",
+        yes - "YES"
+    ]).
 
 :- pragma foreign_export_enum("Java", bool/0, [],
     [
diff --git a/library/builtin.m b/library/builtin.m
index dcb3203..18f5a2a 100644
--- a/library/builtin.m
+++ b/library/builtin.m
@@ -602,12 +602,12 @@ get_one_solution_io(Pred, X, !IO) :-
 :- external(compare/3).
 :- external(compare_representation/3).
 
-% :- pragma foreign_export_enum("C#", comparison_result/0, [],
-%     [
-%         (=) - "COMPARE_EQUAL",
-%         (<) - "COMPARE_LESS",
-%         (>) - "COMPARE_GREATER"
-%     ]).
+:- pragma foreign_export_enum("C#", comparison_result/0, [],
+    [
+        (=) - "COMPARE_EQUAL",
+        (<) - "COMPARE_LESS",
+        (>) - "COMPARE_GREATER"
+    ]).
 
 :- pragma foreign_export_enum("Java", comparison_result/0, [],
     [
@@ -702,6 +702,10 @@ call_rtti_generic_compare(Res, X, Y) :-
 :- pragma foreign_code("C#", "
 public static object deep_copy(object o)
 {
+    if (o == null) {
+        return null;
+    }
+
     System.Type t = o.GetType();
     System.Array arr;
 
diff --git a/library/dir.m b/library/dir.m
index 84f6000..51a5805 100644
--- a/library/dir.m
+++ b/library/dir.m
@@ -323,8 +323,8 @@ use_windows_paths :- dir.directory_separator = ('\\').
     "ML_dir_this_directory").
 :- pragma foreign_export("IL", (dir.this_directory = out),
     "ML_dir_this_directory").
-% :- pragma foreign_export("C#", (dir.this_directory = out),
-%     "ML_dir_this_directory").
+:- pragma foreign_export("C#", (dir.this_directory = out),
+    "ML_dir_this_directory").
 
 dir.this_directory = ".".
 
@@ -772,8 +772,8 @@ dir.make_path_name(DirName, FileName) = DirName/FileName.
     "ML_make_path_name").
 :- pragma foreign_export("IL", dir.make_path_name(in, in) = out,
     "ML_make_path_name").
-% :- pragma foreign_export("C#", dir.make_path_name(in, in) = out,
-%     "ML_make_path_name").
+:- pragma foreign_export("C#", dir.make_path_name(in, in) = out,
+    "ML_make_path_name").
 
 DirName0/FileName0 = PathName :-
     DirName = string.from_char_list(canonicalize_path_chars(
@@ -1193,8 +1193,8 @@ dir.make_single_directory(DirName, Result, !IO) :-
     "ML_make_mkdir_res_ok").
 :- pragma foreign_export("IL", (dir.make_mkdir_res_ok = out),
     "ML_make_mkdir_res_ok").
-% :- pragma foreign_export("C#", (dir.make_mkdir_res_ok = out),
-%     "ML_make_mkdir_res_ok").
+:- pragma foreign_export("C#", (dir.make_mkdir_res_ok = out),
+    "ML_make_mkdir_res_ok").
 :- pragma foreign_export("Java", (dir.make_mkdir_res_ok = out),
     "ML_make_mkdir_res_ok").
 :- pragma foreign_export("Erlang", (dir.make_mkdir_res_ok = out),
@@ -1208,8 +1208,8 @@ dir.make_mkdir_res_ok = ok.
     "ML_make_mkdir_res_error").
 :- pragma foreign_export("IL", dir.make_mkdir_res_error(in, out, di, uo),
     "ML_make_mkdir_res_error").
-% :- pragma foreign_export("C#", dir.make_mkdir_res_error(in, out, di, uo),
-%     "ML_make_mkdir_res_error").
+:- pragma foreign_export("C#", dir.make_mkdir_res_error(in, out, di, uo),
+    "ML_make_mkdir_res_error").
 :- pragma foreign_export("Java", dir.make_mkdir_res_error(in, out, di, uo),
     "ML_make_mkdir_res_error").
 :- pragma foreign_export("Erlang", dir.make_mkdir_res_error(in, out, di, uo),
@@ -1227,9 +1227,9 @@ dir.make_mkdir_res_error(Error, error(make_io_error(Msg)), !IO) :-
 :- pragma foreign_export("IL",
     dir.make_mkdir_res_exists(in, in, out, di, uo),
     "ML_make_mkdir_res_exists").
-% :- pragma foreign_export("C#",
-%     dir.make_mkdir_res_exists(in, in, out, di, uo),
-%     "ML_make_mkdir_res_exists").
+:- pragma foreign_export("C#",
+    dir.make_mkdir_res_exists(in, in, out, di, uo),
+    "ML_make_mkdir_res_exists").
 :- pragma foreign_export("Java",
     dir.make_mkdir_res_exists(in, in, out, di, uo),
     "ML_make_mkdir_res_exists").
@@ -1251,8 +1251,8 @@ dir.make_mkdir_res_exists(Error, DirName, Res, !IO) :-
     "ML_check_dir_accessibility").
 :- pragma foreign_export("IL", dir.check_dir_accessibility(in, out, di, uo),
     "ML_check_dir_accessibility").
-% :- pragma foreign_export("C#", dir.check_dir_accessibility(in, out, di, uo),
-%     "ML_check_dir_accessibility").
+:- pragma foreign_export("C#", dir.check_dir_accessibility(in, out, di, uo),
+    "ML_check_dir_accessibility").
 :- pragma foreign_export("Java", dir.check_dir_accessibility(in, out, di, uo),
     "ML_check_dir_accessibility").
 :- pragma foreign_export("Erlang", dir.check_dir_accessibility(in, out, di, uo),
@@ -1549,7 +1549,7 @@ check_for_symlink_loop(SymLinkParent, DirName, LoopRes, !ParentIds, !IO) :-
 :- pragma foreign_type("C", dir.stream, "ML_DIR_STREAM").
 :- pragma foreign_type("IL", dir.stream,
     "class [mscorlib]System.Collections.IEnumerator").
-% :- pragma foreign_type("C#", dir.stream, "System.Collections.IEnumerator").
+:- pragma foreign_type("C#", dir.stream, "System.Collections.IEnumerator").
 :- pragma foreign_type("Java", dir.stream, "java.util.Iterator").
 :- pragma foreign_type("Erlang", dir.stream, "").
 
@@ -1744,8 +1744,8 @@ dir.check_dir_readable(DirName, IsReadable, Result, !IO) :-
     "ML_dir_read_first_entry").
 :- pragma foreign_export("IL", dir.read_first_entry(in, out, di, uo),
     "ML_dir_read_first_entry").
-% :- pragma foreign_export("C#", dir.read_first_entry(in, out, di, uo),
-%     "ML_dir_read_first_entry").
+:- pragma foreign_export("C#", dir.read_first_entry(in, out, di, uo),
+    "ML_dir_read_first_entry").
 :- pragma foreign_export("Java", dir.read_first_entry(in, out, di, uo),
     "ML_dir_read_first_entry").
 :- pragma foreign_export("Erlang", dir.read_first_entry(in, out, di, uo),
@@ -1762,9 +1762,9 @@ dir.read_first_entry(Dir, Result, !IO) :-
 :- pragma foreign_export("IL",
     make_win32_dir_open_result_ok(in, in, out, di, uo),
     "ML_make_win32_dir_open_result_ok").
-% :- pragma foreign_export("C#",
-%     make_win32_dir_open_result_ok(in, in, out, di, uo),
-%     "ML_make_win32_dir_open_result_ok").
+:- pragma foreign_export("C#",
+    make_win32_dir_open_result_ok(in, in, out, di, uo),
+    "ML_make_win32_dir_open_result_ok").
 :- pragma foreign_export("Java",
     make_win32_dir_open_result_ok(in, in, out, di, uo),
     "ML_make_win32_dir_open_result_ok").
@@ -1821,8 +1821,8 @@ copy_c_string(_) = _ :-
     "ML_make_dir_open_result_eof").
 :- pragma foreign_export("IL", (make_dir_open_result_eof = out),
     "ML_make_dir_open_result_eof").
-% :- pragma foreign_export("C#", (make_dir_open_result_eof = out),
-%     "ML_make_dir_open_result_eof").
+:- pragma foreign_export("C#", (make_dir_open_result_eof = out),
+    "ML_make_dir_open_result_eof").
 :- pragma foreign_export("Java", (make_dir_open_result_eof = out),
     "ML_make_dir_open_result_eof").
 
@@ -1834,8 +1834,8 @@ make_dir_open_result_eof = eof.
     "ML_make_dir_open_result_error").
 :- pragma foreign_export("IL", make_dir_open_result_error(in, out, di, uo),
     "ML_make_dir_open_result_error").
-% :- pragma foreign_export("C#", make_dir_open_result_error(in, out, di, uo),
-%     "ML_make_dir_open_result_error").
+:- pragma foreign_export("C#", make_dir_open_result_error(in, out, di, uo),
+    "ML_make_dir_open_result_error").
 :- pragma foreign_export("Java", make_dir_open_result_error(in, out, di, uo),
     "ML_make_dir_open_result_error").
 :- pragma foreign_export("Erlang", make_dir_open_result_error(in, out, di, uo),
diff --git a/library/exception.m b/library/exception.m
index 79d3c69..5caa016 100644
--- a/library/exception.m
+++ b/library/exception.m
@@ -1613,16 +1613,16 @@ call_handler(Handler, Exception, Result) :- Handler(Exception, Result).
     "ML_call_goal_det").
 :- pragma foreign_export("IL", call_goal(pred(out) is det, out),
     "ML_call_goal_det").
-% :- pragma foreign_export("C#", call_goal(pred(out) is det, out),
-%     "ML_call_goal_det").
+:- pragma foreign_export("C#", call_goal(pred(out) is det, out),
+    "ML_call_goal_det").
 :- pragma foreign_export("Java", call_goal(pred(out) is det, out),
     "ML_call_goal_det").
 :- pragma foreign_export("C", call_goal(pred(out) is semidet, out),
     "ML_call_goal_semidet").
 :- pragma foreign_export("IL", call_goal(pred(out) is semidet, out),
     "ML_call_goal_semidet").
-% :- pragma foreign_export("C#", call_goal(pred(out) is semidet, out),
-%     "ML_call_goal_semidet").
+:- pragma foreign_export("C#", call_goal(pred(out) is semidet, out),
+    "ML_call_goal_semidet").
 :- pragma foreign_export("Java", call_goal(pred(out) is semidet, out),
     "ML_call_goal_semidet").
 
@@ -1641,8 +1641,8 @@ call_handler(Handler, Exception, Result) :- Handler(Exception, Result).
     "ML_call_handler_det").
 :- pragma foreign_export("IL", call_handler(pred(in, out) is det, in, out),
     "ML_call_handler_det").
-% :- pragma foreign_export("C#", call_handler(pred(in, out) is det, in, out),
-%     "ML_call_handler_det").
+:- pragma foreign_export("C#", call_handler(pred(in, out) is det, in, out),
+    "ML_call_handler_det").
 :- pragma foreign_export("Java", call_handler(pred(in, out) is det, in, out),
     "ML_call_handler_det").
 
@@ -2795,8 +2795,8 @@ mercury_sys_init_exceptions_write_out_proc_statics(FILE *deep_fp,
     "ML_report_uncaught_exception").
 :- pragma foreign_export("IL", report_uncaught_exception(in, di, uo),
     "ML_report_uncaught_exception").
-% :- pragma foreign_export("C#", report_uncaught_exception(in, di, uo),
-%     "ML_report_uncaught_exception").
+:- pragma foreign_export("C#", report_uncaught_exception(in, di, uo),
+    "ML_report_uncaught_exception").
 :- pragma foreign_export("Java", report_uncaught_exception(in, di, uo),
     "ML_report_uncaught_exception").
 :- pragma foreign_export("Erlang", report_uncaught_exception(in, di, uo),
diff --git a/library/io.m b/library/io.m
index cc082f5..cf312dc 100644
--- a/library/io.m
+++ b/library/io.m
@@ -1512,7 +1512,7 @@
 :- pragma foreign_type(c, io.system_error, "MR_Integer").
 :- pragma foreign_type(il, io.system_error,
     "class [mscorlib]System.Exception").
-% :- pragma foreign_type("C#", io.system_error, "System.Exception").
+:- pragma foreign_type("C#", io.system_error, "System.Exception").
 :- pragma foreign_type(java, io.system_error, "java.lang.Exception").
 :- pragma foreign_type(erlang, io.system_error, "").
 
@@ -1700,7 +1700,7 @@
 :- type io.state.
 :- pragma foreign_type("C", io.state, "MR_Word", [can_pass_as_mercury_type]).
 :- pragma foreign_type("IL", io.state, "int32", [can_pass_as_mercury_type]).
-% :- pragma foreign_type("C#", io.state, "int", [can_pass_as_mercury_type]).
+:- pragma foreign_type("C#", io.state, "int", [can_pass_as_mercury_type]).
 :- pragma foreign_type("Java", io.state, "java.lang.Object",
     [can_pass_as_mercury_type]).
 :- pragma foreign_type("Erlang", io.state, "", [can_pass_as_mercury_type]).
@@ -1787,7 +1787,7 @@
     [can_pass_as_mercury_type]).
 :- pragma foreign_type("IL", io.stream,
     "class [mercury]mercury.io__csharp_code.MR_MercuryFileStruct").
-% :- pragma foreign_type("C#", io.stream, "io.MR_MercuryFileStruct").
+:- pragma foreign_type("C#", io.stream, "io.MR_MercuryFileStruct").
 :- pragma foreign_type("Java", io.stream, "io.MR_MercuryFileStruct").
 :- pragma foreign_type("Erlang", io.stream, "").
 
@@ -2627,8 +2627,8 @@ io.make_err_msg(Msg0, Msg, !IO) :-
     "ML_make_err_msg").
 :- pragma foreign_export("IL", make_err_msg(in, in, out, di, uo),
     "ML_make_err_msg").
-% :- pragma foreign_export("C#", make_err_msg(in, in, out, di, uo),
-%     "ML_make_err_msg").
+:- pragma foreign_export("C#", make_err_msg(in, in, out, di, uo),
+    "ML_make_err_msg").
 
 :- pragma foreign_proc("C",
     make_err_msg(Error::in, Msg0::in, Msg::out, IO0::di, IO::uo),
@@ -2711,8 +2711,8 @@ have_dotnet :-
     "ML_make_win32_err_msg").
 :- pragma foreign_export("IL", make_win32_err_msg(in, in, out, di, uo),
     "ML_make_win32_err_msg").
-% :- pragma foreign_export("C#", make_win32_err_msg(in, in, out, di, uo),
-%     "ML_make_win32_err_msg").
+:- pragma foreign_export("C#", make_win32_err_msg(in, in, out, di, uo),
+    "ML_make_win32_err_msg").
 
 make_win32_err_msg(_, _, "", !IO) :-
     ( semidet_succeed ->
@@ -3238,28 +3238,28 @@ file_type_unknown = unknown.
     "ML_file_type_character_device").
 :- pragma foreign_export("IL", file_type_character_device = out,
     "ML_file_type_character_device").
-% :- pragma foreign_export("C#", file_type_character_device = out,
-%     "ML_file_type_character_device").
+:- pragma foreign_export("C#", file_type_character_device = out,
+    "ML_file_type_character_device").
 :- pragma foreign_export("Erlang", file_type_character_device = out,
     "ML_file_type_character_device").
 :- pragma foreign_export("C", file_type_block_device = out,
     "ML_file_type_block_device").
 :- pragma foreign_export("IL", file_type_block_device = out,
     "ML_file_type_block_device").
-% :- pragma foreign_export("C#", file_type_block_device = out,
-%     "ML_file_type_block_device").
+:- pragma foreign_export("C#", file_type_block_device = out,
+    "ML_file_type_block_device").
 :- pragma foreign_export("C", file_type_fifo = out,
     "ML_file_type_fifo").
 :- pragma foreign_export("IL", file_type_fifo = out,
     "ML_file_type_fifo").
-% :- pragma foreign_export("C#", file_type_fifo = out,
-%     "ML_file_type_fifo").
+:- pragma foreign_export("C#", file_type_fifo = out,
+    "ML_file_type_fifo").
 :- pragma foreign_export("C", file_type_directory = out,
     "ML_file_type_directory").
 :- pragma foreign_export("IL", file_type_directory = out,
     "ML_file_type_directory").
-% :- pragma foreign_export("C#", file_type_directory = out,
-%     "ML_file_type_directory").
+:- pragma foreign_export("C#", file_type_directory = out,
+    "ML_file_type_directory").
 :- pragma foreign_export("Java", file_type_directory = out,
     "ML_file_type_directory").
 :- pragma foreign_export("Erlang", file_type_directory = out,
@@ -3268,22 +3268,22 @@ file_type_unknown = unknown.
     "ML_file_type_socket").
 :- pragma foreign_export("IL", file_type_socket = out,
     "ML_file_type_socket").
-% :- pragma foreign_export("C#", file_type_socket = out,
-%     "ML_file_type_socket").
+:- pragma foreign_export("C#", file_type_socket = out,
+    "ML_file_type_socket").
 :- pragma foreign_export("C", file_type_symbolic_link = out,
     "ML_file_type_symbolic_link").
 :- pragma foreign_export("IL", file_type_symbolic_link = out,
     "ML_file_type_symbolic_link").
-% :- pragma foreign_export("C#", file_type_symbolic_link = out,
-%     "ML_file_type_symbolic_link").
+:- pragma foreign_export("C#", file_type_symbolic_link = out,
+    "ML_file_type_symbolic_link").
 :- pragma foreign_export("Erlang", file_type_symbolic_link = out,
     "ML_file_type_symbolic_link").
 :- pragma foreign_export("C", file_type_regular = out,
     "ML_file_type_regular").
 :- pragma foreign_export("IL", file_type_regular = out,
     "ML_file_type_regular").
-% :- pragma foreign_export("C#", file_type_regular = out,
-%     "ML_file_type_regular").
+:- pragma foreign_export("C#", file_type_regular = out,
+    "ML_file_type_regular").
 :- pragma foreign_export("Java", file_type_regular = out,
     "ML_file_type_regular").
 :- pragma foreign_export("Erlang", file_type_regular = out,
@@ -3292,26 +3292,26 @@ file_type_unknown = unknown.
     "ML_file_type_message_queue").
 :- pragma foreign_export("IL", file_type_message_queue = out,
     "ML_file_type_message_queue").
-% :- pragma foreign_export("C#", file_type_message_queue = out,
-%     "ML_file_type_message_queue").
+:- pragma foreign_export("C#", file_type_message_queue = out,
+    "ML_file_type_message_queue").
 :- pragma foreign_export("C", file_type_semaphore = out,
     "ML_file_type_semaphore").
 :- pragma foreign_export("IL", file_type_semaphore = out,
     "ML_file_type_semaphore").
-% :- pragma foreign_export("C#", file_type_semaphore = out,
-%     "ML_file_type_semaphore").
+:- pragma foreign_export("C#", file_type_semaphore = out,
+    "ML_file_type_semaphore").
 :- pragma foreign_export("C", file_type_shared_memory = out,
     "ML_file_type_shared_memory").
 :- pragma foreign_export("IL", file_type_shared_memory = out,
     "ML_file_type_shared_memory").
-% :- pragma foreign_export("C#", file_type_shared_memory = out,
-%     "ML_file_type_shared_memory").
+:- pragma foreign_export("C#", file_type_shared_memory = out,
+    "ML_file_type_shared_memory").
 :- pragma foreign_export("C", file_type_unknown = out,
     "ML_file_type_unknown").
 :- pragma foreign_export("IL", file_type_unknown = out,
     "ML_file_type_unknown").
-% :- pragma foreign_export("C#", file_type_unknown = out,
-%     "ML_file_type_unknown").
+:- pragma foreign_export("C#", file_type_unknown = out,
+    "ML_file_type_unknown").
 :- pragma foreign_export("Java", file_type_unknown = out,
     "ML_file_type_unknown").
 :- pragma foreign_export("Erlang", file_type_unknown = out,
@@ -3636,8 +3636,8 @@ check_directory_accessibility_dotnet(_, _, _, Res, !IO) :-
     "ML_access_types_includes_read").
 :- pragma foreign_export("IL", access_types_includes_read(in),
     "ML_access_types_includes_read").
-% :- pragma foreign_export("C#", access_types_includes_read(in),
-%     "ML_access_types_includes_read").
+:- pragma foreign_export("C#", access_types_includes_read(in),
+    "ML_access_types_includes_read").
 :- pragma foreign_export("Java", access_types_includes_read(in),
     "ML_access_types_includes_read").
 :- pragma foreign_export("Erlang", access_types_includes_read(in),
@@ -3651,8 +3651,8 @@ access_types_includes_read(Access) :-
     "ML_access_types_includes_write").
 :- pragma foreign_export("IL", access_types_includes_write(in),
     "ML_access_types_includes_write").
-% :- pragma foreign_export("C#", access_types_includes_write(in),
-%     "ML_access_types_includes_write").
+:- pragma foreign_export("C#", access_types_includes_write(in),
+    "ML_access_types_includes_write").
 :- pragma foreign_export("Java", access_types_includes_write(in),
     "ML_access_types_includes_write").
 :- pragma foreign_export("Erlang", access_types_includes_write(in),
@@ -3666,8 +3666,8 @@ access_types_includes_write(Access) :-
     "ML_access_types_includes_execute").
 :- pragma foreign_export("IL", access_types_includes_execute(in),
     "ML_access_types_includes_execute").
-% :- pragma foreign_export("C#", access_types_includes_execute(in),
-%     "ML_access_types_includes_execute").
+:- pragma foreign_export("C#", access_types_includes_execute(in),
+    "ML_access_types_includes_execute").
 :- pragma foreign_export("Java", access_types_includes_execute(in),
     "ML_access_types_includes_execute").
 :- pragma foreign_export("Erlang", access_types_includes_execute(in),
@@ -3681,8 +3681,8 @@ access_types_includes_execute(Access) :-
     "ML_make_io_res_0_ok").
 :- pragma foreign_export("IL", (make_io_res_0_ok = out),
     "ML_make_io_res_0_ok").
-% :- pragma foreign_export("C#", (make_io_res_0_ok = out),
-%     "ML_make_io_res_0_ok").
+:- pragma foreign_export("C#", (make_io_res_0_ok = out),
+    "ML_make_io_res_0_ok").
 :- pragma foreign_export("Java", (make_io_res_0_ok = out),
     "ML_make_io_res_0_ok").
 :- pragma foreign_export("Erlang", (make_io_res_0_ok = out),
@@ -3696,8 +3696,8 @@ make_io_res_0_ok = ok.
     "ML_make_io_res_0_error").
 :- pragma foreign_export("IL", make_io_res_0_error(in, in, out, di, uo),
     "ML_make_io_res_0_error").
-% :- pragma foreign_export("C#", make_io_res_0_error(in, in, out, di, uo),
-%     "ML_make_io_res_0_error").
+:- pragma foreign_export("C#", make_io_res_0_error(in, in, out, di, uo),
+    "ML_make_io_res_0_error").
 :- pragma foreign_export("Java", make_io_res_0_error(in, in, out, di, uo),
     "ML_make_io_res_0_error").
 :- pragma foreign_export("Erlang", make_io_res_0_error(in, in, out, di, uo),
@@ -3711,8 +3711,8 @@ make_io_res_0_error(Error, Msg0, error(make_io_error(Msg)), !IO) :-
     "ML_make_io_res_0_error_msg").
 :- pragma foreign_export("IL", (make_io_res_0_error_msg(in) = out),
     "ML_make_io_res_0_error_msg").
-% :- pragma foreign_export("C#", (make_io_res_0_error_msg(in) = out),
-%     "ML_make_io_res_0_error_msg").
+:- pragma foreign_export("C#", (make_io_res_0_error_msg(in) = out),
+    "ML_make_io_res_0_error_msg").
 :- pragma foreign_export("Java", (make_io_res_0_error_msg(in) = out),
     "ML_make_io_res_0_error_msg").
 
@@ -3723,8 +3723,8 @@ make_io_res_0_error_msg(Msg) = error(make_io_error(Msg)).
     "ML_make_io_res_1_ok_file_type").
 :- pragma foreign_export("IL", (make_io_res_1_ok_file_type(in) = out),
     "ML_make_io_res_1_ok_file_type").
-% :- pragma foreign_export("C#", (make_io_res_1_ok_file_type(in) = out),
-%     "ML_make_io_res_1_ok_file_type").
+:- pragma foreign_export("C#", (make_io_res_1_ok_file_type(in) = out),
+    "ML_make_io_res_1_ok_file_type").
 :- pragma foreign_export("Java", (make_io_res_1_ok_file_type(in) = out),
     "ML_make_io_res_1_ok_file_type").
 :- pragma foreign_export("Erlang", (make_io_res_1_ok_file_type(in) = out),
@@ -3740,9 +3740,9 @@ make_io_res_1_ok_file_type(FileType) = ok(FileType).
 :- pragma foreign_export("IL",
     make_io_res_1_error_file_type(in, in, out, di, uo),
     "ML_make_io_res_1_error_file_type").
-% :- pragma foreign_export("C#",
-%     make_io_res_1_error_file_type(in, in, out, di, uo),
-%     "ML_make_io_res_1_error_file_type").
+:- pragma foreign_export("C#",
+    make_io_res_1_error_file_type(in, in, out, di, uo),
+    "ML_make_io_res_1_error_file_type").
 :- pragma foreign_export("Java",
     make_io_res_1_error_file_type(in, in, out, di, uo),
     "ML_make_io_res_1_error_file_type").
@@ -3756,8 +3756,8 @@ make_io_res_1_error_file_type(Error, Msg0, error(make_io_error(Msg)), !IO) :-
 :- func make_io_res_1_ok_string(string) = io.res(string).
 :- pragma foreign_export("C", (make_io_res_1_ok_string(in) = out),
     "ML_make_io_res_1_ok_string").
-% :- pragma foreign_export("C#", (make_io_res_1_ok_string(in) = out),
-%     "ML_make_io_res_1_ok_string").
+:- pragma foreign_export("C#", (make_io_res_1_ok_string(in) = out),
+    "ML_make_io_res_1_ok_string").
 :- pragma foreign_export("Java", (make_io_res_1_ok_string(in) = out),
     "ML_make_io_res_1_ok_string").
 :- pragma foreign_export("Erlang", (make_io_res_1_ok_string(in) = out),
@@ -3770,9 +3770,9 @@ make_io_res_1_ok_string(String) = ok(String).
 :- pragma foreign_export("C",
     make_io_res_1_error_string(in, in, out, di, uo),
     "ML_make_io_res_1_error_string").
-% :- pragma foreign_export("C#",
-%     make_io_res_1_error_string(in, in, out, di, uo),
-%     "ML_make_io_res_1_error_string").
+:- pragma foreign_export("C#",
+    make_io_res_1_error_string(in, in, out, di, uo),
+    "ML_make_io_res_1_error_string").
 :- pragma foreign_export("Java",
     make_io_res_1_error_string(in, in, out, di, uo),
     "ML_make_io_res_1_error_string").
@@ -4638,8 +4638,8 @@ io.write_many(Stream, [f(F) | Rest], !IO) :-
     "ML_io_print_to_cur_stream").
 :- pragma foreign_export("IL", io.print(in, di, uo),
     "ML_io_print_to_cur_stream").
-% :- pragma foreign_export("C#", io.print(in, di, uo),
-%     "ML_io_print_to_cur_stream").
+:- pragma foreign_export("C#", io.print(in, di, uo),
+    "ML_io_print_to_cur_stream").
 :- pragma foreign_export("Java", io.print(in, di, uo),
     "ML_io_print_to_cur_stream").
 
diff --git a/library/mutvar.m b/library/mutvar.m
index 49cca64..491d74d 100644
--- a/library/mutvar.m
+++ b/library/mutvar.m
@@ -112,7 +112,7 @@ new_mutvar(X, Ref) :-
 % C# implementation
 %
 
-% :- pragma foreign_type("C#", mutvar(T), "object[]").
+:- pragma foreign_type("C#", mutvar(T), "object[]").
 
 :- pragma foreign_proc("C#",
     new_mutvar0(Ref::uo),
diff --git a/library/par_builtin.m b/library/par_builtin.m
index 6f583a7..e87e604 100644
--- a/library/par_builtin.m
+++ b/library/par_builtin.m
@@ -122,7 +122,7 @@
     % Placeholder only.
 :- pragma foreign_type(il, future(T), "class [mscorlib]System.Object").
 :- pragma foreign_type("Erlang", future(T), "").
-% :- pragma foreign_type("C#", future(T), "object").
+:- pragma foreign_type("C#", future(T), "object").
 :- pragma foreign_type("Java", future(T), "java.lang.Object").
 
 %-----------------------------------------------------------------------------%
diff --git a/library/private_builtin.m b/library/private_builtin.m
index c34eb2d..9bd6167 100644
--- a/library/private_builtin.m
+++ b/library/private_builtin.m
@@ -198,7 +198,7 @@ builtin_compare_string(R, S1, S2) :-
     builtin_strcmp(Res::out, S1::in, S2::in),
     [will_not_call_mercury, promise_pure, thread_safe],
 "
-    Res = System.String.Compare(S1, S2);
+    Res = System.String.CompareOrdinal(S1, S2);
 ").
 :- pragma foreign_proc("Java",
     builtin_strcmp(Res::out, S1::in, S2::in),
diff --git a/library/region_builtin.m b/library/region_builtin.m
index 20083e2..f575d48 100644
--- a/library/region_builtin.m
+++ b/library/region_builtin.m
@@ -52,7 +52,7 @@
 :- pragma foreign_type("C", region, "MR_RegionHeader *",
     [can_pass_as_mercury_type]).
 
-% :- pragma foreign_type("C#", region, "object"). % dummy
+:- pragma foreign_type("C#", region, "object"). % dummy
 
 :- pragma foreign_type("Java", region, "java.lang.Object"). % dummy
 
diff --git a/library/rtti_implementation.m b/library/rtti_implementation.m
index 804c081..ca0a9a9 100644
--- a/library/rtti_implementation.m
+++ b/library/rtti_implementation.m
@@ -183,30 +183,30 @@
     % We keep all the other types abstract.
 
 :- type type_ctor_info ---> type_ctor_info(c_pointer).
-% :- pragma foreign_type("C#", type_ctor_info,
-%     "runtime.TypeCtorInfo_Struct").
+:- pragma foreign_type("C#", type_ctor_info,
+    "runtime.TypeCtorInfo_Struct").
 :- pragma foreign_type("Java", type_ctor_info,
     "jmercury.runtime.TypeCtorInfo_Struct").
 
 :- type type_info ---> type_info(c_pointer).
-% :- pragma foreign_type("C#", type_info, "runtime.TypeInfo_Struct").
+:- pragma foreign_type("C#", type_info, "runtime.TypeInfo_Struct").
 :- pragma foreign_type("Java", type_info, "jmercury.runtime.TypeInfo_Struct").
 
 :- type type_layout ---> type_layout(c_pointer).
-% :- pragma foreign_type("C#", type_layout, "runtime.TypeLayout").
+:- pragma foreign_type("C#", type_layout, "runtime.TypeLayout").
 :- pragma foreign_type("Java", type_layout, "jmercury.runtime.TypeLayout").
 
 :- type pseudo_type_info ---> pseudo_type_info(int).
     % This should be a dummy type. The non-dummy definition is a workaround
     % for a bug in the Erlang backend that generates invalid code for the
     % dummy type.
-% :- pragma foreign_type("C#", pseudo_type_info,
-%     "runtime.PseudoTypeInfo").
+:- pragma foreign_type("C#", pseudo_type_info,
+    "runtime.PseudoTypeInfo").
 :- pragma foreign_type("Java", pseudo_type_info,
     "jmercury.runtime.PseudoTypeInfo").
 
 :- type typeclass_info ---> typeclass_info(c_pointer).
-% :- pragma foreign_type("C#", typeclass_info, "object[]").
+:- pragma foreign_type("C#", typeclass_info, "object[]").
 :- pragma foreign_type("Java", typeclass_info, "java.lang.Object[]").
 
 :- pragma foreign_decl("C#", local,
@@ -843,7 +843,7 @@ compare_tuple_pos(Loc, TupleArity, TypeInfo, Result, TermA, TermB) :-
 :- type unify_or_compare_pred
     --->    unify_or_compare_pred.
 
-% :- pragma foreign_type("C#", unify_or_compare_pred, "object").
+:- pragma foreign_type("C#", unify_or_compare_pred, "object").
 :- pragma foreign_type("Java", unify_or_compare_pred,
     "jmercury.runtime.MethodPtr").
 
@@ -1118,8 +1118,8 @@ result_call_9(_::in, (=)::out, _::in, _::in, _::in, _::in, _::in,
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
 
-% :- pragma foreign_export("C#", compare_type_infos(out, in, in),
-%     "ML_compare_type_infos").
+:- pragma foreign_export("C#", compare_type_infos(out, in, in),
+    "ML_compare_type_infos").
 :- pragma foreign_export("Java", compare_type_infos(out, in, in),
     "ML_compare_type_infos").
 
@@ -1185,8 +1185,8 @@ compare_collapsed_type_infos(Res, TypeInfo1, TypeInfo2) :-
 :- pred compare_type_ctor_infos(comparison_result::out,
     type_ctor_info::in, type_ctor_info::in) is det.
 
-% :- pragma foreign_export("C#", compare_type_ctor_infos(out, in, in),
-%     "ML_compare_type_ctor_infos").
+:- pragma foreign_export("C#", compare_type_ctor_infos(out, in, in),
+    "ML_compare_type_ctor_infos").
 :- pragma foreign_export("Java", compare_type_ctor_infos(out, in, in),
     "ML_compare_type_ctor_infos").
 
@@ -1254,8 +1254,8 @@ type_ctor_is_variable_arity(TypeCtorInfo) :-
 %-----------------------------------------------------------------------------%
 
 :- func collapse_equivalences(type_info) = type_info.
-% :- pragma foreign_export("C#", collapse_equivalences(in) = out,
-%     "ML_collapse_equivalences").
+:- pragma foreign_export("C#", collapse_equivalences(in) = out,
+    "ML_collapse_equivalences").
 :- pragma foreign_export("Java", collapse_equivalences(in) = out,
     "ML_collapse_equivalences").
 
@@ -1656,22 +1656,24 @@ is_exist_pseudo_type_info(_, _) :-
     ML_construct_du(runtime.TypeCtorInfo_Struct tc,
         runtime.DuFunctorDesc functor_desc, list.List_1 arg_list)
     {
+        string typename;
         System.Type type;
 
         if (tc.type_ctor_num_functors == 1) {
-            type = System.Type.GetType(
+            typename =
                 ""mercury."" + ML_name_mangle(tc.type_ctor_module_name)
                 + ""+"" + ML_flipInitialCase(ML_name_mangle(tc.type_ctor_name))
-                + ""_"" + tc.arity);
+                + ""_"" + tc.arity;
         } else {
-            type = System.Type.GetType(
+            typename =
                 ""mercury."" + ML_name_mangle(tc.type_ctor_module_name)
                 + ""+"" + ML_flipInitialCase(ML_name_mangle(tc.type_ctor_name))
                 + ""_"" + tc.arity
                 + ""+"" + ML_flipInitialCase(ML_name_mangle(
                             functor_desc.du_functor_name))
-                + ""_"" + functor_desc.du_functor_orig_arity);
+                + ""_"" + functor_desc.du_functor_orig_arity;
         }
+        type = ML_search_type(typename);
 
         int arity = functor_desc.du_functor_orig_arity;
         object[] args = ML_univ_list_to_array(arg_list, arity);
@@ -1707,13 +1709,29 @@ is_exist_pseudo_type_info(_, _) :-
     private static object
     ML_construct_static_member(runtime.TypeCtorInfo_Struct tc, int i)
     {
-        System.Type type = System.Type.GetType(
+        string typename =
             ""mercury."" + ML_name_mangle(tc.type_ctor_module_name)
             + ""+"" + ML_flipInitialCase(ML_name_mangle(tc.type_ctor_name))
-            + ""_"" + tc.arity);
+            + ""_"" + tc.arity;
+        System.Type type = ML_search_type(typename);
         return System.Enum.ToObject(type, i);
     }
 
+    private static System.Type ML_search_type(string typename)
+    {
+        // Do we need to optimise this?  e.g. search the current assembly,
+        // then that which contains the standard library, or cache old results.
+        System.Reflection.Assembly[] av =
+            System.AppDomain.CurrentDomain.GetAssemblies();
+        foreach (System.Reflection.Assembly a in av) {
+            System.Type t = a.GetType(typename);
+            if (t != null) {
+                return t;
+            }
+        }
+        return null;
+    }
+
     private static string
     ML_flipInitialCase(string s)
     {
@@ -3516,29 +3534,29 @@ get_remote_secondary_tag(_::in) = (0::out) :-
 % :- pragma foreign_type("Java", sectag_locn, "jmercury.runtime.Sectag_Locn").
 
 :- type du_sectag_alternatives ---> du_sectag_alternatives(c_pointer).
-% :- pragma foreign_type("C#", du_sectag_alternatives,
-%     "runtime.DuFunctorDesc[]").
+:- pragma foreign_type("C#", du_sectag_alternatives,
+    "runtime.DuFunctorDesc[]").
 :- pragma foreign_type("Java", du_sectag_alternatives,
     "jmercury.runtime.DuFunctorDesc[]").
 
 :- type ptag_entry ---> ptag_entry(c_pointer).
-% :- pragma foreign_type("C#", ptag_entry, "runtime.DuPtagLayout").
+:- pragma foreign_type("C#", ptag_entry, "runtime.DuPtagLayout").
 :- pragma foreign_type("Java", ptag_entry, "jmercury.runtime.DuPtagLayout").
 
 :- type arg_types ---> arg_types(c_pointer).
-% :- pragma foreign_type("C#", arg_types, "runtime.PseudoTypeInfo[]").
+:- pragma foreign_type("C#", arg_types, "runtime.PseudoTypeInfo[]").
 :- pragma foreign_type("Java", arg_types, "jmercury.runtime.PseudoTypeInfo[]").
 
 :- type arg_names ---> arg_names(c_pointer).
-% :- pragma foreign_type("C#", arg_names, "string[]").
+:- pragma foreign_type("C#", arg_names, "string[]").
 :- pragma foreign_type("Java", arg_names, "java.lang.String[]").
 
 :- type exist_info ---> exist_info(c_pointer).
-% :- pragma foreign_type("C#", exist_info, "runtime.DuExistInfo").
+:- pragma foreign_type("C#", exist_info, "runtime.DuExistInfo").
 :- pragma foreign_type("Java", exist_info, "jmercury.runtime.DuExistInfo").
 
 :- type typeinfo_locn ---> typeinfo_locn(c_pointer).
-% :- pragma foreign_type("C#", typeinfo_locn, "runtime.DuExistLocn").
+:- pragma foreign_type("C#", typeinfo_locn, "runtime.DuExistLocn").
 :- pragma foreign_type("Java", typeinfo_locn, "jmercury.runtime.DuExistLocn").
 
 :- func ptag_index(int, type_layout) = ptag_entry.
@@ -4354,32 +4372,32 @@ type_ctor_search_functor_number_map(_, _, _) :-
 %
 
 :- type type_functors ---> type_functors(c_pointer).
-% :- pragma foreign_type("C#", type_functors,
-%     "runtime.TypeFunctors").
+:- pragma foreign_type("C#", type_functors,
+    "runtime.TypeFunctors").
 :- pragma foreign_type("Java", type_functors,
     "jmercury.runtime.TypeFunctors").
 
 :- type du_functor_desc ---> du_functor_desc(c_pointer).
-% :- pragma foreign_type("C#", du_functor_desc,
-%     "runtime.DuFunctorDesc").
+:- pragma foreign_type("C#", du_functor_desc,
+    "runtime.DuFunctorDesc").
 :- pragma foreign_type("Java", du_functor_desc,
     "jmercury.runtime.DuFunctorDesc").
 
 :- type enum_functor_desc ---> enum_functor_desc(c_pointer).
-% :- pragma foreign_type("C#", enum_functor_desc,
-%     "runtime.EnumFunctorDesc").
+:- pragma foreign_type("C#", enum_functor_desc,
+    "runtime.EnumFunctorDesc").
 :- pragma foreign_type("Java", enum_functor_desc,
     "jmercury.runtime.EnumFunctorDesc").
 
 :- type foreign_enum_functor_desc ---> foreign_enum_functor_desc(c_pointer).
-% :- pragma foreign_type("C#", foreign_enum_functor_desc,
-%     "runtime.ForeignEnumFunctorDesc").
+:- pragma foreign_type("C#", foreign_enum_functor_desc,
+    "runtime.ForeignEnumFunctorDesc").
 :- pragma foreign_type("Java", foreign_enum_functor_desc,
     "jmercury.runtime.ForeignEnumFunctorDesc").
 
 :- type notag_functor_desc ---> notag_functor_desc(c_pointer).
-% :- pragma foreign_type("C#", notag_functor_desc,
-%     "runtime.NotagFunctorDesc").
+:- pragma foreign_type("C#", notag_functor_desc,
+    "runtime.NotagFunctorDesc").
 :- pragma foreign_type("Java", notag_functor_desc,
     "jmercury.runtime.NotagFunctorDesc").
 
diff --git a/library/store.m b/library/store.m
index 94b63e0..e85da4b 100644
--- a/library/store.m
+++ b/library/store.m
@@ -248,8 +248,8 @@
     where equality is store_equal, comparison is store_compare.
 :- pragma foreign_type("IL", store(S), "int32", [can_pass_as_mercury_type])
     where equality is store_equal, comparison is store_compare.
-% :- pragma foreign_type("C#", store(S), "int32", [can_pass_as_mercury_type])
-%     where equality is store_equal, comparison is store_compare.
+:- pragma foreign_type("C#", store(S), "int", [can_pass_as_mercury_type])
+    where equality is store_equal, comparison is store_compare.
 :- pragma foreign_type("Java", store(S), "int", [can_pass_as_mercury_type])
     where equality is store_equal, comparison is store_compare.
 :- pragma foreign_type("Erlang", store(S), "", [can_pass_as_mercury_type])
@@ -343,7 +343,7 @@ store.new(S) :-
     S = S0;
 ").
 
-% :- pragma foreign_type("C#", generic_mutvar(T, S), "object[]").
+:- pragma foreign_type("C#", generic_mutvar(T, S), "object[]").
 
 :- pragma foreign_proc("C#",
     new_mutvar(Val::in, Mutvar::out, _S0::di, _S::uo),
@@ -450,7 +450,7 @@ store.new_cyclic_mutvar(Func, MutVar, !Store) :-
 
 %-----------------------------------------------------------------------------%
 
-% :- pragma foreign_type("C#", generic_ref(T, S), "store.Ref").
+:- pragma foreign_type("C#", generic_ref(T, S), "store.Ref").
 :- pragma foreign_code("C#",
 "
     public class Ref {
diff --git a/library/string.m b/library/string.m
index 344db75..ddb1313 100644
--- a/library/string.m
+++ b/library/string.m
@@ -30,7 +30,7 @@
 % comparison is implemented using C's strcmp() function.  When Mercury
 % is compiled to Java, string comparison is implemented using Java's
 % String.compareTo() method.  When Mercury is compiled to .NET IL code
-% string comparison is implemented using C#'s System.String.Compare()
+% string comparison is implemented using C#'s System.String.CompareOrdinal()
 % method.
 %
 %-----------------------------------------------------------------------------%
@@ -4001,7 +4001,7 @@ string.set_char(Char, Index, !Str) :-
     string.set_char_2(Ch::in, Index::in, Str0::in, Str::out),
     [will_not_call_mercury, promise_pure, thread_safe],
 "
-    if (Index >= Str0.Length) {
+    if (Index < 0 || Index >= Str0.Length) {
         Str = null;
         SUCCESS_INDICATOR = false;
     } else {
@@ -4689,7 +4689,7 @@ string.split(Str, Count, Left, Right) :-
     SUCCESS_INDICATOR = (
         len > 0 &&
         Str[0] == First &&
-        System.String.Compare(Str, 1, Rest, 0, len) == 0
+        System.String.CompareOrdinal(Str, 1, Rest, 0, len) == 0
     );
 ").
 :- pragma foreign_proc("Java",
@@ -4726,7 +4726,8 @@ string.split(Str, Count, Left, Right) :-
 "
     int len = Str.Length;
     if (len > 0) {
-        SUCCESS_INDICATOR = (System.String.Compare(Str, 1, Rest, 0, len) == 0);
+        SUCCESS_INDICATOR = (System.String.CompareOrdinal(Str, 1, Rest, 0, len)
+            == 0);
         First = Str[0];
     } else {
         SUCCESS_INDICATOR = false;
diff --git a/library/thread.m b/library/thread.m
index ee3b223..3a07c33 100644
--- a/library/thread.m
+++ b/library/thread.m
@@ -389,9 +389,9 @@ INIT mercury_sys_init_thread_modules
 :- pragma foreign_export("IL",
     call_back_to_mercury(pred(di, uo) is cc_multi, di, uo),
     "ML_call_back_to_mercury_cc_multi").
-% :- pragma foreign_export("C#",
-%     call_back_to_mercury(pred(di, uo) is cc_multi, di, uo),
-%     "ML_call_back_to_mercury_cc_multi").
+:- pragma foreign_export("C#",
+    call_back_to_mercury(pred(di, uo) is cc_multi, di, uo),
+    "ML_call_back_to_mercury_cc_multi").
 :- pragma foreign_export("Java",
     call_back_to_mercury(pred(di, uo) is cc_multi, di, uo),
     "ML_call_back_to_mercury_cc_multi").
diff --git a/library/thread.semaphore.m b/library/thread.semaphore.m
index d71b297..2ee8ce8 100644
--- a/library/thread.semaphore.m
+++ b/library/thread.semaphore.m
@@ -95,7 +95,7 @@ public class ML_Semaphore {
     [can_pass_as_mercury_type]).
 :- pragma foreign_type("IL", semaphore,
     "class [mercury]mercury.thread.semaphore__csharp_code.mercury_code.ML_Semaphore").
-% :- pragma foreign_type("C#", semaphore, "thread__semaphore.ML_Semaphore").
+:- pragma foreign_type("C#", semaphore, "thread__semaphore.ML_Semaphore").
 :- pragma foreign_type("Erlang", semaphore, "").
 :- pragma foreign_type("Java", semaphore, "java.util.concurrent.Semaphore").
 
@@ -145,7 +145,7 @@ new(Semaphore, !IO) :-
     new(Count::in) = (Semaphore::uo),
     [promise_pure, will_not_call_mercury, thread_safe],
 "
-    Semaphore = new ML_Semaphore();
+    Semaphore = new thread__semaphore.ML_Semaphore();
     Semaphore.count = Count;
 ").
 
diff --git a/library/time.m b/library/time.m
index 58620d2..41bc395 100644
--- a/library/time.m
+++ b/library/time.m
@@ -237,8 +237,8 @@
 :- pragma foreign_type("IL", time_t_rep, "valuetype [mscorlib]System.DateTime")
     where comparison is compare_time_t_reps.
 
-% :- pragma foreign_type("C#", time_t_rep, "System.DateTime")
-%     where comparison is compare_time_t_reps.
+:- pragma foreign_type("C#", time_t_rep, "System.DateTime")
+    where comparison is compare_time_t_reps.
 
 :- pragma foreign_type("Java", time_t_rep, "java.util.Date")
     where comparison is compare_time_t_reps.
@@ -1010,8 +1010,8 @@ time.ctime(Time) = asctime(localtime(Time)).
     "ML_construct_time_t").
 :- pragma foreign_export("IL", construct_time_t(in) = out,
     "ML_construct_time_t").
-% :- pragma foreign_export("C#", construct_time_t(in) = out,
-%     "ML_construct_time_t").
+:- pragma foreign_export("C#", construct_time_t(in) = out,
+    "ML_construct_time_t").
 :- pragma foreign_export("Java", construct_time_t(in) = out,
     "ML_construct_time_t").
 
diff --git a/library/univ.m b/library/univ.m
index cfc547d..c61308c 100644
--- a/library/univ.m
+++ b/library/univ.m
@@ -127,7 +127,7 @@ univ_type(Univ) = type_of(univ_value(Univ)).
 :- pred construct_univ(T::in, univ::out) is det.
 :- pragma foreign_export("C", construct_univ(in, out), "ML_construct_univ").
 :- pragma foreign_export("IL", construct_univ(in, out), "ML_construct_univ").
-% :- pragma foreign_export("C#", construct_univ(in, out), "ML_construct_univ").
+:- pragma foreign_export("C#", construct_univ(in, out), "ML_construct_univ").
 :- pragma foreign_export("Java", construct_univ(in, out), "ML_construct_univ").
 
 construct_univ(X, Univ) :-
@@ -136,7 +136,7 @@ construct_univ(X, Univ) :-
 :- some [T] pred unravel_univ(univ::in, T::out) is det.
 :- pragma foreign_export("C", unravel_univ(in, out), "ML_unravel_univ").
 :- pragma foreign_export("IL", unravel_univ(in, out), "ML_unravel_univ").
-% :- pragma foreign_export("C#", unravel_univ(in, out), "ML_unravel_univ").
+:- pragma foreign_export("C#", unravel_univ(in, out), "ML_unravel_univ").
 :- pragma foreign_export("Java", unravel_univ(in, out), "ML_unravel_univ").
 
 unravel_univ(Univ, X) :-
diff --git a/library/version_array.m b/library/version_array.m
index d82a76c..7f6c237 100644
--- a/library/version_array.m
+++ b/library/version_array.m
@@ -285,10 +285,10 @@ unsafe_rewind(VA, unsafe_rewind(VA)).
         equality   is eq_version_array,
         comparison is cmp_version_array.
 
-% :- pragma foreign_type("C#", version_array(T), "version_array.ML_va")
-%     where
-%         equality   is eq_version_array,
-%         comparison is cmp_version_array.
+:- pragma foreign_type("C#", version_array(T), "version_array.ML_va")
+    where
+        equality   is eq_version_array,
+        comparison is cmp_version_array.
 
 :- pragma foreign_type("Java", version_array(T),
     "jmercury.version_array.ML_va")
diff --git a/mdbcomp/Mmakefile b/mdbcomp/Mmakefile
index 8f1d2c0..c7eced3 100644
--- a/mdbcomp/Mmakefile
+++ b/mdbcomp/Mmakefile
@@ -88,7 +88,7 @@ LN	= ln
 # complete, so we need to pass `--allow-stubs' to get them to compile.
 # Since the standard library is compiled with `--halt-at-warn',
 # we also need `--no-warn-stubs'.
-ifneq ("$(filter il% java% erlang%,$(GRADE))","")
+ifneq ("$(filter il% csharp% java% erlang%,$(GRADE))","")
 MCFLAGS += --allow-stubs --no-warn-stubs
 endif
 
@@ -211,7 +211,7 @@ realclean_local:
 .PHONY: install
 install: install_library
 
-ifneq ("$(filter il% erlang%,$(GRADE))","")
+ifneq ("$(filter il% csharp% erlang%,$(GRADE))","")
 
 # there is no debugger in the .NET or Erlang backends
 
diff --git a/mdbcomp/rtti_access.m b/mdbcomp/rtti_access.m
index ad85fd4..b07f16b 100644
--- a/mdbcomp/rtti_access.m
+++ b/mdbcomp/rtti_access.m
@@ -105,8 +105,10 @@
 
 :- pragma foreign_type("C", bytecode_bytes, "const MR_uint_least8_t *",
     [can_pass_as_mercury_type, stable]).
+    % The following definitions are only stubs.
+:- pragma foreign_type("C#", bytecode_bytes, "object", []).
 :- pragma foreign_type("Java", bytecode_bytes, "java.lang.Object", []).
-    % stub only
+:- pragma foreign_type("Erlang", bytecode_bytes, "").
 
     % read_byte(ByteCode, Byte, !Pos):
     %
@@ -176,7 +178,8 @@
 
 :- pragma foreign_type("C", label_layout, "const MR_LabelLayout *",
     [can_pass_as_mercury_type, stable]).
-    % The Java and Erlang definitions are only stubs.
+    % The following definitions are only stubs.
+:- pragma foreign_type("C#", label_layout, "object", []).
 :- pragma foreign_type("Java", label_layout, "java.lang.Object", []).
 :- pragma foreign_type("Erlang", label_layout, "").
 
@@ -229,7 +232,8 @@ get_path_port_from_label_layout(Label) = PathPort :-
 
 :- pragma foreign_type("C", proc_layout, "const MR_ProcLayout *",
     [can_pass_as_mercury_type, stable]).
-    % The Java and Erlang definitions are only stubs.
+    % The following definitions are only stubs.
+:- pragma foreign_type("C#", proc_layout, "object", []).
 :- pragma foreign_type("Java", proc_layout, "java.lang.Object", []).
 :- pragma foreign_type("Erlang", proc_layout, "").
 
@@ -546,6 +550,13 @@ get_proc_name(special_proc_label(_, _, _, ProcName , _, _)) = ProcName.
 #endif
 ").
 
+:- pragma foreign_proc("C#",
+    proc_bytecode_bytes(_ProcLayout::in) = (_ByteCodeBytes::out),
+    [will_not_call_mercury, thread_safe, promise_pure],
+"
+    throw new System.Exception(\"not supported in C# grade\");
+").
+
 :- pragma foreign_proc("Java",
     proc_bytecode_bytes(_ProcLayout::in) = (_ByteCodeBytes::out),
     [will_not_call_mercury, thread_safe, promise_pure],
@@ -561,13 +572,15 @@ proc_bytecode_bytes(_) = dummy_bytecode_bytes.
 :- pragma foreign_type("C", module_common_layout,
     "const MR_ModuleCommonLayout *",
     [can_pass_as_mercury_type, stable]).
-    % The Java and Erlang definitions are only stubs.
+    % The following definitions are only stubs.
+:- pragma foreign_type("C#", module_common_layout, "object", []).
 :- pragma foreign_type("Java", module_common_layout, "java.lang.Object", []).
 :- pragma foreign_type("Erlang", module_common_layout, "").
 
 :- pragma foreign_type("C", string_table_chars, "MR_ConstString",
     [can_pass_as_mercury_type, stable]).
-    % The Java and Erlang definitions are only stubs.
+    % The following definitions are only stubs.
+:- pragma foreign_type("C#", string_table_chars, "object", []).
 :- pragma foreign_type("Java", string_table_chars, "java.lang.Object", []).
 :- pragma foreign_type("Erlang", string_table_chars, "").
 
diff --git a/profiler/Mmakefile b/profiler/Mmakefile
index a533dd6..a78f80d 100644
--- a/profiler/Mmakefile
+++ b/profiler/Mmakefile
@@ -39,7 +39,7 @@ all:	mercury_profile $(TAGS_FILE_EXISTS)
 # Add some additional dependencies, so that Mmake knows to remake the
 # profiler if one of the libraries changes.
 
-ifeq ("$(filter il% java% erlang%,$(GRADE))","")        
+ifeq ("$(filter il% csharp% java% erlang%,$(GRADE))","")
 mercury_profile: $(RUNTIME_DIR)/lib$(RT_LIB_NAME).$A
 mercury_profile: $(LIBRARY_DIR)/lib$(STD_LIB_NAME).$A
 # XXX Should also depend on $(BOEHM_GC_DIR)/libgc(_prof).$A, but only
diff --git a/runtime/Mmakefile b/runtime/Mmakefile
index 6f3f42a..41aab2b 100644
--- a/runtime/Mmakefile
+++ b/runtime/Mmakefile
@@ -339,19 +339,19 @@ mercury_method_call_codes.i: ../tools/make_spec_method_call
 .PHONY: all
 all:	runtime $(TAGS_FILE_EXISTS)
 
-ifneq "$(filter java% erlang%,$(GRADE))" ""
+ifneq "$(filter csharp% java% erlang%,$(GRADE))" ""
 #
-# For grade java and erlang, there's nothing to do
+# For these grades, there's nothing to do.
 
 .PHONY: runtime
 runtime:
-	@echo "No Mercury runtime needed for grade=java and grade=erlang"
+	@echo "No Mercury runtime needed for GRADE=$(GRADE)"
 
 else
 ifeq ($(findstring il,$(GRADE)),il)
 
 # We put the runtime and library dlls into a single assembly called `mercury'
-MS_CSCFLAGS=/t:module
+CSCFLAGS=/t:module
 
 # We need to build the following DLLs for the .NET runtime
 DOTNET_DLLS=mercury_il.dll mercury_dotnet.dll
@@ -367,7 +367,7 @@ mercury_dotnet.dll: mercury_il.dll
 # that will work with ROTOR.
 # mercury_il.dll: mercury_il.il
 #	sed '/REMOVE FOR ROTOR/s@^@//@' mercury_il.il > mercury_il.rotor.il
-#	$(MS_ILASM) $(ALL_MS_ILASMFLAGS) /dll /quiet /OUT=mercury_il.dll \
+#	$(ILASM) $(ALL_ILASMFLAGS) /dll /quiet /OUT=mercury_il.dll \
 #			mercury_il.rotor.il
 
 else
@@ -458,9 +458,9 @@ install_dirs:
 	-[ -d $(INSTALL_RECONF_DIR)/runtime ] || \
 		mkdir -p $(INSTALL_RECONF_DIR)/runtime
 
-ifneq "$(filter java% erlang%,$(GRADE))" ""
+ifneq "$(filter csharp% java% erlang%,$(GRADE))" ""
 
-# For grade java and erlang, there's nothing to do.
+# For these grades, there's nothing to do.
 # (The java version of the Mercury runtime is in mercury/java/runtime,
 # not mercury/runtime, and its build and installation is handled by
 # mercury/library/Mmakefile.)
@@ -488,7 +488,7 @@ install_init:
 install_lib: $(DOTNET_DLLS) install_headers install_dirs
 	cp `vpath_find $(DOTNET_DLLS)` $(INSTALL_MERC_LIB_DIR)
 
-#MS_ILASMFLAGS=/debug
+#ILASMFLAGS=/debug
 
 else
 
diff --git a/runtime/mercury_dotnet.cs.in b/runtime/mercury_dotnet.cs.in
index 3c1e2cd..407db44 100644
--- a/runtime/mercury_dotnet.cs.in
+++ b/runtime/mercury_dotnet.cs.in
@@ -191,7 +191,18 @@ public class TypeCtorInfo_Struct : PseudoTypeInfo {
         type_functor_number_map = functor_number_map;
     }
 
+    public override bool Equals(object other) {
+        TypeCtorInfo_Struct tci = other as TypeCtorInfo_Struct;
+        if ((System.Object)tci == null) {
+            return false;
+        }
+        return this.Equals(tci);
+    }
+
     public bool Equals(TypeCtorInfo_Struct tci) {
+        if (tci == null) {
+            return false;
+        }
         if (this == tci) {
             return true;
         }
@@ -199,6 +210,16 @@ public class TypeCtorInfo_Struct : PseudoTypeInfo {
             && type_ctor_name.Equals(tci.type_ctor_name)
             && arity == tci.arity;
     }
+
+    public override int GetHashCode() {
+        return type_ctor_module_name.GetHashCode()
+            ^ type_ctor_name.GetHashCode()
+            ^ arity;
+    }
+
+    public override string ToString() {
+        return type_ctor_module_name + "." + type_ctor_name + "/" + arity;
+    }
 }
 
 public class TypeInfo_Struct : PseudoTypeInfo {
@@ -266,7 +287,19 @@ public class TypeInfo_Struct : PseudoTypeInfo {
         return ti;
     }
 
+    public override bool Equals(object other) {
+        TypeInfo_Struct ti = other as TypeInfo_Struct;
+        if ((System.Object)ti == null) {
+            return false;
+        }
+        return this.Equals(ti);
+    }
+
     public bool Equals(TypeInfo_Struct ti) {
+        if (ti == null) {
+            return false;
+        }
+
         if (this == ti) {
             return true;
         }
@@ -317,6 +350,29 @@ public class TypeInfo_Struct : PseudoTypeInfo {
 
         return ti;
     }
+
+    public override int GetHashCode() {
+        int hash = type_ctor.GetHashCode();
+        if (args != null) {
+            foreach (PseudoTypeInfo a in args) {
+                hash ^= a.GetHashCode();
+            }
+        }
+        return hash;
+    }
+
+    /* Useful for debugging.
+    public override string ToString() {
+        string s = type_ctor.ToString() + "(";
+        if (args != null) {
+            foreach (PseudoTypeInfo a in args) {
+                s += a.ToString() + ",";
+            }
+        }
+        s += ")";
+        return s;
+    }
+    */
 }
 
 public class TypeLayout {
diff --git a/scripts/Mercury.config.bootstrap.in b/scripts/Mercury.config.bootstrap.in
index b8c9164..3715911 100644
--- a/scripts/Mercury.config.bootstrap.in
+++ b/scripts/Mercury.config.bootstrap.in
@@ -27,7 +27,7 @@ MERCURY_C_COMPILER=@CC@
 MERCURY_MATH_LIB=@MATH_LIB@
 MERCURY_JAVA_COMPILER=@JAVAC@
 MERCURY_JAVA_INTERPRETER=@JAVA_INTERPRETER@
-MERCURY_CSHARP_COMPILER=@MS_CSC@
+MERCURY_CSHARP_COMPILER=@CSC@
 # $(MATH_LIB) needs to be defined because it may
 # be used by the substitution for SHARED_LIBS.
 MATH_LIB=$(MERCURY_MATH_LIB)
diff --git a/scripts/Mercury.config.in b/scripts/Mercury.config.in
index db85fb4..44f9420 100644
--- a/scripts/Mercury.config.in
+++ b/scripts/Mercury.config.in
@@ -27,7 +27,8 @@ MERCURY_C_COMPILER_TYPE=@C_COMPILER_TYPE@
 MERCURY_MATH_LIB=@MATH_LIB@
 MERCURY_JAVA_COMPILER=@JAVAC@
 MERCURY_JAVA_INTERPRETER=@JAVA_INTERPRETER@
-MERCURY_CSHARP_COMPILER=@MS_CSC@
+MERCURY_CSHARP_COMPILER=@CSC@
+MERCURY_CLI_INTERPRETER=@CLI_INTERPRETER@
 MERCURY_ERLANG_COMPILER=@ERLC@
 MERCURY_ERLANG_INTERPRETER=@ERL@
 # $(MATH_LIB) needs to be defined because it may
@@ -53,6 +54,7 @@ DEFAULT_MCFLAGS=\
 		--java-compiler "$(MERCURY_JAVA_COMPILER)" \
 		--java-interpreter "$(MERCURY_JAVA_INTERPRETER)" \
 		--csharp-compiler "$(MERCURY_CSHARP_COMPILER)" \
+		--cli-interpreter "$(MERCURY_CLI_INTERPRETER)" \
 		--erlang-compiler "$(MERCURY_ERLANG_COMPILER)" \
 		--erlang-interpreter "$(MERCURY_ERLANG_INTERPRETER)" \
 		--cflags-for-ansi "@CFLAGS_FOR_ANSI@" \
diff --git a/scripts/Mmake.rules b/scripts/Mmake.rules
index ec9d71c..ddd8da5 100644
--- a/scripts/Mmake.rules
+++ b/scripts/Mmake.rules
@@ -278,11 +278,11 @@ $(il_dates_subdir)%.il_date : %.m
 ifeq ($(findstring il,$(GRADE)),il)
 
 $(os_subdir)%.dll : %.cs
-	$(MS_CSC) /t:library /lib:`$(FIX_PATH_FOR_CSC) $(MERC_DLL_DIR)` \
-		/out:$@ $(CSHARP_ASSEMBLY_REFS-$*) $(ALL_MS_CSCFLAGS) $<
+	$(CSC) /t:library /lib:`$(FIX_PATH_FOR_CSC) $(MERC_DLL_DIR)` \
+		/out:$@ $(CSHARP_ASSEMBLY_REFS-$*) $(ALL_CSCFLAGS) $<
 
 $(os_subdir)%.dll : %.il
-	$(MS_ILASM) $(ALL_MS_ILASMFLAGS) /dll /quiet /OUT=$@ $<
+	$(ILASM) $(ALL_ILASMFLAGS) /dll /quiet /OUT=$@ $<
 
 mercury.sn:
 	cp $(MERC_DLL_DIR)/mercury.sn .
@@ -378,17 +378,17 @@ endif # $(MMAKE_USE_MMC_MAKE) != yes
 ifeq ($(findstring il,$(GRADE)),il)
 
 .il.dll:
-	$(MS_ILASM) $(ALL_MS_ILASMFLAGS) /dll /quiet /OUT=$@ $<
+	$(ILASM) $(ALL_ILASMFLAGS) /dll /quiet /OUT=$@ $<
 
 .il.exe:
-	$(MS_ILASM) $(ALL_MS_ILASMFLAGS) /quiet /OUT=$@ $<
+	$(ILASM) $(ALL_ILASMFLAGS) /quiet /OUT=$@ $<
 
 .cs.dll:
-	$(MS_CSC) /t:library /lib:`$(FIX_PATH_FOR_CSC) $(MERC_DLL_DIR)` \
+	$(CSC) /t:library /lib:`$(FIX_PATH_FOR_CSC) $(MERC_DLL_DIR)` \
 		/out:$@ $(CSHARP_ASSEMBLY_REFS-$*) $(EXTRA_CSCFLAGS) $<
 
 .cs.exe:
-	$(MS_CSC) /lib:`$(FIX_PATH_FOR_CSC) $(MERC_DLL_DIR)` /out:$@ \
+	$(CSC) /lib:`$(FIX_PATH_FOR_CSC) $(MERC_DLL_DIR)` /out:$@ \
 		$(CSHARP_ASSEMBLY_REFS-$*) $(EXTRA_CSCFLAGS) $<
 
 endif # $(findstring il,$(GRADE)) != ""
diff --git a/scripts/Mmake.vars.in b/scripts/Mmake.vars.in
index 4f80ec7..570ae65 100644
--- a/scripts/Mmake.vars.in
+++ b/scripts/Mmake.vars.in
@@ -132,7 +132,8 @@ ECHO_MERCURY_OPTIONS = { \
 	echo MCFLAGS += '$(MC_MAKE_FLAGS) $(EXTRA_MC_MAKE_FLAGS)'; \
 	echo CFLAGS += '$(ALL_CFLAGS)'; \
 	echo JAVACFLAGS += '$(ALL_JAVACFLAGS)'; \
-	echo MS_ILASMFLAGS += '$(ALL_MS_ILASMFLAGS)'; \
+	echo CSCFLAGS += '$(ALL_CSCFLAGS)'; \
+	echo ILASMFLAGS += '$(ALL_ILASMFLAGS)'; \
 	echo C2INITARGS += '$(ALL_C2INITARGS)'; \
 	echo MLLIBS += '$(ALL_MLLIBS)'; \
 	echo MLOBJS += '$(ALL_MLOBJS)'; \
@@ -230,33 +231,33 @@ MS_DOTNET_SDK_DIR=@MS_DOTNET_SDK_DIR@
 MERC_C_INCL_DIR = $(MERCURY_STDLIB_DIR)/inc
 MERC_DLL_DIR    = $(MERCURY_STDLIB_DIR)/lib/$(GRADESTRING)
 
-# MS_ILASM is the Microsoft IL assembler, which turns IL assembly code
+# ILASM is the Microsoft IL assembler, which turns IL assembly code
 # into bytecode.
 # XXX we should also support the Portable.NET version of ILASM,
 # which has a different command-line interface. 
 # (Is there a Mono ILASM too?  What about Rotor?)
-MS_ILASM	= @ILASM@
-ALL_MS_ILASMFLAGS= $(MS_ILASMFLAGS) $(EXTRA_MS_ILASMFLAGS) \
-		$(TARGET_MS_ILASMFLAGS) $(LIB_MS_ILASMFLAGS) $(ILASM_KEYFLAG)
-MS_ILASMFLAGS	=
-EXTRA_MS_ILASMFLAGS =
-LIB_MS_ILASMFLAGS= $(patsubst %,-I %,$(EXTRA_C_INCL_DIRS))
+ILASM		= @ILASM@
+ALL_ILASMFLAGS= $(ILASMFLAGS) $(EXTRA_ILASMFLAGS) \
+		$(TARGET_ILASMFLAGS) $(LIB_ILASMFLAGS) $(ILASM_KEYFLAG)
+ILASMFLAGS	=
+EXTRA_ILASMFLAGS =
+LIB_ILASMFLAGS= $(patsubst %,-I %,$(EXTRA_C_INCL_DIRS))
 
 # MS_AL is the Microsoft assembly linker, which creates assemblies.
 MS_AL		= @MS_AL@ 
 
-# MS_CSC is the command line version of C# compiler
+# CSC is the command line version of C# compiler
 # XXX we should also support the Portable.NET and Mono C# compilers,
 # which have a different command-line interface. 
 # (What about Rotor?)
 
 FIX_PATH_FOR_CSC = @CYGPATH@
-MS_CSC		= @MS_CSC@ 
-ALL_MS_CSCFLAGS	= $(MS_CSCFLAGS) $(EXTRA_MS_CSCFLAGS) $(TARGET_MS_CSCFLAGS) \
-		$(LIB_MS_CSCFLAGS)
-MS_CSCFLAGS	=
-EXTRA_MS_CSCFLAGS =
-LIB_MS_CSCFLAGS	= 
+CSC		= @CSC@
+ALL_CSCFLAGS	= $(CSCFLAGS) $(EXTRA_CSCFLAGS) $(TARGET_CSCFLAGS) \
+		$(LIB_CSCFLAGS)
+CSCFLAGS	=
+EXTRA_CSCFLAGS =
+LIB_CSCFLAGS	=
 
 #-----------------------------------------------------------------------------#
 #
@@ -522,15 +523,15 @@ EXTRA_TARGET_LIBGRADES = \
 maybe-base-EXTRA_LIBGRADES- = $(EXTRA_LIBGRADES-$*)
 maybe-base-EXTRA_LIBGRADES-undefined =
 
-TARGET_MS_CSCFLAGS = \
-  $(maybe-base-MS_CSCFLAGS-$(findstring undefined,$(origin MS_CSCFLAGS-$*)))
-maybe-base-MS_CSCFLAGS- = $(MS_CSCFLAGS-$*)
-maybe-base-MS_CSCFLAGS-undefined =
+TARGET_CSCFLAGS = \
+  $(maybe-base-CSCFLAGS-$(findstring undefined,$(origin CSCFLAGS-$*)))
+maybe-base-CSCFLAGS- = $(CSCFLAGS-$*)
+maybe-base-CSCFLAGS-undefined =
 
-TARGET_MS_ILASMFLAGS = \
-   $(maybe-base-MS_ILASMFLAGS-$(findstring undefined,$(origin MS_ILASMFLAGS-$*)))
-maybe-base-MS_ILASMFLAGS- = $(MS_ILASMFLAGS-$*)
-maybe-base-MS_ILASMFLAGS-undefined =
+TARGET_ILASMFLAGS = \
+   $(maybe-base-ILASMFLAGS-$(findstring undefined,$(origin ILASMFLAGS-$*)))
+maybe-base-ILASMFLAGS- = $(ILASMFLAGS-$*)
+maybe-base-ILASMFLAGS-undefined =
 
 ILASM_KEYFLAG = \
   $(maybe-target-ILASM_KEYFLAG-$(findstring undefined,$(origin ILASM_KEYFLAG-$*)))
diff --git a/scripts/canonical_grade.sh-subr b/scripts/canonical_grade.sh-subr
index 9b66655..673c8fc 100644
--- a/scripts/canonical_grade.sh-subr
+++ b/scripts/canonical_grade.sh-subr
@@ -37,16 +37,14 @@ case $asm_labels in
 	false)		;;
 esac
 
-case $target in
-	erlang)		GRADE="erlang" ;;
-esac
-
 case $highlevel_code,$highlevel_data,$GRADE,$target in
 	true,true,none,*)		
 		case $target in
 			c|asm)	GRADE="hl" ;;
 			il)	GRADE="il" ;;
+			csharp) GRADE="csharp" ;;
 			java)	GRADE="java" ;;
+			erlang) GRADE="erlang" ;;
 			*)
 				progname=`basename $0`
 				echo "$progname: unknown target: $target"
diff --git a/scripts/final_grade_options.sh-subr b/scripts/final_grade_options.sh-subr
index 5d00ee5..dc49f5d 100644
--- a/scripts/final_grade_options.sh-subr
+++ b/scripts/final_grade_options.sh-subr
@@ -57,23 +57,23 @@ case $decl_debug in true)
 esac
 
 #
-# --target asm, IL or Java implies --high-level-code
+# --target asm, IL, C#, Java, Erlang implies --high-level-code
 #
-case $target in asm|il|java)
+case $target in asm|il|csharp|java|erlang)
 	highlevel_code=true ;;
 esac
 
 #
-# --target IL or Java implies --high-level-data
+# --target IL, C#, Java, Erlang implies --high-level-data
 #
-case $target in il|java)
+case $target in il|csharp|java|erlang)
 	highlevel_data=true ;;
 esac
 
 #
-# --target IL or Java or Erlang implies --gc automatic
+# --target IL, C#, Java, Erlang implies --gc automatic
 #
-case $target in il|java|erlang)
+case $target in il|csharp|java|erlang)
 	gc_method=automatic ;;
 esac
 
diff --git a/scripts/init_grade_options.sh-subr b/scripts/init_grade_options.sh-subr
index cdd8ce6..15edf09 100644
--- a/scripts/init_grade_options.sh-subr
+++ b/scripts/init_grade_options.sh-subr
@@ -23,7 +23,7 @@
 grade_usage="\
 Grade options:
 	-s <grade>, --grade <grade>
-	--target {il, c, java, asm}
+	--target {il, c, csharp, java, erlang, asm}
 	--il
 	--asm-labels
 	--gcc-non-local-gotos
diff --git a/scripts/parse_grade_options.sh-subr b/scripts/parse_grade_options.sh-subr
index 80571bd..84755b2 100644
--- a/scripts/parse_grade_options.sh-subr
+++ b/scripts/parse_grade_options.sh-subr
@@ -30,6 +30,8 @@
                 target=c ;;
             il|IL)
                 target=il ;;
+            csharp|'C#')
+                target=csharp ;;
             java|Java)
                 target=java ;;
             erlang|Erlang)
@@ -44,6 +46,9 @@
     --il|--IL|--il-only|--IL-only)
         target=il ;;
 
+    --csharp|'--C#'|--csharp-only|'--C#-only')
+        target=csharp ;;
+
     --java|--Java|--java-only|--Java-only)
         target=java ;;
 
@@ -289,6 +294,15 @@
                     gcc_nested_functions=false
                     highlevel_data=false
                     ;;
+                csharp)
+                    target=csharp
+                    asm_labels=false
+                    non_local_gotos=false
+                    global_regs=false
+                    highlevel_code=true
+                    gcc_nested_functions=false
+                    highlevel_data=true
+                    ;;
                 java)
                     target=java
                     asm_labels=false
@@ -300,6 +314,12 @@
                     ;;
                 erlang)
                     target=erlang
+                    asm_labels=false
+                    non_local_gotos=false
+                    global_regs=false
+                    highlevel_code=true
+                    gcc_nested_functions=false
+                    highlevel_data=true
                     ;;
                 hl)
                     asm_labels=false
diff --git a/scripts/prepare_install_dir.in b/scripts/prepare_install_dir.in
index b0804e7..79581b7 100644
--- a/scripts/prepare_install_dir.in
+++ b/scripts/prepare_install_dir.in
@@ -66,6 +66,7 @@ cp runtime/Mmake* ${installdir}/runtime
 cp runtime/.mgnuc* ${installdir}/runtime
 cp runtime/*.in ${installdir}/runtime
 cp runtime/*.[ch] ${installdir}/runtime
+cp runtime/*.cs ${installdir}/runtime
 cp runtime/*.il ${installdir}/runtime
 cp runtime/machdeps/*.h ${installdir}/runtime/machdeps
 mkdir ${installdir}/trace
diff --git a/slice/Mmakefile b/slice/Mmakefile
index 6a33b90..f7918a1 100644
--- a/slice/Mmakefile
+++ b/slice/Mmakefile
@@ -92,7 +92,7 @@ $(MDBCOMP_MODULES): $(MDBCOMP_ORIG_MODULES)
 # Add some additional dependencies, so that Mmake knows to remake the
 # slicer and dicer if one of the libraries changes.
 
-ifeq ("$(filter il% java% erlang%,$(GRADE))","")        
+ifeq ("$(filter il% csharp% java% erlang%,$(GRADE))","")
 mslice: $(RUNTIME_DIR)/lib$(RT_LIB_NAME).$A
 mslice: $(LIBRARY_DIR)/lib$(STD_LIB_NAME).$A
 mslice: $(BROWSER_DIR)/lib$(BROWSER_LIB_NAME).$A
diff --git a/ssdb/Mmakefile b/ssdb/Mmakefile
index 58f5ccd..d9f35e8 100644
--- a/ssdb/Mmakefile
+++ b/ssdb/Mmakefile
@@ -99,7 +99,7 @@ LN	= ln
 # complete, so we need to pass `--allow-stubs' to get them to compile.
 # Since the standard library is compiled with `--halt-at-warn',
 # we also need `--no-warn-stubs'.
-ifneq ("$(filter il% java% erlang%,$(GRADE))","")
+ifneq ("$(filter il% csharp% java% erlang%,$(GRADE))","")
 MCFLAGS += --allow-stubs --no-warn-stubs
 endif
 
@@ -246,7 +246,7 @@ realclean_local:
 .PHONY: install
 install: install_library
 
-ifneq ("$(filter il% erlang%,$(GRADE))","")
+ifneq ("$(filter il% csharp% erlang%,$(GRADE))","")
 
 # there is no ssdb in the .NET or Erlang backends
 
diff --git a/tests/debugger/Mmakefile b/tests/debugger/Mmakefile
index baa4c31..58040ee 100644
--- a/tests/debugger/Mmakefile
+++ b/tests/debugger/Mmakefile
@@ -176,7 +176,7 @@ ALL_NONRETRY_PROGS = $(NONRETRY_PROGS) $(SENSITIVE_PROGS) \
 			$(SHALLOW_PROGS) $(DEBUG_GRADE_PROGS) $(ENUM_PROGS) \
 			$(TERM_SIZE_PROGS) $(MMOS_PROGS)
 
-# Debugging doesn't yet don't work in MLDS grades (hl*, il*, and java),
+# Debugging doesn't yet don't work in MLDS grades (hl*, il*, csharp, java),
 # or the Erlang grade,
 # and the retry command doesn't and will not work in deep profiling
 # grades (profdeep).
@@ -201,7 +201,7 @@ else
     DEBUGGER_PROGS=$(DEBUGGER_PROGS0)
 endif
 
-ifneq "$(filter hl% java% il% erlang%,$(GRADE))" ""
+ifneq "$(filter hl% java% csharp% il% erlang%,$(GRADE))" ""
     PROGS=
 else
     ifneq "$(findstring asm_,$(GRADE))" ""
diff --git a/tests/debugger/declarative/Mmakefile b/tests/debugger/declarative/Mmakefile
index af18c21..d6ccc14 100644
--- a/tests/debugger/declarative/Mmakefile
+++ b/tests/debugger/declarative/Mmakefile
@@ -136,13 +136,13 @@ else
     endif
 endif
 
-# Debugging does not work in MLDS (hl*, il*, and java*) grades
+# Debugging does not work in MLDS (hl*, il*, csharp*, java*) grades
 # or Erlang grades or deep profiling (profdeep) grades.
 # Base grades `jump' and `fast' cannot be used with
 # stack layouts (which are required for tracing).
 # Also, declarative debugging only works in `.gc' grades.
 
-ifeq "$(filter hl% il% java% erlang%,$(GRADE))$(findstring profdeep,$(GRADE))" ""
+ifeq "$(filter hl% il% csharp% java% erlang%,$(GRADE))$(findstring profdeep,$(GRADE))" ""
     ifneq "$(findstring .gc,$(GRADE))" ""
        ifneq "$(findstring asm_,$(GRADE))" ""
            PROGS=$(PROGS_2)
diff --git a/tests/general/structure_reuse/Mmakefile b/tests/general/structure_reuse/Mmakefile
index eadee09..9ec83c0 100644
--- a/tests/general/structure_reuse/Mmakefile
+++ b/tests/general/structure_reuse/Mmakefile
@@ -9,8 +9,8 @@ STRUCTURE_REUSE_PROGS=		\
 	internal_alias		\
 	interpret
 
-# We currently don't do any testing in Java or Erlang grades on this directory.
-ifneq "$(filter java% erlang%,$(GRADE))" ""
+# We currently don't do any testing in some grades on this directory.
+ifneq "$(filter java% csharp% erlang%,$(GRADE))" ""
 	PROGS=
 else
 	PROGS=$(STRUCTURE_REUSE_PROGS)
diff --git a/tests/hard_coded/Mmakefile b/tests/hard_coded/Mmakefile
index 167222e..055214e 100644
--- a/tests/hard_coded/Mmakefile
+++ b/tests/hard_coded/Mmakefile
@@ -623,7 +623,7 @@ endif
 
 # string_hash tests features of the Mercury C runtime.
 # It requires too much memory to be used in non-GC grades.
-ifeq "$(filter il% java%,$(GRADE))$(findstring gc,$(GRADE))" "gc"
+ifeq "$(filter il% csharp% java%,$(GRADE))$(findstring gc,$(GRADE))" "gc"
 	C_AND_GC_ONLY_PROGS =string_hash
 else
 	C_AND_GC_ONLY_PROGS =
diff --git a/tests/hard_coded/foreign_enum_dummy.m b/tests/hard_coded/foreign_enum_dummy.m
index 7e50f8c..261a13e 100644
--- a/tests/hard_coded/foreign_enum_dummy.m
+++ b/tests/hard_coded/foreign_enum_dummy.m
@@ -32,7 +32,7 @@ main(!IO) :-
 	test(FOO::in),
 	[will_not_call_mercury, promise_pure],
 "
-	if (FOO == 561) {
+	if ((int) FOO == 561) {
 		SUCCESS_INDICATOR = true;
 	} else {
 		SUCCESS_INDICATOR = false;
diff --git a/tests/hard_coded/sub-modules/Mmakefile b/tests/hard_coded/sub-modules/Mmakefile
index 293b35d..c751d70 100644
--- a/tests/hard_coded/sub-modules/Mmakefile
+++ b/tests/hard_coded/sub-modules/Mmakefile
@@ -33,7 +33,7 @@ SUB_MODULE_PROGS= \
 	use_submodule
 
 # Solver types only work in C grades
-ifeq "$(filter il% java% erlang%,$(GRADE))" ""
+ifeq "$(filter il% csharp% java% erlang%,$(GRADE))" ""
 	SOLVER_PROGS = \
 		ts
 else
diff --git a/tests/hard_coded/sub-modules/non_word_mutable.m b/tests/hard_coded/sub-modules/non_word_mutable.m
index 76322c9..afa52ac 100644
--- a/tests/hard_coded/sub-modules/non_word_mutable.m
+++ b/tests/hard_coded/sub-modules/non_word_mutable.m
@@ -22,6 +22,7 @@
 
 :- type coord.
 :- pragma foreign_type(c, coord, "coord *").
+:- pragma foreign_type("C#", coord, "coord").
 :- pragma foreign_type("Java", coord, "coord").
 :- pragma foreign_type("Erlang", coord, "").
 
@@ -31,6 +32,12 @@ typedef struct {
 } coord;
 ").
 
+:- pragma foreign_decl("C#", "
+public class coord {
+    public int x, y;
+}
+").
+
 :- pragma foreign_decl("Java", "
 class coord {
     public int x, y;
@@ -64,6 +71,29 @@ class coord {
     Y = C->y;
 ").
 
+:- pragma foreign_proc("C#",
+    new_coord(X::in, Y::in) = (C::out),
+    [will_not_call_mercury, promise_pure],
+"
+    C = new coord();
+    C.x = X;
+    C.y = Y;
+").
+
+:- pragma foreign_proc("C#",
+    x(C::in) = (X::out),
+    [will_not_call_mercury, promise_pure],
+"
+    X = C.x;
+").
+
+:- pragma foreign_proc("C#",
+    y(C::in) = (Y::out),
+    [will_not_call_mercury, promise_pure],
+"
+    Y = C.y;
+").
+
 :- pragma foreign_proc("Java",
     new_coord(X::in, Y::in) = (C::out),
     [will_not_call_mercury, promise_pure],
diff --git a/tests/hard_coded/sub-modules/sm_exp_bug.m b/tests/hard_coded/sub-modules/sm_exp_bug.m
index a6f86bd..64f0e60 100644
--- a/tests/hard_coded/sub-modules/sm_exp_bug.m
+++ b/tests/hard_coded/sub-modules/sm_exp_bug.m
@@ -28,6 +28,14 @@ main(!IO) :-
 	IO = IO0;
 ").
 
+:- pragma foreign_proc("C#",
+	call_foreign(IO0::di, IO::uo),
+	[may_call_mercury, promise_pure],
+"
+	WRITE_HELLO();
+	IO = IO0;
+").
+
 :- pragma foreign_proc("Java",
 	call_foreign(IO0::di, IO::uo),
 	[may_call_mercury, promise_pure],
@@ -44,6 +52,7 @@ main(!IO) :-
 ").
 
 :- pragma foreign_export("C", write_hello(di, uo), "WRITE_HELLO").
+:- pragma foreign_export("C#", write_hello(di, uo), "WRITE_HELLO").
 :- pragma foreign_export("Java", write_hello(di, uo), "WRITE_HELLO").
 :- pragma foreign_export("Erlang", write_hello(di, uo), "WRITE_HELLO").
 :- pred write_hello(io::di, io::uo) is det.
diff --git a/tests/invalid/Mmakefile b/tests/invalid/Mmakefile
index 8b7b77b..d319108 100644
--- a/tests/invalid/Mmakefile
+++ b/tests/invalid/Mmakefile
@@ -300,14 +300,14 @@ NON_PROFDEEP_MODULES = \
 
 # These tests test things which only work for back-ends which support
 # the C interface.
-ifneq "$(filter java% il% erlang%,$(GRADE))" ""
+ifneq "$(filter java% csharp% il% erlang%,$(GRADE))" ""
 	C_INTERFACE_PROGS=
 else
 	C_INTERFACE_PROGS=$(C_INTERFACE_MODULES)
 endif
 
 # The java and il grades compile with num_tag_bits = 0.
-ifneq "$(filter java% il% erlang%,$(GRADE))" ""
+ifneq "$(filter java% csharp% il% erlang%,$(GRADE))" ""
 	RESERVE_TAG_PROGS =
 else
 	RESERVE_TAG_PROGS = $(RESERVE_TAG_MODULES)
@@ -325,14 +325,7 @@ else
 	NON_PROFDEEP_PROGS = 
 endif
 
-# The java back-end ignores pragma type_spec, so it doesn't diagnose errors
-# in them. (XXX Perhaps the code to ignore them in make_hlds.m should be moved
-# to after the error-checking?)
-ifneq "$(filter java%,$(GRADE))" ""
-	TYPE_SPEC_PROGS =
-else
-	TYPE_SPEC_PROGS = $(TYPE_SPEC_MODULES)
-endif
+TYPE_SPEC_PROGS = $(TYPE_SPEC_MODULES)
 
 SINGLEMODULE_PROGS = $(SINGLEMODULE) \
 	$(C_INTERFACE_PROGS) \
diff --git a/tests/mmc_make/Mmakefile b/tests/mmc_make/Mmakefile
index 5f91a13..7fe6bc6 100644
--- a/tests/mmc_make/Mmakefile
+++ b/tests/mmc_make/Mmakefile
@@ -36,7 +36,7 @@ linkage_test.log: install_libs_linkage_test2
 rebuild.runtest:
 	$(MCM) --rebuild rebuild
 	$(MCM) --rebuild --verbose-make rebuild > rebuild.err2 2>&1
-	grep '^Making rebuild$(EXT_FOR_EXE)$$' rebuild.err2
+	grep '^Making rebuild\($$\|\.\)' rebuild.err2
 
 # The compiler used to fail when invoked as `mmc --make build_object.o'.
 build_object.runtest: build_object.o
diff --git a/tests/mmc_make/complex_test.exp2 b/tests/mmc_make/complex_test.exp2
new file mode 100644
index 0000000..a6b9cbf
--- /dev/null
+++ b/tests/mmc_make/complex_test.exp2
@@ -0,0 +1,54 @@
+tests of (complex op complex)
+X = cmplx(3.0, 4.0)
+X + X = cmplx(6.0, 8.0)
+X - X = cmplx(0.0, 0.0)
+X * X = cmplx(-7.0, 24.0)
+X / X = cmplx(1.0, 0.0)
+Y = cmplx(-5.0, 6.0)
+Y + Y = cmplx(-10.0, 12.0)
+Y - Y = cmplx(0.0, 0.0)
+Y * Y = cmplx(-11.0, -60.0)
+Y / Y = cmplx(1.0, 0.0)
+X + Y = cmplx(-2.0, 10.0)
+X - Y = cmplx(8.0, -2.0)
+X * Y = cmplx(-39.0, -2.0)
+X / Y = cmplx(0.14754098360655737, -0.62295081967213117)
+
+tests of (imag op imag)
+Z = im(4.0)
+Z + Z = im(8.0)
+Z - Z = im(0.0)
+Z * Z = -16.0
+Z / Z = 1.0
+
+tests of (float op imag)
+5.0 + Z = cmplx(5.0, 4.0)
+5.0 - Z = cmplx(5.0, -4.0)
+5.0 * Z = im(20.0)
+5.0 / Z = im(-1.25)
+
+tests of (imag op float)
+Z + 5.0 = cmplx(5.0, 4.0)
+Z - 5.0 = cmplx(-5.0, 4.0)
+Z * 5.0 = im(20.0)
+Z / 5.0 = im(0.8)
+
+tests of (complex op imag)
+X + Z = cmplx(3.0, 8.0)
+X - Z = cmplx(3.0, 0.0)
+X * Z = cmplx(-16.0, 12.0)
+X / Z = cmplx(1.0, -0.75)
+Y + Z = cmplx(-5.0, 10.0)
+Y - Z = cmplx(-5.0, 2.0)
+Y * Z = cmplx(-24.0, -20.0)
+Y / Z = cmplx(1.5, 1.25)
+
+tests of (imag op complex)
+Z + X = cmplx(3.0, 8.0)
+Z - X = cmplx(-3.0, 0.0)
+Z * X = cmplx(-16.0, 12.0)
+Z / X = cmplx(0.64, 0.48)
+Z + Y = cmplx(-5.0, 10.0)
+Z - Y = cmplx(5.0, -2.0)
+Z * Y = cmplx(-24.0, -20.0)
+Z / Y = cmplx(0.39344262295081966, -0.32786885245901637)
diff --git a/tests/par_conj/Mmakefile b/tests/par_conj/Mmakefile
index 3b74d6c..b07256a 100644
--- a/tests/par_conj/Mmakefile
+++ b/tests/par_conj/Mmakefile
@@ -67,7 +67,7 @@ LLDS_PROGS = \
 	par_ddeath \
 	par_ddeath_2
 
-ifeq "$(filter hl% java% il% erlang%,$(GRADE))" ""
+ifeq "$(filter hl% java% csharp% il% erlang%,$(GRADE))" ""
 	PROGS0 = $(LLDS_PROGS)
 else
 	PROGS0 =
@@ -133,7 +133,7 @@ $(OBJ_PROGS:%=%.runtest): %.runtest: %.$(TARGET_OBJ_EXT) ;
 
 # Exercise multiple Mercury engines in lowlevel grades.
 ENGINES :=
-ifeq "$(filter hl% java% il% erlang%,$(GRADE))" ""
+ifeq "$(filter hl% java% csharp% il% erlang%,$(GRADE))" ""
 	ENGINES := MERCURY_OPTIONS=-P2
 endif
 
@@ -141,7 +141,7 @@ endif
 	{ [ -f $*.inp ] && cat $*.inp; } | $(ENGINES) ./$< > $@ 2>&1 || \
 		{ grep . $@ /dev/null; exit 1; }
 
-ifeq "$(filter hl% java% il% erlang%,$(GRADE))" ""
+ifeq "$(filter hl% java% csharp% il% erlang%,$(GRADE))" ""
 
 # Run threads_hang with multiple OS threads in lowlevel parallel grades.
 # Repeat the test a few times in increase the chances of getting a deadlock.
diff --git a/tests/run_one_test b/tests/run_one_test
index b8b34ef..51b28ef 100755
--- a/tests/run_one_test
+++ b/tests/run_one_test
@@ -39,11 +39,16 @@ else
     if test -f $test_full.failed
     then
         rm -f $test_full.failed
+        case $GRADE in
+            csharp*|java*|erlang*) ;;
+            *)
         if test -f $test
         then
             rm -f $test.gz $test.exe.gz
             gzip $test || gzip $test.exe
         fi
+                ;;
+        esac
         echo FAILED TEST $this_dir/$test_full $params_msg \
             | tee -a $test_full.log
         echo $test_full >> FAILED_TESTS
diff --git a/tests/stm/Mmakefile b/tests/stm/Mmakefile
index ff0b0b3..5fe96a0 100644
--- a/tests/stm/Mmakefile
+++ b/tests/stm/Mmakefile
@@ -40,7 +40,7 @@ MULTI_PROGS =			\
 #
 LLDS_PROGS = 
 
-ifeq "$(filter hl% java% il% erlang%,$(GRADE))" ""
+ifeq "$(filter hl% java% csharp% il% erlang%,$(GRADE))" ""
 	PROGS0 = $(LLDS_PROGS)
 else
 	PROGS0 =
@@ -119,7 +119,7 @@ endif
 
 # Exercise multiple Mercury engines in lowlevel grades.
 ENGINES :=
-ifeq "$(filter hl% java% il% erlang%,$(GRADE))" ""
+ifeq "$(filter hl% java% csharp% il% erlang%,$(GRADE))" ""
 	ENGINES := MERCURY_OPTIONS=-P8
 endif
 
diff --git a/tests/valid/Mmakefile b/tests/valid/Mmakefile
index 3cb9450..67c474c 100644
--- a/tests/valid/Mmakefile
+++ b/tests/valid/Mmakefile
@@ -349,10 +349,10 @@ CONSTRAINT_TYPECHECK_PROGS = \
 ifeq "$(findstring hl,$(GRADE))$(findstring .agc,$(GRADE))" "hl"
 	PROGS0 = $(TYPECLASS_PROGS) $(OTHER_PROGS)
 else
-	# The agc.* tests don't work in the il, java or erlang grades.
+	# The agc.* tests don't work in the il, java, csharp or erlang grades.
 	# The agc.* tests also don't work in minimal model grades,
 	# because the collector doesn't scan the copied areas of the stacks.
-    	ifneq "$(filter java% il% erlang%,$(GRADE))$(findstring mm,$(GRADE))" ""
+	ifneq "$(filter java% csharp% il% erlang%,$(GRADE))$(findstring mm,$(GRADE))" ""
 		PROGS0 = $(TYPECLASS_PROGS) $(OTHER_PROGS)
 	else
 		PROGS0 = $(AGC_PROGS) $(TYPECLASS_PROGS) $(OTHER_PROGS)
@@ -382,13 +382,13 @@ else
 	PROGS2=$(PROGS1) $(TRAIL_PROGS)
 endif
 
-ifneq "$(filter java% il% erlang%,$(GRADE))$(findstring profdeep,$(GRADE))" ""
+ifneq "$(filter java% csharp% il% erlang%,$(GRADE))$(findstring profdeep,$(GRADE))" ""
 	PROGS3 = $(PROGS2)
 else
 	PROGS3 = $(PROGS2) $(TABLE_PROGS)
 endif
 
-ifeq "$(filter hl% java% il% erlang%,$(GRADE))" ""
+ifeq "$(filter hl% java% csharp% il% erlang%,$(GRADE))" ""
 	PROGS4 = $(PROGS3) $(C_INTERFACE_PROGS) $(SOLVER_PROGS) \
 		$(DEEP_PROF_CAPABLE_PROGS) $(LLDS_PROGS)
 else
@@ -407,7 +407,7 @@ else
 	PROGS6 = $(PROGS5)
 endif
 
-ifeq "$(filter java% il% erlang%,$(GRADE))" ""
+ifeq "$(filter java% csharp% il% erlang%,$(GRADE))" ""
 	OBJ_PROGS = $(PROGS6) $(RESERVE_TAG_PROGS)
 else
 	OBJ_PROGS = $(PROGS6)
@@ -436,6 +436,11 @@ ifeq ($(findstring il,$(GRADE)),il)
 	TARGET_OBJ_EXT=dll
 	TARGET_OBJ_SUBDIR=$(DLLS_SUBDIR)
 else
+ifeq ($(findstring csharp,$(GRADE)),csharp)
+	# XXX we should produce DLLs but currently that invokes the IL backend
+	TARGET_OBJ_EXT=cs
+	TARGET_OBJ_SUBDIR=$(DLLS_SUBDIR)
+else
 ifeq ($(findstring erlang,$(GRADE)),erlang)
 	TARGET_OBJ_EXT=beam
 	# Erlang backend currently requires `mmc --make'.
@@ -450,6 +455,7 @@ else
 endif
 endif
 endif
+endif
 OBJS =	$(OBJ_PROGS:%=$(TARGET_OBJ_SUBDIR)%.$(TARGET_OBJ_EXT)) \
 		$(IL_PROGS:%=$(ILS_SUBDIR)%.il)
 
diff --git a/trace/Mmakefile b/trace/Mmakefile
index 5344c02..3138bba 100644
--- a/trace/Mmakefile
+++ b/trace/Mmakefile
@@ -221,7 +221,7 @@ mercury_event_spec.$(EXT_FOR_PIC_OBJECTS): $(GEN_EVENTSPEC_HDRS)
 
 .PHONY: all
 .PHONY: trace
-ifneq ("$(filter il% java% erlang%,$(GRADE))","")        
+ifneq ("$(filter il% csharp% java% erlang%,$(GRADE))","")
 # there is no tracing in the .NET, Java, Erlang backends
 
 all:
@@ -320,7 +320,7 @@ tags_file_exists:
 .PHONY: install
 install: install_headers install_lib
 
-ifneq ("$(filter il% java% erlang%,$(GRADE))","")        
+ifneq ("$(filter il% csharp% java% erlang%,$(GRADE))","")
 
 # there is no tracing in the .NET, Java, Erlang backends

--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to:       mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions:          mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------



More information about the reviews mailing list