How to Write Native Plugins for Unity

Unity has the ability to import pieces of code written (and compiled) in other languages; they are called Native Plugins, and this tutorial will teach you how to build them.

Source codes:

Managed and unmanaged plugins in Unity

Connecting different piece of code is not something which Unity invented. If you are a Windows user, is very likely you might have heard of DLLs, an acronym which means Dynamic Link Libraries. Similarly to standalone applications, they are compiled softwares. Unlike them, however, they cannot be executed directly since they are designed specifically to be used by other applications.

Unity supports two types of plugins: managed and unmanaged. The former are piece of code written in C# and compiled into a bytecode language called Common Intermediate Language (CIL). Managed plugins are as powerful as C# scripts, with the advantage of having their source codes compiled. Unmanaged (or native) plugins, instead, are piece of software written in other languages, typically C++. There are no constraints on what they can do, and since they are compiled in machine code they tend to be much faster than traditional scripts.

Step 1: Creating a C++ project

For this tutorial I will use Visual Studio 2015; as long as you know how to compile C++ code, you can chose whichever IDE you want. The first step to create an unmanaged C++ library is to create a project for it. Open Visual Studio, go to File | New Project and select Visual C++ | Win32 Console Application.

01

After choosing a name for the project (TestDLL in this example), make sure to select DLL under Application type, and Empty project under Additional options.

02

The Visual C++ solution is now ready and we can start writing our code.

Step 2: Writing the library

03

C++ code is generally split in two files. The functions definitions (called header) and their actual implementation (called body). While the body is written into .cpp files inside the folder Resource files, headers goes into Header Files and have extension .h. For this solution we will create a header and a body; the latter will contain all the functions we want to store in our DLL. You can create a file by right clicking in the relative folder, then selecting Add | New Item.

The body: TestDLLSort.cpp

Let’s start with the code that sorts our array.

#include "TestDLLSort.h"
#include <algorithm>

extern "C" {
	void TestSort(int a[], int length) {
		std::sort(a, a+length);
	}
}

Lines 5-7 uses the std:sort function from the algorithm library to sort the array. If you are familiar with C++11, this should be nothing new. The only addition is the extern "C" block, which is necessary to export the references to TestSort into the DLL.

The header: TestDLLSort.h

The definition of the body must be complete with a header. It has to contain the prototype of TestSort, which is the signature of the function.

#define TESTDLLSORT_API __declspec(dllexport) 

extern "C" {
	TESTDLLSORT_API void TestSort(int a[], int length);
}

The remaining code is necessary to create the DLL. The name TESTDLLSORT_API is arbitrary and is used to mark all the functions exported. In more sophisticated pieces of software, TESTDLLSORT_API should be binded to __declspec(dllimport) depending on the situation. But in this toy example, this is not necessary.

📰 Ad Break

Step 3: Compiling

The final step to complete in Visual Studio for our DLL is now to compile it. Make sure that your target is set to Release for the right platform (32bit or 64bit). Then, select Build | Build Solution.

04

On the bottom of the screen, you’ll see an output log on the console. It should look like this:

1>------ Rebuild All started: Project: TestDLL, Configuration: Release x64 ------
1>  TestDLLSort.cpp
1>     Creating library C:\Users\Alan Zucconi\Documents\Visual Studio 2015\Projects\TestDLL\x64\Release\TestDLL.lib and object C:\Users\Alan Zucconi\Documents\Visual Studio 2015\Projects\TestDLL\x64\Release\TestDLL.exp
1>  Generating code
1>  All 30 functions were compiled because no usable IPDB/IOBJ from previous compilation was found.
1>  Finished generating code
1>  TestDLL.vcxproj -> C:\Users\Alan Zucconi\Documents\Visual Studio 2015\Projects\TestDLL\x64\Release\TestDLL.dll
========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========

If you are experiencing a warning such as warning C4273: inconsistent dll linkage, there might be ambiguity between the usage of __declspec(dllimport) and __declspec(dllexport). If you are just trying to create a native plugin for Unity, stick with the latter.

Step 4: Importing in Unity

05

Following the previous compilation log, explore the project folders to find the compiled DLL. In this case it it placed in the folder x64\Release. This is the only file you need. The first step to make it work into Unity is to copy it with a folder called Plugins.

Native plugins are typically bounded to a specific OS or platform. You can use the Inspector to make sure each DLL is included in the right build.

Step 5: Using in Unity

Once imported, using a DLL is relatively simple. The first step is to define its entry point, which is done using the DLLImport annotation. You need to specify the name of the DLL and the name of the function. It is then given an alias, which can be invoked like any other function.

using UnityEngine;
using System.Runtime.InteropServices;

public class TestDLL : MonoBehaviour {
    // The imported function
    [DllImport("TestDLL", EntryPoint = "TestSort")]
    public static extern void TestSort(int [] a, int length);

    public int[] a;

    void Start() {
        TestSort(a, a.Length);
    }
}

The string used in EntryPoint must match with the name used in the C++ library. However, you can call the function in the line below the way you want; this is how C# will call it from now on.

