My goal is to get a toy C++ library wrapped using SWIG, and accessible to C# / Mono scripts in Unity. (In other words, have the library functionality working in a Windows build of the game. I'll tackle Android next :)
I have been following a combination of Build a C# module (SWIG tutorial), Unity and DLLs (Eric Eastwood) and Getting started with SWiG for Visual Studio projects (Technical Recipes). I have generated two DLLs in Visual Studio 2013 and added them to the Unity project. But accessing the toy method at runtime is failing.
Steps I followed (including common fixes for the error I am receiving):
Create C++ project / custom build
Create a C++ Win32 Console Application project in Visual Studio
(because MonoDevelop on Windows cannot compile C++)
Add example code to the project
Create example.i (interface file for SWIG)
Create an Custom Build Tool for the interface file
Execute the Custom Build Tool (generates wrapper code for C++ and C#)
Add C++ wrapper code to project (will be used later to generate C++ DLL)
Create C# project
Create a C# Class Library project in Visual Studio
Change Target Framework version 3.5
Add C# wrapper code files to project root
Add the following library references and namespace to the C# wrapper files:
using System;
using System.Runtime.InteropServices;
namespace CSharpExampleLib {
...
}
Build two Release DLLs
Set the build settings to Release / x86 for both projects
Set the target for the C# build to the target of the C++ build
Build the solution (generates two DLLs, one per project)
Confirm with Dependency Walker that the DLLs do not see each other as missing (reference)
Used CorFlags to force the C# DLL to be 32-bit (reference) (this does not work / does not apply to C++ DLL)
Add DLLs to Unity project
Create a new project in Unity 4 (Pro) with a simple Mono script
Close Unity project
Copy the DLLs into Assets/Plugins folder
Reopen the Unity project (DLLs recognised)
Right-click on Assets in the Project Hierarchy, select "Synch with MonoDevelop..." (opens simple script in MonoDevelop, ensures DLLs are accessible)
Added library references to the simple script:
using System.Runtime.InteropServices;
using System.IO;
Invoke method from DLL
Finally, I added a logging call from the simple script to the C# DLL (Intellisense confirms that the DLL and method are accessible):
Debug.Log(CSharpExampleLib.example.fact(3));
// should log the result of 3 factorial
Runtime error
However, when I start the game from the Unity editor, I get the following error:
DllNotFoundException: example
CSharpExampleLib.examplePINVOKE+SWIGExceptionHelper..cctor ()
Rethrow as TypeInitializationException: An exception was thrown by the type initializer for SWIGExceptionHelper
CSharpExampleLib.examplePINVOKE..cctor ()
Rethrow as TypeInitializationException: An exception was thrown by the type initializer for CSharpExampleLib.examplePINVOKE
CSharpExampleLib.example.fact (Int32 n)
SimpleController.Start () (at Assets/scripts/SimpleController.cs:10)
I made several attempts to correct common causes for this error (build as Release, build as 32-bit, check Dependency Walker, etc) to no avail. Is there something SWIG- or Unity-specific I am missing? Any other checks I can perform on my DLLs?
After discussion on the SWIG user mailing list and some careful review, I discovered I was missing two configuration steps:
The C++ DLL must have the same name as the module name specified in the SWIG interface file (so for my toy example using interface file example.i, it is best to name the C++ project "example" and it will generate example.dll)
In the backwards and forwards of resolving other issues, I lost the reference to the autogenerated C++ wrapper (example_wrap.cxx) and needed to re-add it to the C++ project.
Related
I'm trying to use the OpenCV library for android (native C++) with Xamarin.Forms application. I created a Dynamic Shared Library and its wrapper in C# that works when there is no OpenCV in the project.
Next, I configured my library project to use OpenCV and built it (without actually using OpenCV in my code). The build is successful, but now when I run my Xamarin application and call functions from c++, the bellow exception will be thrown:
System.DllNotFoundException: 'libMathFuncs.so assembly:<unknown assembly> type:<unknown type> member:(null)'
I followed the instructions described here, successfully created a .so file, and used it in Xamarin.Forms application. I wrote the whole process in my blog.
Then I did the following changes to my Dynamic Shared Library project configuration (in Visual Studio):
In General -> Use of STL : LLVM libc++ static library (c++_static) (also tried shared library)
In C++:
General -> Aditional Include Library: Add "PathToOpenCV\sdk\native\jni\include" (I also tried to add this
path to VC++ Directories -> External Include Directories)
set the Enable C++ Exceptions to Yes (-fexceptions)
set the Enable Run-Time Type Information to Yes (-frtti)
set the Precompile Header to Not Using Precompiled Headers
In Linker:
I tried two ways:
Way 1: I added "sdk\native\libs\arm64-v8a\libopencv_java4.so" to input -> Aditional Dependencies
Way 2:
Added "sdk\native\libs\arm64-v8a" to General -> Additional Library Directories and
Added "opencv_java4" to Input -> Library Dependencies
I didn't use any OpenCV in my code (Actually did at first, but remove them). The project is built successfully.
But now when the application calls the function from .so file, the above exception will be thrown.
I tried with or without changing the told flags, but the result was the same.
Note: For now I only intrested in ARM64
My Enviremont:
Visual Studio 2022
Xaramin.Forms (Android Only)
Target API Level: Pie 9.0 (android-28)
Android NDK: R23C
Target: Nokia 8.1 - Android 11
There is a code in GitHub that is similar to what I want to do. I compared the project configuration and code of this repo with my project but didn't find where I went wrong.
Context
I got this uwp demo project which uses this sdk. The sdk is available for Windows UWP C#. Running its solution works fine and it does what it's supposed to do. Now I want to use it in my unity project, which is set up for the ar glasses HoloLens (choosed uwp as bulding platform in unity).------------------------------------------------------------------------------------------------------------------------------------ Question
How can I use the dll from the demo project in my unity project?
------------------------------------------------------------------------------------------------------------------------------------
What I tried
1. I took the dlls out of the build dir of the demo project and imported them to unity. I created a folder Assets\Plugins and put it there. Trying to use it via using Kinemic.Gesture gives me the error error CS0246: The type or namespace name 'Kinemic' could not be found (are you missing a using directive or an assembly reference?) I also tried to add the reference by using the reference manager and taking the dll from the pluing folder, but then I got this notification:
2. I took the nuget-package and changed the format to .zip, so I can unzip it and take the dlls out of it. But I got only targets:
3. I opened my unity project in visual studio by opening a script in unity. Created by right click on solution → Add new project → Class Library (Universal Windows) a new project. That way I could add the package via nuget manager:
I thought building this project should give me the dlls/references but all I get is this error in Unity:
------------------------------------------------------------------------------------------------------------------------------------
My setup
Unity 2019.2.9f1
Visual Studio Pro 2019
The only correct way of adding external DLLs to unity in the listed trials above is the first one, every other method will not compile/build or crash at runtime (guaranteed).
So how to use a UWP library in unity.
For a C# library
If it says Type: 'Managed' and Targets some .NET x.y, then it is.
1-1: In previous screenshot, if the library 'Targets .NET 4.x then edit your project settings to target .NET 4.x
1-2: Again, in the first screenshot, select the library, and edit the 'Include Platforms' with only UWP (WSA Player) platform selected, any other platform won't work including the editor.
1-3: Build your project, without trying to use the library:
Did it build safely ? great, proceed to next step.
Did it produce errors ? figure out what the reason was and why.
1-4: Since this is a UWP library, and there is no unity editor version for it, you won't get intellesense support for it, and so using Kinemic.Gesture will produce errors in the editor, any code in that library needs to be wrapped inside #if directive for UWP platform.
An #if directive simply tells unity to ignore that code until the app is running at build on specific platform, since only then will the library be usable by unity, to learn more: Platform dependent compilation
For example:
#if UNITY_WSA
using Kinemic.Gesture;
#endif
using UnityEngine
public class SomeClass : MonoBehaviour
{
public void SomeFunction
{
#if UNITY_WSA
// call some code in the Kinemic.Gesture library.
#endif
}
}
For a Native Library
It is a little bit trickier than that, but you get all intellesense support, it would still be only functional in the build tho.
One way is to interop with the library from your unity scripts using PInvoke, for more information see Unity Nativ Plug-ins
Another way, which I like is to write a wrapper C# library for this C++ library and import the C# wrapper to unity, this is achieved by:
Create a Class Library (.NET Framework) C# project.
Import Kinemic from nuget or by adding reference.
Start with a class called UnitKinemicWrapper, that looks like:
using Kinemic.Gesture;
public class UnityKinemicWrapper
{
public static void KinemicConnect(string band)
{
Kinemic.Gesture.Engine.Connect(band);
}
}
Build your C# wrapper library, and import it to unity.
Configure it with the steps at the very beginning of this guide for configuring C# libraries, in addition to that, tell unity to not process this library by un-ticking these checkboxes, then hit apply.
Now in your unity scripts you can call
string band = "band";
UnityKinemicWrapper.KinemicConnect(band);
Another approach for UWP projects only
Don't import any Kinemic libraries to unity.
Build your unity project.
Open the UWP produced project.
From there, contact unity using UnityEngine.GameObject.SendMessage, more about SendMessage
I am attempting to write a a CLI interop layer between an existing c++ codebase and a c# wpf app. My c++ libraries already overload global new and delete in order to implement my own memory tracking and other niceties. So the dependencies look something like this:
(Native library compiled to static lib)->(CLI layer)->(C# WPF application)
However, whenever I include my native libraries and try and build my CLI project, I run into a conflicting symbol for global delete which was already defined in msvcrtd:
Error LNK2005 "void __cdecl operator delete(void *)" (??3#YAXPAX#Z) already defined in msvcrtd.lib(delete_scalar.obj)
I'm not sure how to get my build to take my global delete instead of the one in the default library. I have tried making another pure native project that compiles a DLL, and compiling all of my static libs into that, then having the interop layer load that DLL. This works, but I'd rather not have 2 layers of glue instead of the one.
I'm using visual studio 2015.
The native component uses the CRT as DLL? This is requirement if using mixed assemblies. If you statically linked library uses the static CRT you get into troubles.
Check and link with the /VERBOSE flag to see, where this other delete comes from. Eliminate this other library call.
This question is kind of lengthy but I try to provide you with the details that I think is necessary to find the answer.
I have a C# WPF solution (.Net 4) consisting of a main project, building a WPF windows app, which depends on a few class library projects residing in the same Visual Studio 2010 solution.
One of the class library projects encapsulates some previously developed python code that I want to make use of through IronPython and Microsoft Dynamic Language Runtime.
I would like the class library project to be self contained and not depend on a complete installation of IronPython.
The problem is that I don't know how to refer to the encapsulating library project holding the python code in a way that always work.
Normally I would just add a reference to the class library project as discussed in this question: Visual Studio 2010: How refer to a C# .Net class library project with third part dependencies. However it did not help.
How the solution is set up in Visual Studio:
The solution looks like this:
MainApp (windows WPF application project)
...
ClassLib1 (C# class library project)
...
ClassLibWithPython (C# class library project with IronPython)
C# classes
lib (directory)
IronPython.dll
IronPython.Modules.dll
Microsoft.Dynamic.dll
Microsoft.Scripting.dll
Microsoft.Scripting.Metadata.dll
pylib (directory with some used python modules)
os.py
... .py
ctypes (directory with some used python modules)
my pyton classes (directory)
ClassLibWithPython has references to the IronPython DLLs residing in its local lib folder (Copy Local attribute True). The MainApp project has references to ClassLib1 project and ClassLibWithPython project (also with Copy Local attribute True).
When compiling the solution all DLLs and the MainApp.exe file shows up in MainApp/bin/Debug and it works fine on some machines (XP and Win 7) however it fails on some other machines (XP). After doing some debugging I've found that the built-in IronPython modules are not loaded correctly. When importing the os module (pylib/os.py like this one http://pydoc.org/get.cgi/usr/local/lib/python2.5/os.py) I get a python exception (ImportError, no os specific module found) due to missing module name 'nt'.
When comparing what's happening where it works and where it doesn't I've found that sys.builtin_module_names just returns a few items compared to what I get when running the same code on some other machines.
Problematic machine has:
sys.builtin_module_names = ['clr', 'future_builtins', 'imp', 'sys', '__builtin__', 'exceptions']
Computers where everything works have:
sys.builtin_module_names: ['clr', 'future_builtins', 'imp', 'sys', '__builtin__', 'exceptions', '_codecs', 'cmath', '_sha512', 'msvcrt', 'array', '_winreg', '_weakref', '_warnings', '_subprocess', '_ssl', '_sre', '_random', '_functools', 'xxsubtype', 'time', 'thread', '_struct', '_heapq', '_ctypes_test', '_ctypes', 'socket', '_sha256', '_sha', 'select', 're', 'operator', 'nt', '_md5', 'math', 'marshal', '_locale', '_io', 'itertools', 'gc', 'errno', 'datetime', 'cStringIO', 'cPickle', 'copy_reg', '_collections', 'binascii', 'zlib', 'signal', 'mmap']
Work-around that didn't help
I've tried to add using statements to the C# code of ClassLibWithPython to make sure even the implicitly referenced assemblies are linked, but with no difference.
Work-arounds that helped
I've found two workarounds providing a working solution, however both of them breaks the encapsulation principle and exposes the implementation details of ClassLibWithPython:
Put all code from ClassLibWithPython in the MainApp project instead.
Keep ClassLibWithPython in a separate project but add references to IronPython.dll and IronPython.Modules.dll to the MainApp project as well.
What is it that make work-around #2 working?
Any suggestions how to make this work in a clean way?
Thank's for reading this far ;-)
I don't fully understand the deployed layout - but try the following.
1) For modules that you expect to be loaded from IronPython.Modules.dll ensure that this assembly is available in your deployment location, and/or hook AssemblyResolve (see here) event if this assembly is in a different location.
2) For modules that you expect to be loaded from a py module. Ensure the probing location is added to sys.path via sys or from the DLR hosting API. eg sys.path.append(...)
I have a DLL that I've been using with no problem in Visual C# (simply adding the reference and using the namespace). Now I'm trying to learn C++, and I don't understand how you reference a namespace from a DLL. I can right-click on a project and select 'references' and from there click 'add new reference', but that just provides me with an empty 'projects' window. What am I missing?
C++ is a lot different from C#/VB.Net when it comes to processing DLL references. In C# all that is needed to do a reference is a DLL because it contains metadata describing the structures that lay inside. The compiler can read this information such that they can be used from another project.
C++ does not have the concept of metadata in the DLL in the sense that C# does. Instead you must explicitly provide the metadata in the form of a header file. These files are included in your C++ project and then the DLL is delay loaded at runtime. You don't actually "add a reference" so to speak in C++ but include a header file instead.
Once the header file is included, you can then access the namespace by including it in your CPP files
using namespace SomeNamespace;
First of all, if you are trying to use the same DLL you used in your C# application, if you are using pure native C++, it is not straightforward to make calls into that DLL. The problem is the DLL you are referencing in C# relies on the .NET framework in order to execute (it is a "Managed" DLL, as all C#, VB.NET and C++/CLI assemblies are). There is an easy way to reference "managed" code from C++ and that is by making a managed C++ project (AKA C++/CLI) (choosing from "CLR" section in the C++ project wizard in Visual Studio). Otherwise the only way to access the managed DLL is by exposing it to COM and using COM to access the object.
EDIT: The previous answer will be more helpful if you're using unmanaged c++; I assumed because of the C# reference that you were targeting managed C++.
The 'Add Reference' dialog should have a series of tabs - 'Projects' lists projects in the current solution; .NET lists the libraries installed in the GAC and 'Browse' lets you find a DLL yourself.
If you just want to add a reference to the DLL you should be able to do it with 'Browse'. If it's the output of a project you have the source to, add the project to the solution and it'll appear under the 'Projects' tab.
If this doesn't help, which version of Visual Studio are you using, and where/what is the DLL you want to use?