Search Unity

Is C++/CLI forbidden in Unity?

Discussion in 'Scripting' started by AP-IGD, Jun 24, 2019.

  1. AP-IGD

    AP-IGD

    Joined:
    Jun 24, 2019
    Posts:
    5
    Hy there

    As the title intends, I'm trying to integrate a C++ library to Unity scripting, so C#. As recommended by MS, I'm using the managed interop. I'm not the first one, but seemingly the last that hasn't perished yet...
    So there is C++ library --> wrapped in C++/CLI mixed assembly --> wrapped by C# assembly --> called by my unity C# script

    Problem is:

    - Using a C# assembly with references to mixed (using C++/CLI as external interface) assemblies causes Editor to crash and build-generation to fail

    To be more precise:
    - Editor : the assemblies are loaded, but the first transition to the mixed assembly makes the engine call the good old C-style 'abort()' during text logging
    - Build generation : fails by providing depency error (assembl. not found or not allowed to load)

    It's not due to (debugged that quite intensely):
    - version conflicts
    - wrong build type settings
    - other dependencies (happens for just 60 lines of code with no additional dependencies...)
    - and other things someone with 30 years experience in programming would check...

    I've come to the point where I'm SURE that this is either an everlasting bug in the engine or intended behavior. I'm in with a pro-license but my employer is not big enough, to efford the premium support... Thus I cannot ask an insider.

    Does anyone have any clue about what "the creators" are saying?

    I've found various bug reports and questions, but NONE got ANY answer... For now we don't want to migrate to Unreal, but if it's the only way to use C++ without writing those ancient and inefficient C-wrappers, I'm afraid we'll have to.

    HELP
     
  2. WallaceT_MFM

    WallaceT_MFM

    Joined:
    Sep 25, 2017
    Posts:
    394
    By default, Unity relies on Mono, which doesn't support mixed assemblies. You might have better luck switching to il2cpp if you haven't already. That's found in Player Settings -> Other Settings -> Scripting Backend. Haven't done it myself but seems worth a try.
    EDIT:
    Hmm, looks like it may simply not work, according to this answer: https://issuetracker.unity3d.com/is...n-calling-a-function-inside-a-c-plus-plus-dll
     
    AP-IGD likes this.
  3. RTFM

    https://docs.unity3d.com/Manual/NativePlugins.html

    Also maybe useful:
    https://docs.unity3d.com/Manual/UsingDLL.html
    https://docs.unity3d.com/Manual/PluginsForDesktop.html
    https://docs.unity3d.com/Manual/NativePluginInterface.html

    These are the options. Please keep in mind, Unity's scripting mainly is C#, C++ plugins are supported on this extent. You can buy source license and build your own Unity from source if you like to integrate deeper on the basis of C++.
     
    lordofduct likes this.
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,745
    Your best bet is to write a C wrapper around your C++ code in order to remove issues with name mangling, then compile it into a library for inclusion in Unity.

    Then just follow the links posted by @Lurking-Ninja above and call your C entry points directly from C# interop.
     
    lordofduct likes this.
  5. AP-IGD

    AP-IGD

    Joined:
    Jun 24, 2019
    Posts:
    5
    Thanks to the replies, but maybe I wasn't precise enough... I've literally read all pages you linked here (again thanks for that). As far as I understood, all statements are targeting the use of native/mixed plugins. Not safe C# assembly plugins with dependencies to others.

    @WallaceT_MFM
    I've indeed tried il2cpp. Unfortunately that made absolutely no difference. ?!Surprisingly, even the crash point in the editor and the error message in the generator were the same!? Thanks nevertheless

    I've read the manual (aeh, much of it). Please read the question carefully: this is NOT about a C++ plugin! It's a normal C# assembly, that has a DEPENDENCY to a managed (so already 'name-compatible-mangled') assembly. So even in the C# sources (not visible to Unity) no C/C++/CLI stuff is used and it's compiled outside of Unity and linked against the valid system libraries. This is no violation of requirements to plugins, if you have a link to a comment that proves me wrong, please share. So when the dependencies are not explicitly checked recursively (for whatever state), no difference to a standard Unity plugin (or any verifiable assembly) is visible...

    The problem with all the proposed extern-C interface methods is, that you'll end up in a big state machine; no longer object oriented. Since I use rather complex data structures, that's not an option. And neither is porting time critical, hardware related code to C#. But I know these are the only two ways to use your code from within C# when no CLI is possible. That's why I was hoping the indirection via the library dependencies could be a solution, or at least a glitch...

    So my conclusion is, "Unity does not support the use of managed C++ dlls" also recursively applies to all dependencies of the assembly. This is the worst case, since even writing a C-interface might end up in crashes due to dependencies... We'll discuss what to do in our team, but I'm afraid we've to revise our engine decision. So hello Ms Alotta Work

    And please, before you start to hate me out loud: I like Unity and will continue using it for private stuff, regardless the company decisions :)
     
  6. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,338
    If the engine is crashing, that's always a bug, and should be reported through the bug reporter. Unity should not crash, if you do something that's not allowed, you should be getting an error message.


    This is something that I'm pretty sure should work. That being said, it might very much be that you're not using a compatible compiler. Or you might be doing something else wrong?
    You could try posting in the experimental scripting subforum - it's not quite the right category, but some of the staff members working on Unity's compiler tech reads and replies in that subforum.

    Finally, what Unity version and runtime version are you using? You could check if this works with the deprecated 3.5-based runtime, in which case you have a regression bug that's pretty likely to get fixed.
     
    AP-IGD likes this.
  7. AP-IGD

    AP-IGD

    Joined:
    Jun 24, 2019
    Posts:
    5
    Aah. Framework version, sry I forgot to mention these...

    I'm using up-to-date Visual Studio 2017 with MS compiler (unfortunately the only one capable of CLI compilation) and default setup Unity 2019.?3? and a 2018.? (I'm not in office, so I cannot tell the exact framework version) so at least close to the latest version. I've tried .Net framework in 4.x, explicitly 4.6.1 and the 2nd core version, always the SAME problems... Wan't to test VS2019, but I not yet had the hours for installing.

    I've found bug reports (to my understanding describing the same problem) for the editor-crash in various versions, one of them from 2013 (sorry, I should have bookmarked the links, I'll check). Neither of them got any response, so I didn't even try to post a new one. Maybe with some more knowledge of what's going on, I'll create a more precise report.

    @Baste
    Thanks, I appreciate your help! I agree, it should never crash. On the other side I know how hard it can be, to write programs that are robust to all possible wrong-goings... And the 'funny' thing is, the editor tries to generate an error message somewhere deep in the frameworks C code and crashes while reporting it. So something is very wrong.
    I'll try the 3.5 runtime and report back as soon as I have more info. Also I'll check the experimental subforum.

    Since I've got more response here, than all my predecessors in other places all together, a glimbs of sunshine seams to rise at the horizon.
     
  8. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,338
    It's a long shot, but you could try to have Unity's internal Roslyn version build the .dll instead of using VS. There's a C# interface for compiling files, see here for a pretty basic tutorial.
    It might be that that API has the ability to target a .sln or .csproj and have magic happen, I don't know.

    2019.3 is very, very much in alpha, so it's probably not that. The stable versions are 2018.4 ("long term support") and 2019.1 ("tech" release). If you have actually tried to use 2019.3 and not 2019.1 and didn't just miss-remember the version, you should make sure it breaks in the 2019.1.


    If nothing works, and you don't want to wait for a bug report to be processed, it might be that you could attack this from a different direction. With IL2CPP, you're supposed to be able to drop cpp files directly into the project, and call out directly. That might be easier than what you're trying to do?
     
    AP-IGD likes this.
  9. AP-IGD

    AP-IGD

    Joined:
    Jun 24, 2019
    Posts:
    5
    Even more thanks Baste. I've stacked the ideas and will process them as soon as I can... I'm quite sure not be be in alpha, but will definitely check that. Especially the cpp-drop may be an interesting approach, so far from the ones I tried, that it might give new results. The complete source is pure C++11, so compiler and platform independent.
     
  10. AP-IGD

    AP-IGD

    Joined:
    Jun 24, 2019
    Posts:
    5
    OK, finally I (think I) worked the problem out. I was mostly using Unix/Linux and 'hard compiled' languages. This is about Windows and Just-In-Time (JIT) compiler like languages, so if someone wants to add/correct something, PLEASE do.

    Thanks to Bastes' attack-from-different-direction-advice I've used IL2CPP to generate a VS solution using dummy assemblies. So I discarded the dependency to C++/CLI lib and added C# instead. So basicly I have a C# wrapper assembly for a C# assembly, seams odd but helped to understand, what's going on when Mono and IL2CPP do, when transforming the assemblies. ! yes even external dependencies of plugins have to be transformed !

    Setup is: A Base C# assembly having 'some' functionalty. A PlugIn C# assembly directly forwarding calls to the Base. In Unity create a script, referencing the C# plugin. Obviously, no problem in Editor or Build system.
    Creating a VS solution using IL2CPP generator reveals the pitfall (I should have been aware of): the JIT compilation in C# assemblies. Due to this, execution code can not easily be hidden, since normally it is compiled 'somewhere' at runtime and has to be known to the environment. And so it has to be for IL2CPP and Mono... C# assemblies have no problem, their Intermediate Language (IL) is transformed to C/C++ and done.

    Adding a reference to an assembly that is (at least partially) not a JIT compiler like language breaks this chain. The assembly references are (and have to be) recursively processed and at some point a not JIT compile code (dll) is reached. Trying to find the code to be unJITed obviously fails. At this point, Mono chrashes in Editor and the Build-generator indeed means "is not allowed to load". More helpfull would be something like "is not an IL assembly" or something like this... This is why a delay loaded library (don't mess up with Dynamic Link Library = DLL) with a C-interface is needed. It's the answer to the question, how to hide code to the JIT compiler environment, GC etc.

    Subsuming:
    -the problem is about assembly conversion (i.e. IL in Mono/IL2CPP)
    -the problem is not within Unity
    -the problem is not about name mangling (the code converter would handle this...)

    So yes, (for now) ANY not JIT-compile language is forbidden at ANY depth of (externally visible) dependency, since neither Mono nor IL2CPP can handle transitions between the two compilation paradigms. Unfortunatly, I didn't got that earlier, since the concept of not hiding code when 'linking' external libraries is not what I'm used to...

    Solution for hardcore coders:
    You can create a VS solution as I did above using dummy libraries to replace yours. Then you can look up the transformed code (for me : FolderYouSelectedInBuildDialog/Il2CppOutputProject/Source/il2cppOutput/YOURLIBNAME.cpp) and CAREFULLY integrate whatever you want using Visual Studio and the solution file. But the code is highly auto-gen and connected to the rest of the IL2CPP framework! So there is a lot of byte padding, pointer shifts to members etc. It will be a pain in the ...

    Finally: thanks @Baste and @WallaceT_MFM. The IL2CPP got me on the right way!
     
    Doidel and Baste like this.