-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Unity's IL2CPP // AOT compilation mode compatibility #13099
Comments
@ThomasNigro EF Core uses a large amount of dynamically built and compiled code. This causes issues for AOT compilers in a couple of ways:
Neither of these things are, conceptually, blockers for running EF in an AOT environment. The first issue is just about making the configuration experience work. The second issue is not because of AOT, but because the environment precludes a JIT for also dynamically running code. However, given that the two things are often linked--AOT and removal of JIT--it does cause a major problem for EF in these systems. Also, I should mention that EF does not dynamically create types or assemblies. (That is, it doesn't use Ref.Emit directly.) It only uses compiled expression trees and delegate creation to existing methods. This is why it works with .NET Native, at least with interpreted IL. I don't have any context on the Unity system or how it fits in with this; we will discuss as a team whether we can put resources onto any investigation. Hopefully this general information is useful in the meantime. |
@ThomasNigro just to reiterate what @ajcvickers already mentioned, instead of using Reflection.Emit directly, EF Core uses compiled LINQ expression trees, and there is an interpreter of LINQ expressions that is designed for AOT platforms. This is what allows EF Core to work in some other AOT platforms like UWP (when compiled with .NET Native). In fact, Mono has included this interpreter of LINQ expression for a while. That is why it can work also on Xamarin for iOS (although there are some other known limitation that may be currently blocking EF Core from working on Xamarin iOS, as far as I know they are unrelated with the usage of , compiled LINQ expressions). That said, from discussions like https://forum.unity.com/threads/are-c-expression-trees-or-ilgenerator-allowed-on-ios.489498/, it is unclear if Unity is taking advantage of it when using IL2CPP. Although the existence of the interpreter was called out near the end of the thread, Unity people in that thread seemed to be mostly unaware of this possibility. As @ajcvickers there are also common issues caused by the removal of reflection metadata and library code that cannot be statically determined to be required (in the case of IL2CPP this is equivalent to the Unused Bytecode Stripper), but other AOT environments provide workarounds that allow controlling what code and what metadata needs to be preserved (see #10963 for more details) and so this are not blockers either. We would love to see any gaps addressed to make it possible to use EF Core with IL2CPP, but it seems that most of the investigation needs to happen on the Unity side. If you haven't already, I suggest to start a conversation in the Unity community forums or report this in the Unity issue tracker. Feel free to point me to it once you have it, so we can learn more details. |
@ThomasNigro from reading into https://docs.unity3d.com/Manual/IL2CPP-BytecodeStripping.html, it seems that IL2CPP supports the same link.xml format for fine control of what code is removed as Xamarin does with the Mono linker, so if the first error you are getting is due to the removal of such code or reflection metadata, tweaking link.xml might help get further. |
Thank you for these very detailed answers! Those really help understand the potential underlying issues. To sum up:
Also:
As you suggested, I will open a ticket on the Unity issue tracker in the coming days and paste the link here right after that. Thank you for helping and investigating on the matter! |
Thank you. Looking forward to learn more about this.
This should be quite easy to test in a simple program without using EF Core. I will try to do some experiments.
Not sure if we are saying the same thing, but link.xml is supposed to help guide the stripping process. E.g. you add a type with preserve="all" when that class is required but cannot be determined statically to be used, e.g. because you only use it through reflection. As stated in the Unity documentation:
|
I can confirm that the expression interpreter does not work with IL2CPP, however I did not observe a runtime exception. I used a simple project with this C# script: using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq.Expressions;
using UnityEngine;
using UnityEngine.UI;
public class NewBehaviourScript : MonoBehaviour
{
public Text text;
// Use this for initialization
void Start()
{
text.text = "Ok, let's try...";
// this seems to be ignored when using IL2CPP:
text.text ="Hey 1+1 is " + EvalExpression(() => 1 + 1);
}
static int EvalExpression(Expression<Func<int>> expression)
{
return expression.Compile().Invoke();
}
// Update is called once per frame
void Update ()
{
}
} |
Next thing I would like to check if I have a chance if is the behavior is due to the code being removed, so I will look into adding link.xml. |
Regarding Your script tests IL2CPP (in)ability to use the expression interpreter. During our tests with EF Core, we observed compile-time exception. I'm building a small repro project, will upload in a couple of hours. |
Just added the repro sample here : https://github.com/ThomasNigro/EFCoreUnityIL2CPP |
Here is the Unity issue ticket |
Thanks @ThomasNigro. Looking forward to answers to your ticket. Based on the error you reported, it seems there may be multiple issues preventing EF Core form working on Unity. FWIW, I tried a few things on link.xml but didn't see any change. |
Hey, I'm a developer at Unity working on IL2CPP. Hopefully I can shed a bit of light on this issue. Starting in Unity 2018.2, IL2CPP will use the Interpreter for Linq expressions, so some things have a chance of working. As discussed here, you will need to use a link.xml file, since the interpreter implementation uses reflection in internally, and the managed byte code stripper is a bit too aggressive with it. This link.xml should be enough:
In Unity 2018.2, you'll need to use the .NET Standard 2.0 Api Compatibility Level option in Unity. In Unity 2018.3 we're also supporting this with the .NET 4.x Api Compatibility Level. In the future Unity 2019.1 version, you won't need the link.xml file work around, the byte code stripper will be smart enough to keep this code around when it it used. With that said, you might still hit some limitations of the IL2CPP AOT engine. Specifically, these are often related to the use of value types. So a snippet like this, which uses only reference types (a
But code which uses value types (like IL2CPP does not have the capability to share generics with value type arguments yet, where Xamarin for iOS does. This is an area of future development for IL2CPP, but it is not ready for production yet. Regarding the specific issues raised in the bug |
Note for triage: Clearing up assignment and milestone. I think this is not necessarily actionable in 3.0 and can move to the backlog. If things begin working better and the customer demand for running EF Core on Unity becomes significant, we can do some testing, samples, etc. |
Hi, I have read carefully this thread as I would like to make EFCore work with Unity IL2CPP on android & ios. I succeeded in making it working with mono backend but I am not able to compile with IL2CPP. I am using Unity 2018.3, EFCore 2.2.0. I have done a custom implementation of SQLiteRawPCL provider for android working on mono. Even without Entity framework SQLite provider, I am not able to compile. |
You can make EFCore work by having that part of the code reside inside the "GameEngine.DLL" Launcher and wiring up callbacks to both sides of the IL2CPP/C# divide. This is an under utilized capability at the moment; the ability to have code reside in the Launcher layer. Leveraging loose code coupling, you could have just your game logic code reside on the IL2CPP side with everything else sitting in the Launcher layer. Putting too much code in the Launcher layer will limit the viability of the editor experience unless you also implement a strategy to allow the editor to call out to your Launcher layer code (that too is doable). There may also be callback performance, threading performance and thread locking considerations when opting to put code in the Launcher layer. For things that just work on the IL2CPP side, it's not worth the added complexity to put that code in the Launcher layer. The UWP C# Native compiler is much better than IL2CPP in transforming IL. That too may factor into which code you choose to put into the Launcher layer. |
cc @indiesaudi |
#24903 would help with this if we are able to do it. |
@bricelam & @AndriySvyryd , let's make it happen! IL2CPP should fully support .Net Standard, else Unity will start to contribute toward .Net fragmentation in a big way. Especially if the burst compiler bits start to get more traction, with its subset of C#. There's really no need for yet another C# variant if the core can be made to work everywhere in a performant way that significantly outpaces the Unity Burst compiler. Microsoft doesn't yet fully appreciate the extent to which Unity will fragment .Net if its not brought back into the family. |
After NativeAOT implemented generic default interface method, I successfully made efcore work with AOT. Here is a sample project for everyone wants to use efcore with NativeAOT: https://github.com/hez2010/EFCore.NativeAOT But efcore still has a long way to go in NativeAOT aera, e.g. dynamic member annotations so that we no longer need to investigate heavely on the |
@hez2010 thanks for that, good to know! We do plan to revisit making EF Core more trimming- and AOT-friendly at some point, and to ideally work without an rd.xml. |
Is there any way to use Microsoft.Data.Sqlite with Unity today or is that a ways off? |
@Sahasrara You'd need to create a Our expectation is that once Unity moves to .NET 6 we won't need to do anything special in EF or Sqlite to make them work. |
Thanks @AndriySvyryd! So if I build this repo with c651888 reverted, the generated artifacts might allow me to use Microsoft.Data.Sqlite in Unity? Sorry, I think I may be coming in from a position of significant ignorance. |
@Sahasrara No, you can create the Also, you wouldn't be able to use EF Core 6 or 7 as Unity only supports up to .NET Standard 2.1 currently. So, you'd need to use EF Core 5. |
Just using Microsoft.Data.Sqlite (i.e. without EF Core) should work fine with Unity's IL2CPP today. IIRC, it doesn't even require a link.xml file. But installing the NuGet packages into a Unity project is a bit tricky--see ericsink/SQLitePCL.raw#347 (comment). |
Closing since Unity is moving to .NET. |
I'm running into the same issue, and could use some help. I get this error:
I've tried adding it to a link.xml file like this:
I've also tried using the AotHelper from JSON.NET like this:
Neither approach worked though. Any ideas what I'm doing wrong? |
Sometimes these AOT issues are very difficult to get right. I don't think the link.xml will help, as this is probably not a code stripping issue. It looks like you are on the right track with the AotHelper, but I don't see quite what is wrong. I'll suggest another option - In Unity 2022.2 and later this should "just work" as we now have a fall back for these unseen generic cases. See https://blog.unity.com/engine-platform/il2cpp-full-generic-sharing-in-unity-2022-1-beta for details. Is that an option for you? |
Unfortunately not. This is a game in production on Unity 2020.3, so updating to a non LTS isn't really viable (EF Core would be used on the multiplayer servers only though, but it all is built from the same Unity project). I suspect AotHelper is failing because it considers the method signature different once its a derived class. I can't try it from the base class since the CreateGeneric method is protected. |
Hi! ✋
Context
We've been using EF Core in our Unity3D app for more than a year. In the Unity Editor (which runs .NET 4.6) EF Core 1.1.3 works great, as long as we manually add the required .NET dependencies. The UWP export (HoloLens in our case) doesn't work OOTB because the Unity's ReferenceRewriter executable fails find some dependencies. We worked around the problem by adding the EF Core DLLs later in the build pipeline, in the UWP project generated by Unity; this way the RefRewriter doesn't see any EFCore bits and doesn't fail the build. A bit of a 'hack', but hey it works. That's how we managed to use EFCore on Unity targeting UWP.
Issue
Now Unity is forcing developers to migrate to their IL2CPP scripting backend as they are about to drop .NET Scripting Backend support. Also, Unity supports .NET Standard 2 and the latest UWP SDK only in IL2CPP mode, so we basically have to migrate to IL2CPP.
However, it seems that EF Core 2.0 and IL2CPP/AOT do not go well together.
Here we provide two ways to reproduce the problem. The first one might give more information about the issue, but the second one is much faster to reproduce, though the logs won't tell you anything meaningful.
Steps to reproduce
1. By targeting iOS
Details
iOS forbids code generation and IIRC that was the primary reason Unity worked on their IL2CPP system. But we rapidly noticed that this AOT compiler can't manage to build EFCore properly as it seems to heavily rely on runtime code generation and reflection.
When trying to make EFCore work on iOS (which means by using IL2CPP), we ran into all sorts of exceptions. Here are a few of them:
NotSupportedException: /Users/builduser/buildslave/unity/build/External/il2cpp/il2cpp/libil2cpp/icalls/mscorlib/System.Reflection.Emit/AssemblyBuilder.cpp(20) : Unsupported internal call for IL2CPP:AssemblyBuilder::basic_init - System.Reflection.Emit is not supported.
Rethrow as TypeInitializationException: The type initializer for 'Microsoft.EntityFrameworkCore.Metadata.Internal.ClrAccessorFactory<Microsoft.EntityFrameworkCore.Metadata.Internal.IClrPropertySetter>' threw an exception.
ExecutionEngineException: Attempting to call method ‘Microsoft.EntityFrameworkCore.Metadata.Internal.ClrPropertySetterFactory::CreateGeneric’ for which no ahead of time (AOT) code was generated.
If necessary, I might be able to provide more detailed callstacks.
We tried many different ways to make IL2CPP compile EFCore properly but as you can see, we couldn't. One way or another, something fails, whether it's the lack of generated code ahead of time, or a forbidden API (
System.Reflections.Emit
), or something else.2. In the Editor
Details
Steps
This behaviour happens with some libraries such as Autofac and, as said, EFCore. The DLL works fine if EFCore nuget package is not installed in the "Test" DLL.
Question(s)
In the meantime, I'm also preparing to open a ticket on Unity's support. I honestly still don't know if the problems stands on EFCore's part, Unity's, or ours.
Thank you for helping!
The text was updated successfully, but these errors were encountered: