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 `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 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](samples) directory. ``` 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 the CLI execution environment on the process assembly. You can run the program using the 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 ``` \lib\mercury\lib\csharp ``` where `` 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: 1. `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. 2. `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`. 3. `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. 4. `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.) 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](https://www.mercurylang.org/information/documentation.html). Additionally, the [samples/csharp_interface](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](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: 1. Ensure that you have an existing working Mercury compiler in your `PATH` and a clean version of the Mercury source tree. 2. Run `prepare.sh` and `configure` as normal. 3. Add the line: GRADE=csharp to a file named `Mmake.params` at the top-level of the source tree. 4. Build the dependencies using the following command: mmake --use-mmc-make depend GRADE=csharp 5. Compile using the following command: mmake --use-mmc-make GRADE=csharp 6. 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`. -----------------------------------------------------------------------------