Using Nim with C# .NET

Nim is a statically typed programming language that compiles to C featuring a tracing garbage collector, zero overhead iterators, and powerful compile time evaluation of user defined functions. It features an indentation based syntax with a powerful AST based macro system. Thanks to the fact that Nim currently compiles to C, it can run on many platforms and architectures via a native binary. Cross compilation (for example, compiling Windows executables on Linux) is also possible with the correct compiler configuration.

C# is a programming language from Microsoft that is developed as part of the .NET framework. It is also strongly typed and offers multiple programming paradigms, though it is primarily object orientated. Until very recently, the .NET framework was a proprietary framework available only for Windows. With the .NET Core initiative though, Microsoft have started opening .NET onto other platforms including Linux and the Mac. However, many third party libraries (and several first party ones) do not work with .NET Core due to changes that Microsoft made to program structure and configuration.

In this post, I will be exploring how easy it is to use libraries written in Nim within your C# projects. Thanks to the fact that Nim compiles to C, it’s incredibly easy to build a DLL that can be accessed from within .NET. To begin, we’ll write an extremely simple Nim library with a single function that adds two integers and returns the result.

Writing a simple Nim library

The first step is to create a folder to keep your library in. For the purpose of this post, we will be using the directory ~/NimAdder. The first thing to do is create a project file: ~/NimAdder/adder.nim:

proc addTwoInts*(a, b: cint): cint {.cdecl, exportc, dynlib.} =
  ## addTwoInts adds two integers together.
  result = a + b

Some key things to note here are:

You can compile this code using the below command from the ~/NimAdder directory:

$ nim c -d:release --header --noMain --app:lib adder.nim

Note the flags we used here:

This will output some information (as seen below) about the compilation process and you should end up with a file named adder.dll (on Windows, or .dylib on Mac or .so on Linux and other systems).

Hint: used config file '/usr/local/Cellar/nim/0.14.2/nim/config/nim.cfg' [Conf]
Hint: system [Processing]
Hint: adder [Processing]
CC: adder
CC: stdlib_system
Hint:  [Link]
Hint: operation successful (10299 lines compiled; 1.107 sec total; 15.504MiB; Debug Build) [SuccessX]

Creating a C# project to use the created DLL

Now that we’ve built a library, we need to create a C# project. Start Visual Studio and create a new project - the type doesn’t matter, but I will use a Console Application as an example.

The first thing to do is to set the platform target for your project from the project settings. This is located under the Build tab and has to be set for all build configurations (Build and Release by default). By default the target is Any CPU, you need to change it to match the architecture your Nim library was built for. If you built it on a 64 bit system, you must set the .NET project to target x64 for example.

Now add the DLL you built earlier to your project as an existing item (Project > Add Existing Item > Browse to adder.dll) and set it to copy to the output directory if newer (Right click on adder.dll in the Solution Explorer and select Properties, change Copy to Output Directory to Copy if newer). As .NET loads DLLS dynamically, this ensures that the DLL will be copied alongside your executable when your project is built.

Now to reference the function that we exported in the Nim code. We do this using the DllImport attribute from System.Runtime.InteropServices:

namespace NimAdder
{
  class Program
  {
    [DllImport("adder.dll")]
    public static extern void NimMain();

    [DllImport("adder.dll")]
    public static extern int addTwoInts(int a, int b);

    static void Main(string[] args)
    {
    }
  }
}

You can now simply use addTwoInts like any other function:

static void Main(string[] args)
{
  var res = addTwoInts(40, 2);

  Console.WriteLine("The meaning to life, the universe and everything is: {0}", res);
  Console.ReadKey();
}

Closing

As you can see, accessing simple functions written in Nim from .NET is pretty easy. This approach should also allow you to call Nim functions from any other .NET language (such as Visual Basic .NET and F#).