Unity не может построить проект GRPC для UWP с бэкэндом IL2CPP - PullRequest
0 голосов
/ 26 ноября 2018

Здесь или здесь для полной версии, вы можете найти пример GRPC-проекта Hello World для Unity.Только первая версия, созданная для Unity и обернутая в DLL, прекрасно работает отлично в Unity IDE и Автономная сборка .Файлы Raw Grpc.Core правильно ссылаются на все в IDE, но у них есть проблема с Marshaling.

К сожалению, он не может получить сборку для UWP с бэкэндом IL2CPP.Unity создает проект и создает проект .sln.Но Visual Studio всегда выдает LNK2001 для свойств GRPC при окончательной компиляции.

Вот первые коды ошибок:

LNK2001 unresolved external _grpccsharp_init@0
LNK2001 unresolved external _grpccsharp_shutdonw@0
LNK2001 unresolved external _grpccsharp_version_string@0
...

Хорошо, благодаря @Sunius, я углубился в это немного больше,Есть несколько моментов, которые я собираюсь добавить к вопросу:

Существует два метода ссылки на extern методы в пакете GRPC C #.Они называются static и shared libs.

internal class DllImportsFromStaticLib
{
    private const string ImportName = "__Internal";

    [DllImport(ImportName)]
    public static extern void grpcsharp_init();

    [DllImport(ImportName)]
    public static extern void grpcsharp_shutdown();

    ...
}

и

internal class DllImportsFromSharedLib
{
    private const string ImportName = "grpc_csharp_ext";

    [DllImport(ImportName)]
    public static extern void grpcsharp_init();

    [DllImport(ImportName)]
    public static extern void grpcsharp_shutdown();

    ...
}

Я пытался проверить его с общим, яполучил другой файл ошибок компоновки, который немного отличается.

LNK2001 unresolved external _dlopen@8
LNK2001 unresolved external _dlsym@8
...

В двух отдельных методах методы extern подключаются к внутреннему интерфейсу:

public NativeMethods(DllImportsFromStaticLib unusedInstance) 
{
    this.grpccsharp_init = DllImportsFromStaticLib.grpccsharp_init; 
    this.grpccsharp_shutdown = DllImportsFromStaticLib.grpccsharp_shutdonw;
    ...
}

и

public NativeMethods(DllImportsFromSharedLib unusedInstance) 
{
    this.grpccsharp_init = DllImportsFromSharedLib.grpccsharp_init; 
    this.grpccsharp_shutdown = DllImportsFromSharedLib.grpccsharp_shutdonw;
    ...
}

И какой метод будет вызван, определяется здесь:

private static NativMethods LoadNativeMethodsUnity()
{
    switch(PlatformApis.GetUnityRuntimePlatform())
    {
        case "IPhonePlayer":
            return new NativeMethods(new NativeMethods.DllImportsFromStaticLib());
        default:
            return new NativeMethods(new NativeMethods.DllImportsFromSharedLib());  
    }
}

Некоторые обновления:

Благодаря @jsmouret, в Stub.c есть файл его GrpcGithub с поддельными методами, поэтому Linker больше не жалуется на методы Grpc_init.

Следующая ошибка: dlopen, dlsym, dlerror:

Сначала я попытался использовать ту же технику, Stub, но это не помогло в этом случае, или, возможно, я сделал это неправильно.

Благодаря @Sunius, я закомментировал все "__Internal" коды импорта dll.Поэтому я не получаю никаких ошибок dlopen, dlsym и dlerror.

Следующая ошибка: это происходит изнутри приложения, а не отладчика Visual Studio.Он говорит мне: « исключение: чтобы упорядочить управляемый метод, добавьте атрибут с именем« MonoPInvokeCallback »в определение метода. »

exception: error loading the embedded resource "Grpc.Core.roots.pem"

и

exception: To marshal a managed method, please add an attribute named 'MonoPInvokeCallback' to the method definition.

После того, как я погуглил, я знаю свои варианты, но вопрос в том, для какого метода я должен это делать?!

Ответы [ 2 ]

0 голосов
/ 03 декабря 2018

