The Mercury compiler has a backend that generates C# source code, that can be compiled into bytecode suitable for running using the .NET or Mono runtime systems. The backend is mostly complete, but some parts of the Mercury standard library are not yet implemented.
The C# backend requires C# 5.0 or higher -- older versions of C# are not supported.
- Prerequisites
- Installing the
csharp
grade - Compiling programs with the
csharp
grade - Running
csharp
grade programs with Mono - Running
csharp
grade programs on Windows with .NET - Limitations
- Library support
- Interfacing with C#
- Mercury-level debugging
- Building the Mercury compiler in the
csharp
grade
In order to use Mercury's C# backend you will need either:
- Microsoft .NET 4.5 or above.
- Mono 4.0 or above.
The Mercury compiler uses the grade csharp
to target C# source code that
is then compiled by a C# compiler.
Mercury's autoconfiguration script will cause the csharp
grade to be installed
if it finds a suitable C# compiler (e.g. csc
) and .NET runtime in your PATH
.
You can check if your Mercury installation has been configured to include the
csharp
grade by looking if csharp
is included in the output of the Mercury
compiler's --output-stdlib-grades
option.
Once you have a Mercury installation that includes the csharp
grade, you
can build programs such as hello.m
or calculator.m
in the samples
directory.
$ cd samples
$ mmc ---grade csharp --make hello
When building programs with the csharp
grade you must use mmc --make
; using
mmake
to build programs using the csharp
grade is not supported.
For the example in the previous section on a Unix (or more generally,
non-Windows) system using Mono, the Mercury compiler will generate a process
assembly, e.g. hello.exe
, and a wrapper shell script named hello
.
The wrapper shell script will set the MONO_PATH
environment variable
to point to the location of the Mercury standard library assemblies.
It will then invoke then CLI execution environment on the process assembly.
You can run the program using wrapper shell script, for example:
$ ./hello
On Windows, the Mercury compiler will only generate a process assembly, e.g.
hello.exe
. On Windows there is no need to generate a wrapper shell script.
With .NET, the library assemblies (.dlls) for the Mercury standard libraries must either (1) reside in (or under) the same directory as the process assembly (.exe) or (2) be entered into the global assembly cache (GAC). If neither of these things is done then execution will abort with a message that begins:
Unhandled Exception: System.IO.FileNotFoundException: Could not load file
or assembly 'mer_std', Version=...
For (1), you will need to copy the library assemblies from the Mercury library installation directory into the same directory as the process assembly. The files for the Mercury library assemblies are located in
<prefix>\lib\mercury\lib\csharp
where <prefix>
is the location of the Mercury installation.
Copy all of the .dll files in the above directory into that of the process
assembly.
To enter assemblies into the GAC, run the following command for each assembly.
gacutil /i mer_std.dll
Assemblies can be removed from the GAC by doing, for example
gacutil /u mer_std.dll
The following features of the Mercury implementation are not (currently) supported by the C# backend:
- Mercury-level debugging (however, see further down).
- Mercury-level profiling.
- Trailing.
- Tabling.
- Backjumping.
The Mercury standard library has not been fully ported to C# yet. The use of unimplemented procedures will result in a run-time error, with a stack trace and a message like:
Sorry, not implemented: foreign code for this function
If you find missing functionality, you can interface to C# using Mercury's foreign language interface.
The following individual Mercury standard library procedures are either not supported or not fully implemented:
-
io.read_binary/{3,4}
io.write_binary/{3,4}
The current implementation of
read_binary
does not work with the way Mercury file streams are implemented for the C# backend. -
benchmarking.report_stats/0
benchmarking.report_full_memory_stats/0
Memory usage statistics are not yet available, and cpu time is not the same as in the C backends, as per
time.m
. -
store.arg_ref/5
store.new_arg_ref/5
Due to some limitations in RTTI support, dynamic type checking is missing for these predicates. They should be used with care.
-
math.fma/3
This function is not available because it is not supported by C# 5.0. (It will be supported once the minimum version of C# required by Mercury increases.)
You can call C# code directly from Mercury using the foreign language interface. For example:
:- pred to_string(T::in, string::out) is det.
:- pragma foreign_proc("C#",
to_string(T::in, Str::out),
[promise_pure, will_not_call_mercury],
"
Str = T.ToString();
").
The implementation will include this C# code in the module's .cs file, and you
can then call the predicate to_string/2
exactly the same as if it were
implemented using pure Mercury code.
For more information about the foreign language interface, see the Mercury Language Reference Manual. Additionally, the samples/csharp_interface directory in the Mercury distribution contains examples of how to use the foreign language interface with C#.
The only Mercury-level debugger available for the C# backend is the experimental source-to-source debugger; see README.ssdebug.md for details.
Building the Mercury compiler and other related tools in the C# grade is NOT generally supported and should be considered experimental. In particular, a Mercury compiler built in the C# grade may be slower than normal and some features may not be available.
However, if you want to give it a try, the required steps are:
-
Ensure that you have an existing working Mercury compiler in your
PATH
and a clean version of the Mercury source tree. -
Run
prepare.sh
andconfigure
as normal. -
Add the line:
GRADE=csharp
to a file named
Mmake.params
at the top-level of the source tree. -
Begin the build process using the following command:
$ mmake --use-mmc-make GRADE=csharp
The C# version of the compiler MUST be built using
mmake
's--use-mmc-make
option; the build will not work otherwise. Setting the variableGRADE
in the invocation of mmake is currently necessary in order to avoid some variable definition ordering problems inMmake.workspace
. -
To install the C# version of the compiler, do:
$ mmake --use-mmc-make install GRADE=csharp