Search Unity

DLL Problems

Discussion in 'Scripting' started by sz-Bit-Barons, Jul 15, 2015.

  1. sz-Bit-Barons

    sz-Bit-Barons

    Joined:
    Nov 12, 2013
    Posts:
    150
    Hi,

    I would like write my code in separate assemblies and use the compiled DLLs inside my unity project. This works well as long as you don't have (generic) classes deriving from MonoBehaviour, which are base classes for classes in other assemblies.

    I followed this great post to figure out what to do:
    With ILMerge I merge all the assemblies I use into one single DLL file. (Then I create a MDB file with pdb2mdb but this doesn't seem to make any problems).

    I create the DLL with the following batch file:
    Code (csharp):
    1.  
    2. set output="Merged.Ofm.Framework.dll"
    3.  
    4. REM remove previously compiled dll
    5. del %output%
    6.  
    7. REM Create a single .dll that combines the root .dll and all subassemblies.
    8. set unitypath=%~1
    9.    
    10. "..\..\packages\ilmerge.2.14.1208\tools\ilmerge.exe" /target:dll /lib:"%unityPath%\Editor\Data\Managed" /lib:"%unityPath%\Editor\Data\UnityExtensions\Unity\GUISystem" /lib:"%unityPath%\Editor\Data\UnityExtensions\Unity\Networking" /targetplatform:v2,"%unityPath%\Editor\Data\Mono\lib\mono\2.0" /out:"%output%" "Ofm.Framework.Ui.dll" "FullInspector-Core.dll" "Ofm.Framework.Core.dll" "Ofm.Framework.Core.Unity.dll" "Ofm.Framework.Commands.dll" "Ofm.Framework.Storage.dll"
    There is one thing I am not sure about:
    Code (csharp):
    1. /targetplatform:v2,"%unityPath%\Editor\Data\Mono\lib\mono\2.0"
    this specifies where to look for the .Net framework for merging (or in this case the Mono Framework). I am not sure what to set here.
    In my Visual Studio Projects I reference "Unity 3.5 .net full Base Class Libraries" as Target framework. I have no Idea how I can let ILMerge also reference this particular target. I believe this is the source of my problem.


    Ok, now I have to tell you the problem:

    In Unity the DLL looks good in the Project Window. I see it there, can expand it and see all the classes which inherit MonoBehaviour.

    But my Hierachy and Inspector window don't show anything.

    I get tons of errors in the console:

    Full Inspector (awsome Editor Extension I use) error:
    Except for the Full Inspector error all the errors are spammed into the console very often...

    I guess It is because my DLLs are referencing something different than the editor which actually should be shared between both (either UnityEngine DLLs or the Mono stuff...)

    Any suggestions?
     
  2. ippdev

    ippdev

    Joined:
    Feb 7, 2010
    Posts:
    3,853
    Yeah. Post to the proper subsection dealing with Scripting.
     
  3. guavaman

    guavaman

    Joined:
    Nov 20, 2009
    Posts:
    5,632
    That post I made was outlining a particular way of having base classes in the DLL extended by scripts in the project. I don't use this method anymore because frankly it did not improve performance in C# for the most part. It was a huge benefit to JS compile speed, but I've since moved fully to C# and I do not regret it.

    Additionally, if you're just extending the base classes in the DLL from scripts in your project, there's no need for the ILMerge step. Unity can extend the base Monobehavior classes in a script without issue.

    I believe the path after v2 is unnecessary. Just leave it off and it will use .NET 3.5.

    Do you have a custom inspector for this class? If so, where is it located? It should not be inside the DLL. You should never have any references to UnityEditor.dll in your game assemblies because that DLL is never available in a build.
     
    Last edited: Jul 15, 2015
  4. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Yeah I'm not sure why you're using ILMerge. You may be merging in assemblies that Unity already references and creating ambiguous reference issues, or accessibility issues. Just use multiple DLLs if you need and only copy over what's needed that Unity doesn't already reference. Also, if you have editor extensions, leave those in their own assembly and make sure they're in a /Editor folder.
     
  5. guavaman

    guavaman

    Joined:
    Nov 20, 2009
    Posts:
    5,632
    I used ILMerge in my old post because I wanted to extend a MonoBehavior-derived class that existed in one DLL from another DLL and it was the only workaround I could find. There's no need if you're just extending them in scripts. However, the OP seems to need to merge the ofm.framework DLLs, which shouldn't be a problem.

    I've had no ambiguous references when using ILMerge. It doesn't include the UnityEngine DLL in the merge unless you specifically tell it to. (That would be bad.)
     
    Last edited: Jul 15, 2015
  6. guavaman

    guavaman

    Joined:
    Nov 20, 2009
    Posts:
    5,632
    I think I see the problem. You did merge "Full-Inspector-Core.dll" into the same assembly. I'm guessing this is a Unity inspector. As such, it references UnityEditor.dll and cannot be in your runtime dll. You need to make a separate DLL for the editor and either place it inside an Editor folder in your project or check only the "Editor" box in the DLL import inspector if using Unity 5+ so it is never included in a build.

    By the way, I've never had good luck with including custom inspectors in DLLs, which may ultimately be the real problem here. Unity just doesn't process them correctly. I've done it before but it requires that you have an Editor derived inspector script in the project that then makes calls to a class in your DLL that does the actual work. The class in the DLL should not extend Editor.
     
    Last edited: Jul 15, 2015
  7. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Unless Unity has something different, Full Inspector is a (very nice and handy I might add) package from the Asset Store.
     
  8. guavaman

    guavaman

    Joined:
    Nov 20, 2009
    Posts:
    5,632
    If the issue is with Full Inspector, I cannot help any further. This isn't part of Unity's standard workflow and I have no experience with this package to tell why why its inspectors aren't working.
     
  9. sz-Bit-Barons

    sz-Bit-Barons

    Joined:
    Nov 12, 2013
    Posts:
    150
    Thanks for all the replies :)

    I think I have to clarify some things...

    1. Why I want to use DLLs
    There are several reasons why you could want to use DLLs with unity. Compile time in Unity is one reason, but not the most important for me.
    I like to have one assembly for one topic because you cannot cross reference between the assemblies anymore which leads to cleaner code. Also if you split your code into a framework part and a game part (game references framework but not the other way around) you can simply copy your framework over to a new project without worring about game related code.
    Except for this cosmetic thing I have another usage for some of the DLLs: The game I am working on will have a backend in the cloud which runs C#. I wanted to use some code on both sides, the client and the server. Custom visual studio projects with some post build scripts to copy the output dll to unity and to the backend repo would have been very elegant...

    2. Why I have to merge the DLLs
    I managed to copy all the DLL and MDB files into one single unity folder. They seemed to work. But then I discovered that none of the Behaviours where available which derived from another Behaviour in another DLL. At least if the base-Bahviour was a generic type.
    To overcome this Unity bug I merged all the DLLs into one as described above.

    3. What is this Full Inspector thing?
    Full Inspector is the best Unity editor extension I know. It can serialize and display many things in the Inspector which Unity cannot handle normally even in an AOT environment (like iOS - credits also go to Dustin Hornes Json.Net serializer). Search for it if you don't know it. It is great!
    Every MonoBehaviour which should be serialized with Full Inspector has to derive from "BaseBehavior<TSerializer>". As you can see this is a generic base class (which derives from MonoBehaviour). So even if I wouldn't split up my Framework that much I still would have the problem with the lost Components.

    4. Don't use Editor stuff!
    I do not. My editor code is still in some loose source files inside the unity project. None of them are inside one of my DLLs.
    I am not 100% sure about the Full Inspector DLL (only 99%). There is one DLL for the Core Full Inspector stuff and a separate one for the Full Inspector Editor stuff (in another folder called "Editor"). So I guess in the Core DLL shouldn't be any editor related things.
    When I use source code in the unity project instead of my DLLs but still use the Full Inspector DLL everything works fine. Seems like the Full Inspector is not responsible.

    5. Don't include Unity DLLs!
    I do not. I just reference them in the merged DLL using the ILMerge argument "/lib:%path%". The path to the Unity DLLs is of course the same as the location of the unity editor version I use.
    ILMerge didn't compile as long as I didn't reference UnityEngine.Network.dll. This was strange because I do not reference this in any of my assemblies. However, maybe Full Inspector references it for some reason. After pointing to the path (/lib argument) where that DLL can be found, it was able to merge.

    I hope I didn't forget anything :)

    Ah, and thanks for the suggestion guavaman:
    unfortunately removing the path didn't change anything (but yeah, it merges the DLLs without errors).
     
    Dustin-Horne likes this.
  10. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Or just click the link in my signature. :p And yes, Full Inspector is awesome, and the publisher is very responsive and helpful as well. I highly recommend it.

    And I see what you're saying... it's a known issue when you try to create a Behaviour that inherits from another in a separate assembly. I've seen other references to that in the forums. No idea why it doesn't work.
     
  11. guavaman

    guavaman

    Joined:
    Nov 20, 2009
    Posts:
    5,632
    Thanks for all the clarifications. This information is really helpful in understanding what your needs are. What you are describing is exactly what I described in that old post about 2 separate DLLs. The solution worked for me and I didn't see any issues with inspectors.

    I would suggest you do some basic tests with fewer variables involved to see if you can determine which part of the process is causing it to break. The errors you are receiving are pretty much all over the map and make it impossible to tell which part of this is failing. Try to do a basic 2-dll merge with the MonoBehavior inheritance and see what happens. At the time I wrote that post it worked, but Unity does have a tendency to break things over time. Then you could try the same thing while also including and using Full Inspector.

    Edit: One more thing: The idea of a single unified DLL for all the support frameworks in your games sounds like a great idea in theory. But it can tend to be brittle when it comes to cross-platform compatibility. There are scores of hidden and undocumented gotchas that span just about every non-desktop platform, especially WSA, Webplayer, iOS, WiiU, and WebGL. For example: This and This and This and This among many more. Going to DLLs and maintaining cross-platform compatibility means you have to code for the least common denominator (once you discover each of these caveats) and put all kinds of workarounds in your code (reminds me of web development) or build platform-specific DLLs. The latter is probably easiest now that Unity 5 includes the per-platform DLL include system.
     
    Last edited: Jul 16, 2015
  12. sz-Bit-Barons

    sz-Bit-Barons

    Joined:
    Nov 12, 2013
    Posts:
    150
    Hmm... I tried to combine Full Inspector and one other DLL (one which doesn't even reference unity) and nothing more and still having the problem.

    Now I have no Idea anymore. So I guess I will work with source code files again.

    I realized that I still can have shared DLLs with the backend. Because the Backend doesn't know Unity the shared DLLs cannot reference the Unity DLLs. Therefore there are no MonoBehaviours in these assemblies. And this means such DLLs should also work with unity and without merging.
    So I still have my most important benefit of the DLLs.

    Thanks for your support.
     
  13. guavaman

    guavaman

    Joined:
    Nov 20, 2009
    Posts:
    5,632
    I don't know if you want to spend more time on this, but I just thought of a couple of possibilities that might lead you somewhere:

    1. Take a look at the DLL in ILSpy and see what .Net version it was built on. Do the same for your resulting merged DLL.
    2. Check if it or its partner library Full Inspector Editor has any Friend Assemblies listed. If Full Inspector has any internal members being accessed through friend assemblies. If the final assembly name doesn't match, this would break.

    Another thing I just saw is that you've got your referenced assemblies in 3 different folders for the ILMerge. I may be remembering incorrectly, but I believe I had to manually copy the assemblies into the same folder as the files being merged. (I may be thinking of working with pdb2mdb here...)
     
  14. sz-Bit-Barons

    sz-Bit-Barons

    Joined:
    Nov 12, 2013
    Posts:
    150
    Thanks for your Ideas guavaman.
    In fact I cannot spend more time for this topic at least no time at work. Maybe I will investigate this a little bit more in my sparetime...

    my referenced Assemblies are indeed in three different folders, because I reference the install location of unity and the folders where to find UnityEngine.dll, UnityEngine.UI.dll and UnityEngine.Networking.dll. This seems to work. In the documentation of ILMerge is a hint that this is possible by using a /lib argument for each reference path. If I don't reference them all ILMerge throws an exception. So I am pretty sure it does the job.