You should notice that Unity cannot check unmanaged DLLs in the editor; you’ll have to run the game to check whether the linkage has been successful or not. This is not the case with managed DLLs, which can be checked statically.

Conclusion

Native plugins are extremely important and can play a vital role in the development of your game. Their most significant advantage is the speed. While C# scripts are translated CIL, Unmanaged DLLs are compiled in machine code. You can try yourself by benchmarking the DLL created in this test. Sorting an array of 1000000 elements takes approximately 480ms with Array.Sort, but only 65 with std::sort. This is seven times faster! If your game has some heavy simulations (such as fluid dynamics or heavy AI stuff) you should consider moving that part of code in a C++ library.

Other resources

  • Native plugins for Mac: a detailed article which covers most of the content here presented, but oriented for Mac developers;
  • Unity and DLLs: a tutorial to create managed (C#) and unmanaged (C++) plugins for Unity;
  • Writing plugins: an official video tutorial from Unity to create your first plugin with Visual Studio.

Comments

21 responses to “How to Write Native Plugins for Unity”

  1. sebastien avatar

    Does unity still use c++ ?
    I heard they replace it by HPC#

  2. Guido Salimbeni avatar
    Guido Salimbeni

    Hello Alan,
    This is great. I have a python code that I would like to turn into a plugin for UNITY. I would really like not to rewrite in C++, and I wonder if you think there is any option to turn it to a dll and then follow your tutorial to run it in Unity? Thank you in advance. Guido

    1. Hey!
      As far as I know, there is no way to turn a Python script into a Unity plugin.
      If you can’t rewrite the entire script in C++, you can probably run the script from a command in C# and wait for its result. This is exceptionally slow and very hard to port, but depending on what you are doing it might work for you. It has been used in ML-Agents, the Unity extension for machine learning. So if you have a look at its source code, you might see how they connect Python with Unity.

  3. Alessandro Cali avatar
    Alessandro Cali

    Hey Alan,

    Great tutorial! I’ve followed along with it, however am constantly receiving a “DllNotFoundException”. I have scoured through StackOverflow and Unity Documentation without any luck. Would you be able to help me?

    Thanks in advance!

    – Alessandro

    1. Thank you!
      It’s very hard to see what wrong without seeing the full exception and what causes it! Are you trying to write your own DLL?

    2. Had the same problem.
      My solution was to use the full path to the dll file.
      The DLL import looks like that:
      “[DllImport(“Assets/Plugins/x64/UnityDLLTest.dll”, EntryPoint = “TestSort”)]”

      Just select the dll within the Unity project and cope the path from the inspector.

  4. Wonrderful, You are doing a great job as programmer. Totally understandable.

  5. Thanks for your wonderful and right to the point tutorial.

    1. Thank you so much! <3

  6. Rosco Pecoltran avatar
    Rosco Pecoltran

    Would be awesome to have something working with https://github.com/mono/CppSharp/ and CMake, so we could cross-compile libraries with toolchains, like in this repo https://github.com/m039/XLIS

    Do you know guys any tools or helpers allowing to generate all the .cs files for DLLImport annotation and create disposable objects ?

  7. Thanks for the tutorial, this is pretty close to what I want to do. The difference is, my dll is compiled from C, not from C++. I have successfully used my dll from C# in Visual Studio, but I fail to use from Unity.
    I have been struggling with step 4, I just can’t find how to import the dll!?

  8. Hi,
    is there a way to edit the dll while Unity is open? I have to restart Unity each time I want to change something in the dll, which is really annying.. 🙁

    1. Hey! I don’t think so.
      If I remember correctly the documentation clearly says that once is loaded, you have to restart Unity to re-load it. T_T
      I doubt that has been fixed.

  9. Hi,
    I’m wondering if anyone has run into a EntryPointNotFoundException: TestSort TestDLL.Start () error in Unity when trying this? From what I can gather, the function name is probably being mangled even though we’re using extern “C” but I’m unsure how to fix it?
    Thanks for any help as it would be great to get this working.
    Cheers, Stu

    1. You could check your dll exports using Dependency Walker.
      EntryPointNotFoundException can also happen if you forward-declare a class used in the exported API, whereupon nothing gets exported!

  10. Mentar avatar

    Thanks for this Alan,
    Was useful to us in making of our prototype 🙂

    1. Ohhh I’m glad it was helpful! 😀

  11. When run the example Unity is frezzed.

  12. […] How to Write Native Plugins for Unity. […]

  13. Alan,

    Great tutorial. Was very helpful in getting me going.

    I used this as a base for building a native C++ plugin for rendering textures. It works beautifully in the editor and standalone. Now I wanted to make shared libraries of the plugin for use in the Android and iOS versions of the app. I was wondering if you had any experience with this? I’d like to just use the win32 console app project I used to make the plugin as it is now but I’m guessing I have to use the Cross Platform Shared Libraries project type in VS2015? I’m a little lost as to how to port it over. If you had any suggestions for resources that might lead me in the right direction that would be great! Thank you.

Leave a Reply

Your email address will not be published. Required fields are marked *