Despite using --use-mmc-make when we build Mercury in the C# or Java grades, we
still need to run the depend target in order ensure that its various other
actions take place (e.g. copying files from the mdbcomp directory to the slice
directory). Not explicitly invoking the depend target, can result in timing
related problems, especially when using parallel builds. Modify the
documentation for building C#/Java compilers to include an explicit depend
step.
README.CSharp.md:
README.Java.md:
As above.
7.6 KiB
Mercury C# Backend
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.
Contents
- Prerequisites
- Installing the
csharpgrade - Compiling programs with the
csharpgrade - Running
csharpgrade programs with Mono - Running
csharpgrade programs on Windows with .NET - Limitations
- Library support
- Interfacing with C#
- Mercury-level debugging
- Building the Mercury compiler in the
csharpgrade
Prerequisites
In order to use Mercury's C# backend you will need either:
- Microsoft .NET 4.5 or above.
- Mono 4.0 or above.
Installing the csharp grade
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.
Compiling programs with the csharp grade
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.
Running csharp grade programs with Mono
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
Running csharp grade programs on Windows with .NET
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
Limitations
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.
Library support
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_binarydoes not work with the way Mercury file streams are implemented for the C# backend. -
benchmarking.report_stats/0
benchmarking.report_full_memory_stats/0Memory 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/5Due to some limitations in RTTI support, dynamic type checking is missing for these predicates. They should be used with care.
-
math.fma/3This 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.)
Interfacing with C#
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#.
Mercury-level debugging
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 in the csharp grade
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
PATHand a clean version of the Mercury source tree. -
Run
prepare.shandconfigureas normal. -
Add the line:
GRADE=csharpto a file named
Mmake.paramsat the top-level of the source tree. -
Build the dependencies using the following command:
$ mmake --use-mmc-make depend GRADE=csharp -
Compile using the following command:
$ mmake --use-mmc-make GRADE=csharp -
To install the C# version of the compiler, do:
$ mmake --use-mmc-make install 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 variable GRADE in the
invocations of mmake is currently required to avoid some variable definition
ordering problems in Mmake.workspace.