Using Nim with C# .NETFri, Sep 30, 2016
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:
Some key things to note here are:
prockeyword - this is how you define a function in Nim.
*symbol after the function name - this is how you declare a function or type to be public within a Nim module.
- The arguments and return types are all
cint- this means that the arguments and return value are all C style 32 bit (usually) integer values.
pragmas included after the function return definition - these are enclosed within curly brackets with a dot (
.}) after the function definition and are comma separated. The pragmas used here are
- The implicit
resultvariable - you can use the
returnstatement to return a value from a function, but using the
resultvariable is preferred unless you need to return early from some function.
You can compile this code using the below command from the
$ nim c -d:release --header --noMain --app:lib adder.nim
Note the flags we used here:
-c- this tells the compiler to compile the file it is passed.
-d:release- this results in an optimised release build with several runtime checks turned off and optimisations turned on.
--header- this results in a C header file being output to the
./nimcachefolder, which can be used to see the C functions that are created.
--app:lib- this tells the compiler to build the project as a DLL.
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 (
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 (
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
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
You can now simply use
addTwoInts like any other function:
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#).