Благодаря моей коллеге Алисе, @Sunius и @jsmouret, в конце grpc работает над UWP на платформе Unity, выполняя следующие шаги:

  1. Загрузка Grpc.Core папкаиз Google Grpc Github.
  2. Загрузите плагин Grpc Unity со своего официального сайта .
  3. Скопируйте папку времени выполнения в папку Grpc.Core.Пожалуйста, удалите Grpc.Core.dll, который вы получаете из Grpc Unity Plugin, так как мы используем их исходный код.
  4. Grpc должен находиться в папке Plugins in Unity, иначе он не будет распознан.
  5. Включите этот файл в папку времени выполнения.
  6. Включите заглушку также из Инспектора подключаемых модулей Unity для WSA.
  7. Найдите библиотеку времени выполнения для Windows и включитеих в WSA от инспектора плагинов Unity.

К настоящему времени вы должны получить ошибку _dlopen.

Выполните поиск в своем Unity Solution с помощью IDE для «__Internal».Там не так много мест, но закомментируйте их.Также некоторые методы, которые зависят от "__Internal", такие как dlopen и dlsym.

К настоящему времени вы больше не получаете ошибку сборки, но вам нужно заставить работать Grpc.

Найдите что-то вроде «DefaultSslRootsOverride» и прокомментируйте, как показано ниже:

internal static class DefaultSslRootsOverride
{
    const string RootsPemResourceName = "Grpc.Core.roots.pem";
    static object staticLock = new object();

    /// <summary>
    /// Overrides C core's default roots with roots.pem loaded as embedded resource.
    /// </summary>
    public static void Override(NativeMethods native)
    {
        lock (staticLock)
        {
            //var stream = typeof(DefaultSslRootsOverride).GetTypeInfo().Assembly.GetManifestResourceStream(RootsPemResourceName);
            //if (stream == null)
            //{
            //    throw new IOException(string.Format("Error loading the embedded resource \"{0}\"", RootsPemResourceName));   
            //}
            //using (var streamReader = new StreamReader(stream))
            //{
            //    var pemRootCerts = streamReader.ReadToEnd();
            //    native.grpcsharp_override_default_ssl_roots(pemRootCerts);
            //}
        }
    }
}

Найдите что-то вроде «static void HandWrite» и добавьте атрибут, например, вниже:

[MonoPInvokeCallback(typeof(GprLogDelegate))]
private static void HandleWrite(IntPtr fileStringPtr, int line, ulong threadId, IntPtr severityStringPtr, IntPtr msgPtr)
{
    try
    {
        var logger = GrpcEnvironment.Logger;
        string severityString = Marshal.PtrToStringAnsi(severityStringPtr);
        string message = string.Format("{0} {1}:{2}: {3}",
            threadId,
            Marshal.PtrToStringAnsi(fileStringPtr), 
            line, 
            Marshal.PtrToStringAnsi(msgPtr));

        switch (severityString)
        {
            case "D":
                logger.Debug(message);
                break;
            case "I":
                logger.Info(message);
                break;
            case "E":
                logger.Error(message);
                break;
            default:
                // severity not recognized, default to error.
                logger.Error(message);
                break;
        }
    }
    catch (Exception e)
    {
        Console.WriteLine("Caught exception in native callback " + e);
    }
}

Полагаю, все готово.В случае, если это не сработало для вашего UWP, дайте мне знать, может быть, я могу помочь.:)

0 голосов
/ 28 ноября 2018

Похоже, что ваш плагин использует "__Internal" P / Invoke для вызова этих собственных функций:

https://github.com/grpc/grpc/blob/befc7220cadb963755de86763a04ab6f9dc14200/src/csharp/Grpc.Core/Internal/NativeMethods.Generated.cs#L542

Однако компоновщик не может найти эти функции и, таким образом, происходит сбой.Вам следует изменить этот код, чтобы указать имя файла DLL, в котором реализованы функции, или добавить исходные файлы с определениями этих функций в проект Unity.Или, если этот путь к коду фактически не вызывается (поскольку вы сказали, что он работает на автономном проигрывателе), #ifdef его из сборки UWP.

Более подробную информацию о "__Internal" P / Invoke вы можете найти здесь:

https://docs.unity3d.com/Manual/windowsstore-plugins-il2cpp.html

...