Перейти к содержимому

Unity il2cpp что это

  • автор:

IL2CPP

IL2CPP (Intermediate Language To C++) is a Unity-developed scripting backend which you can use as an alternative to Mono when building projects for various platforms. When building a project using IL2CPP, Unity converts IL code from scripts and assemblies to C++, before creating a native binary file (.exe, apk, .xap, for example) for your chosen platform. Some of the uses for IL2CPP include increasing the performance, security, and platform compatibility of your Unity projects.

For more information about using IL2CPP, refer to the The Unity IL2CPP blog series and the following Unity Manual pages.

  • Building a project using IL2CPP
  • How IL2CPP works
  • Optimising IL2CPP build times

See the Scripting Restrictions page for details about which platforms support IL2CPP.

IL2CPP supports debugging of managed code in the same way as the Mono scripting backend.

• 2018–05–15 Page amended

Unity/Bolt, IL2CPP — ломает игру на Андроид, но в редакторе Unity — работает отлично

Визуальный скрипт кнопки Play

Создаю игру на Unity с помощью визуального программирования — Bolt. Если установить scripting backend — IL2CPP — игра в редакторе Unity — работает, но после билда на Андроид — не работают звуки, музыка, загрузка сцены при нажатии на кнопки. Ошибок в Unity консоле не выдаёт (development build, profiler — активны). Выше — визуальный скрипт кнопки Play (coroutine — активен, «TransitionCircle» — объект который анимирует плавную смену сцены, переменная «Scene» = название сцены, указана верно). При использовании scripting backend — Mono — всё работает отлично, в редакторе и на андроид. Mono — не позволяет использовать ARM64. Нужен — IL2CPP. Есть предложения для разрешения проблемы?

Отслеживать

задан 31 янв 2021 в 11:53

21 5 5 бронзовых знаков

Предлагаю не использовать Bolt.

31 янв 2021 в 12:00

Возможно, нужно выполнить Pre-Build: docs.unity3d.com/2019.3/Documentation/Manual/bolt-aot.html

31 янв 2021 в 14:56

ssa112112, Спасибо, это действительно решение проблемы. 3 Дня голову себе ломал, что только не пробовал.

Введение в IL2CPP

Unity продолжают совершенствовать технологию IL2CPP, а мы публикуем перевод статьи о том, как она работает.

Около года назад мы писали о будущем скриптинга в Unity. Новая технология скриптинга IL2CPP должна была обеспечить движок высокопроизводительной портативной виртуальной машиной. В январе мы выпустили нашу первую платформу на 64-битной iOS, использующую IL2CPP. С выходом Unity 5 появилась еще одна платформа – WebGL. При поддержке огромного сообщества пользователей мы выпустили множество патчей и обновлений для IL2CPP, постепенно оптимизируя компилятор и повышая быстродействие среды.

А пока мы продолжаем совершенствовать технологию IL2CPP, было бы неплохо рассказать о том, как она работает. Мы планируем написать серию статей, посвященных таким темам:

1. Основы – набор инструментов и аргументы командной строки (эта статья).
2. Экскурсия по генерируемому коду.
3. Советы по отладке генерируемого кода.
4. Вызовы методов: обычные методы, виртуальные методы и другие.
5. Реализация общего обмена.
6. Обёртки P/Invoke для типов и методов.
7. Интеграция сборщика мусора.
8. Тестирование и применение фреймворков.

В этих статьях мы обсудим некоторые особенности реализации IL2CPP. Надеюсь, эта информация вам пригодится.

Что такое IL2CPP?

Технология IL2CPP состоит из двух частей:

• компилятор Ahead-of-time (AOT);
• исполняемая библиотека для поддержки виртуальной машины.

AOT-компилятор переводит промежуточный язык (IL) из .NET-компиляторов в исходный код C++. Исполняемая библиотека предоставляет сервисы и абстракции (такие как сборщик мусора), межплатформенный доступ к потокам и файлам, а также способы реализации внутренних вызовов (неуправляемый код, напрямую изменяющий управляемые структуры данных).

AOT-компилятор

AOT-компилятор IL2CPP называется il2cpp.exe. В Windows его можно найти в директории Editor\Data\il2cpp, а в OS X – в директории Contents/Frameworks/il2cpp/build в месте установки Unity. Утилита il2cpp.exe полностью написана на языке C# и скомпилирована с помощью .NET и компиляторов Mono.

Эта утилита принимает управляемые сборки, скомпилированные Mono-компилятором, поставляемым с Unity, и генерирует код C++, который мы передаем в компилятор C++ для конкретной платформы.
Инструментарий IL2CPP можно схематически представить так:

Исполняемая библиотека

Вторая часть технологии IL2CPP – это исполняемая библиотека для поддержки виртуальной машины. Мы написали эту библиотеку почти полностью на C++ (в ней есть немного платформенного кода, но пусть это останется между нами) и назвали ее libil2cpp. Она поставляется в виде статической библиотеки, связанной с исполняемым файлом плеера, а ее простота и портативность являются одними из ключевых преимуществ технологии IL2CPP.

Вы можете получить более четкое представление об организации кода libil2cpp, глядя на файлы заголовков, поставляемых с Unity (их можно найти в директории Editor\Data\PlaybackEngines\webglsupport\BuildTools\Libraries\libil2cpp\include в Windows, или в директории Contents/Frameworks/il2cpp/libil2cpp – в OS X). Например, интерфейс между кодом C++, генерируемым il2cpp.exe, и средой libil2cpp находится в файле заголовка codegen/il2cpp-codegen.h.

Один из ключевых элементов среды – сборщик мусора. В комплект Unity 5 входит libgc, сборщик мусора Boehm-Demers-Weiser. Однако libil2cpp поддерживает и другие сборщики. Например, мы рассматриваем возможность интеграции с Microsoft GC – сборщиком с открытым исходным кодом в комплекте CoreCLR. В одной из следующих статей мы расскажем о нём подробнее.

Как выполняется il2cpp.exe?

Давайте рассмотрим на примере. Для этого я создам новый пустой проект в Unity 5.0.1 на Windows. Чтобы у нас был хотя бы один пользовательский скрипт, я добавлю к главной камере простой компонент MonoBehaviour:

При сборке для платформы WebGL я могу использовать Process Explorer, чтобы увидеть команду для запуска il2cpp.exe:

«C:\Program Files\Unity\Editor\Data\MonoBleedingEdge\bin\mono.exe» «C:\Program Files\Unity\Editor\Data\il2cpp/il2cpp.exe» —copy-level=None —enable-generic-sharing —enable-unity-event-support —output-format=Compact —extra-types.file=»C:\Program Files\Unity\Editor\Data\il2cpp\il2cpp_default_extra_types.txt» «C:\Users\Josh Peterson\Documents\IL2CPP Blog Example\Temp\StagingArea\Data\Managed\Assembly-CSharp.dll» «C:\Users\Josh Peterson\Documents\IL2CPP Blog Example\Temp\StagingArea\Data\Managed\UnityEngine.UI.dll» «C:\Users\Josh Peterson\Documents\IL2CPP Blog Example\Temp\StagingArea\Data\il2cppOutput»

Это достаточно длинная строка, поэтому давайте разберем ее по частям. Сперва Unity запускает этот исполняемый файл:

Следующий аргумент – сама утилита il2cpp.exe.

Остальные аргументы передаются il2cpp.exe, а не mono.exe. Давайте разберем и их. Во-первых, Unity передает 5 флагов il2cpp.exe:

• -copy-level=None
Указывает, что il2cpp.exe не следует выполнять специальные копии файлов генерируемого кода C++.

• -enable-generic-sharing
Уменьшает размер кода и бинарного файла. Со временем мы опубликуем процесс выполнения универсальных методов в IL2CPP.

• -enable-unity-event-support
Обеспечивает корректную генерацию кода для событий Unity, вызываемых при помощи рефлексии.

• -output-format=Compact
Генерирует код C++ в формате с меньшим количеством символов для имен типов и методов. Учитывая, что имена на промежуточном языке не сохраняются, такой код сложнее отлаживать, но зато он быстрее компилируется, поскольку компилятору C++ нужно разобрать меньше кода.

• -extra-types.file=»C:\Program Files\Unity\Editor\Data\il2cpp\il2cpp_default_extra_types.txt»
Использует стандартный пустой файл для дополнительных типов. Его можно добавить в проект Unity, чтобы il2cpp.exe знал, какие универсальные или индексируемые типы создаются во время выполнения, но не указаны в коде IL.

Стоит отметить, что этот набор аргументов командной строки для il2cpp.exe всё еще нестабилен и, скорее всего, изменится в последующих версиях.

Итак, в командной строке указаны 2 файла и 1 директория:

• «C:\Users\Josh Peterson\Documents\IL2CPP Blog Example\Temp\StagingArea\Data\Managed\Assembly-CSharp.dll»
• «C:\Users\Josh Peterson\Documents\IL2CPP Blog Example\Temp\StagingArea\Data\Managed\UnityEngine.UI.dll»
• «C:\Users\Josh Peterson\Documents\IL2CPP Blog Example\Temp\StagingArea\Data\il2cppOutput»

Утилита il2cpp.exe принимает список всех сборок IL, подлежащих конвертации. В нашем случае сюда входит мой простой скрипт MonoBehaviour, Assembly-CSharp.dll и UnityEngine.UI.dll. Обратите внимание, что здесь явно отсутствует несколько сборок. Очевидно, что мой скрипт ссылается на UnityEngine.dll, а значит нужен хотя бы mscorlib.dll, и, возможно, другие сборки. Но где они? Дело в том, что разрешение сборок происходит внутри il2cpp.exe. Их можно упомянуть в командной строке, но это необязательно. Получается, Unity нужно всего лишь указать корневые сборки (на которые не ссылаются другие сборки).

Последний аргумент командной строки il2cpp.exe – каталог, в котором создаются файлы C++. Если вам интересно, вы можете сами ознакомиться со сгенерированными файлами, но мы еще поговорим о них подробнее в следующей статье. Прежде чем открыть каталог, вам стоит выбрать опцию Development Player в настройках сборки WebGL. Это удалит аргумент -output-format=Compact и улучшит отображение имен типов и методов в коде C++.

Попробуйте поиграть с настройками Player Settings WebGL или iOS. Вы увидите различные параметры командной строки, передаваемые il2cpp.exe и отвечающие за различные этапы генерации кода. Например, задав параметру Enable Exceptions в WebGL Player Settings значение Full, вы добавите в командную строку аргументы -emit-null-checks, -enable-stacktrace и -enable-array-bounds-check.

Чего не делает IL2CPP?

Хотелось бы обратить внимание на одну сложность, которую мы решили обойти стороной и таким образом избежали многих проблем. Мы не пытались переписать стандартную библиотеку C# под IL2CPP. При создании проекта Unity с использованием IL2CPP весь код стандартных библиотек C# (mscorlib.dll, System.dll и т. д.) является точной копией кода Mono-скриптов.

Мы используем код стандартных библиотек C#, потому что он уже успел хорошо зарекомендовать себя во многих проектах. Таким образом, если где-то возникает ошибка, мы можем быть уверены, что проблема в AOT-компиляторе или исполняемой библиотеке.

Разработка, тестирование и выпуск IL2CPP

С момента первого официального релиза IL2CPP версии 4.6.1p5 в январе мы выпустили 6 полноценных обновлений и 7 патчей (для Unity 4.6 и 5.0), в которых исправили более ста ошибок.

Чтобы обеспечить непрерывную оптимизацию, мы разрабатываем обновления на базе одной версии кода. Перед каждым релизом мы передаем все изменения в конкретную релизную ветку, проводим тестирование и проверяем, все ли ошибки были успешно исправлены. Наши команды QA и Sustained Engineering прикладывают максимум усилий, чтобы разработка велась в таком темпе, и ошибки исправлялись каждую неделю.

Наше сообщество оказало нам бесценную помощь, предоставив множество полезных сообщений об ошибках. Мы очень благодарны пользователям за все отзывы, которые помогают непрерывно улучшать IL2CPP.

Для разработчиков IL2CPP тестирование стоит на первом месте. Мы часто берем за основу технику разработки через тестирование и крайне редко отправляем запросы на включение, если код не был полностью протестирован. Эта стратегия хорошо работает для таких технологий, как IL2CPP, где есть четкие входы и выходы. Это означает, что подавляющее большинство ошибок, с которыми мы сталкиваемся, являются скорее частными случаями, чем неожиданным поведением системы (например, при использовании 64-битного IntPtr в качестве 32-битного индекса массива может произойти вылет с ошибкой компилятора С++). Таким образом, мы можем быстро определять и исправлять любые баги.
При поддержке нашего сообщества мы всё время делаем IL2CPP стабильнее и производительнее.

Продолжение следует
Боюсь, я слишком часто упоминаю о следующих статьях. Просто хочется рассказать очень много, и это не уместить в одном посте. В следующий раз мы покопаемся в коде, генерируемом il2cpp.exe, и поговорим о работе компилятора C++.

IL2CPP: обобщенная реализация

В предыдущей статье из серии по IL2CPP мы рассмотрели вызовы методов в генерируемом коде C++. Теперь мы поговорим об одной из самых важных особенностей кода IL2CPP – обобщенной реализации методов, позволяющей существенно уменьшить размер исполняемого файла IL2CPP. Стоит отметить, что обобщенная реализация также используется в средах выполнения Mono и .NET. В IL2CPP она изначально не поддерживалась и была добавлена только со временем.

Итак, мы проанализируем реализацию обобщенных методов для ссылочных типов и типов значений, а также то, как на нее влияют ограничения обобщенных параметров. Не забывайте, что генерируемый код в этой статье может измениться в следующих версиях Unity. Но, как правило, мы обсуждаем подобные изменения сразу после их выхода.

Что такое обобщенная реализация?

Представьте, что вам нужно написать реализацию для класса List на C#. Будет ли эта реализация зависеть от типа T? Можно ли использовать реализацию метода Add как для List string, так и для List object? А как насчет List DateTime?

Вообще-то, плюс обобщений как раз в том, что их реализации в C# подходят для совместного использования, а значит обобщенный класс List подойдет для любого типа T. Но что если List нужно преобразовать из C# во что-то исполняемое, например, ассемблерный код, как это делает Mono, или код C++ в случае IL2CPP? Сможем ли мы тогда использовать одинаковую реализацию метода Add?

В большинстве случаев да. Как мы увидим далее в этой статье, возможность обобщенной реализации почти полностью от размера типа T. Если это ссылочный тип (string или object), его размер всегда равен размеру указателя. Если же T – тип значения (int или DateTime), его размер может варьироваться, и это немного усложняет вещи. В конечном итоге, чем больше методов имеют общую реализацию, тем меньше размер исполняемого кода.

Марк Пробст, разработчик, внедривший обобщенную реализацию в Mono, написал об этом несколько интереснейших статей. Мы не будем сильно углубляться в сам концепт, а лучше поговорим о том, как и при каких условиях он используется в IL2CPP. Думаю, эта информация сможет дать вам более полную картину о размере исполняемого файла вашего проекта.

Особенности обобщенной реализации в IL2CPP

IL2CPP поддерживает обобщенную реализацию методов для типа SomeGenericType, если T представляет собой ссылочный тип (string, object или любой пользовательский класс), целочисленный тип или enum. Для типов значений обобщенная реализация не поддерживается, поскольку их размер может варьироваться в зависимости от размера полей.

Это значит, что добавление SomeGenericType, где T – это ссылочный тип, практически не повлияет на размер исполняемого файла. С другой стороны, если T является типом значения, последствия будут более ощутимыми. В Mono и IL2CPP это работает одинаково. Но давайте перейдем непосредственно к деталям реализации.

Подготовка к работе

Я буду использовать версию Unity 5.0.2p1 на Windows для сборки проекта под WebGL. При этом я включу опцию Development Player и задам значение None для Enable Exceptions. Для начала пропишем метод драйвера, чтобы создать экземпляры обобщенных типов, которые мы и будем рассматривать:

public void DemonstrateGenericSharing() < var usesAString = new GenericType(); var usesAClass = new GenericType(); var usesAValueType = new GenericType(); var interfaceConstrainedType = new InterfaceConstrainedGenericType(); >

Затем определим типы, используемые в этом методе:

class GenericType  < public T UsesGenericParameter(T value) < return value; >public void DoesNotUseGenericParameter() <> public U UsesDifferentGenericParameter(U value) < return value; >> class AnyClass <> interface AnswerFinderInterface < int ComputeAnswer(); >class ExperimentWithInterface : AnswerFinderInterface < public int ComputeAnswer() < return 42; >> class InterfaceConstrainedGenericType where T : AnswerFinderInterface < public int FindTheAnswer(T experiment) < return experiment.ComputeAnswer(); >>

Весь код вложен в класс под названием HelloWorld, производный от MonoBehaviour. Вы можете также обратить внимание, что командная строка il2cpp.exe больше не содержит опцию -enable-generic-sharing, как в первой статье этой серии. Тем не менее, обобщенная реализация происходит, но теперь – автоматически.

Обобщенная реализация ссылочных типов

Для начала рассмотрим самый распространенный случай – ссылочные типы. В управляемом коде такие типы являются производными от System.Object, а в генерируемом коде – от Object_t. Поэтому для их представления в коде C++ можно использовать плейсхолдер Object_t*.

Давайте найдем сгенерированную версию метода DemonstrateGenericSharing. В моем проекте она называется HelloWorld_DemonstrateGenericSharing_m4. Нас интересуют определения четырех методов в классе GenericType. С помощью Ctags мы можем перейти к объявлению метода для GenericType_1__ctor_m8 (конструктора GenericType). Обратите внимание, что это объявление метода является оператором #define, сопоставляющим данный метод с методом GenericType_1__ctor_m10447_gshared.

Теперь давайте найдем объявления методов для типа GenericType. Что интересно, объявление конструктора GenericType_1__ctor_m9 также является оператором #define, связанным с той же функцией – GenericType_1__ctor_m10447_gshared!
Комментарий к коду определения GenericType_1__ctor_m10447_gshared указывает на то, что этот метод соответствует имени управляемого метода HelloWorld/GenericType`1. ctor(). Это конструктор типа GenericType object, который называется полностью обобщенным – если взять тип GenericType, то для любого ссылочного типа T реализация всех методов будет использовать версию, где T – это object.

Чуть ниже конструктора в генерируемом коде можно увидеть метод UsesGenericParameter:

extern "C" Object_t * GenericType_1_UsesGenericParameter_m10449_gshared (GenericType_1_t2159 * __this, Object_t * ___value, MethodInfo* method) < < Object_t * L_0 = ___value; return L_0; >>

В обоих случаях, где встречается обобщенный параметр T (тип возвращаемого значения и тип отдельного аргумента), в генерируемом коде используется тип Object_t*. А с учетом того, что все ссылочные типы в таком коде могут быть представлены через Object_t*, эту реализацию метода можно вызвать для любого T, являющегося ссылочным типом.

Во второй статье из этой серии я упоминал, что все определения методов в C++ являются свободными функциями. Утилита il2cpp.exe не использует наследование C++ для генерации переопределенных методов C#, однако использует его для типов. Введя в поиск «AnyClass_t», мы можем увидеть, как тип C# AnyClass выглядит в C++:

struct AnyClass_t1 : public Object_t < >; 

Учитывая, что AnyClass_t1 является производным от Object_t, мы можем просто передать ему указатель в качестве аргумента к функции GenericType_1_UsesGenericParameter_m10449_gshared.

Но что насчет возвращаемого значения? Мы не можем возвратить указатель на базовый класс там, где предполагается указатель на производный, разве не так? Взгляните на объявление метода GenericType::UsesGenericParameter:

#define GenericType_1_UsesGenericParameter_m10452(__this, ___value, method) (( AnyClass_t1 * (*) (GenericType_1_t6 *, AnyClass_t1 *, MethodInfo*))GenericType_1_UsesGenericParameter_m10449_gshared)(__this, ___value, method)

В генерируемом коде возвращаемое значение (тип Object_t*) фактически становится производным типом AnyClass_t1*. Получается, IL2CPP обманывает компилятор C++, чтобы избежать системы типов C++.

Обобщенная реализация с ограничениями

Предположим, нам нужно разрешить вызов некоторых методов для объекта типа Т, но разве использование Object_t* не будет этому препятствовать? Будет, но для начала мы должны сообщить эту идею компилятору C# с помощью обобщенных ограничений.

Взгляните еще раз на скриптовый код, а именно на InterfaceConstrainedGenericType. Этот обобщенный тип использует выражение where, чтобы тип T был производным от интерфейса AnswerFinderInterface, тем самым разрешая вызов метода ComputeAnswer. В предыдущей статье мы говорили о том, что для вызова методов интерфейса требуется поиск в таблице vtable. А поскольку метод FindTheAnswer совершает прямой вызов функции для экземпляра ограниченного типа T (представленного через Object_t*), в коде C++ может использоваться полностью обобщенная реализация.

Перейдя от реализации функции HelloWorld_DemonstrateGenericSharing_m4 к определению функции InterfaceConstrainedGenericType_1__ctor_m11, мы можем увидеть, что и этот метод является оператором #define, связанным с функцией InterfaceConstrainedGenericType_1__ctor_m10456_gshared. Чуть ниже находится реализация функции InterfaceConstrainedGenericType_1_FindTheAnswer_m10458_gshared, которая принимает аргумент Object_t* и также является полностью обобщенной. Вызов функции InterfaceFuncInvoker0::Invoke позволяет совершить вызов управляемого метода ComputeAnswer.

extern "C" int32_t InterfaceConstrainedGenericType_1_FindTheAnswer_m10458_gshared (InterfaceConstrainedGenericType_1_t2160 * __this, Object_t * ___experiment, MethodInfo* method) < static bool s_Il2CppMethodIntialized; if (!s_Il2CppMethodIntialized) < AnswerFinderInterface_t11_il2cpp_TypeInfo_var = il2cpp_codegen_class_from_type(&AnswerFinderInterface_t11_0_0_0); s_Il2CppMethodIntialized = true; >< int32_t L_0 = (int32_t)InterfaceFuncInvoker0::Invoke(0 /* System.Int32 HelloWorld/AnswerFinderInterface::ComputeAnswer() */, AnswerFinderInterface_t11_il2cpp_TypeInfo_var, (Object_t *)(*(&___experiment))); return L_0; > >

Важно помнить, что IL2CPP рассматривает любой управляемый интерфейс как System.Object. Это правило подходит для любого кода, генерируемого утилитой il2cpp.exe.

Ограничения базового класса

Кроме ограничений интерфейса C# допускает наличие ограничений базового класса. Но если IL2CPP не рассматривает базовые классы как System.Object, как в таком случае работает обобщенная реализация?

Так как базовые классы всегда являются ссылочными типами, IL2CPP использует для них полностью обобщенные методы. В любом коде, использующем поле или вызывающем метод для ограниченного типа, происходит приведение типа в C++. Опять-таки компилятор C# обеспечивает корректную реализацию обобщенного ограничения, и мы обманываем компилятор C++ касательно типа.

Обобщенная реализация типов значений

Давайте вернемся к функции HelloWorld_DemonstrateGenericSharing_m4 и взглянем на реализацию GenericType. Тип DateTime – ссылочный, поэтому GenericType не является обобщенным. Перейдем к объявлению конструктора этого типа, GenericType_1__ctor_m10. Здесь, как и в других случаях, мы видим #define, но он связан с функцией GenericType_1__ctor_m10_gshared, используемой только одним классом – GenericType.

Концептуальное осмысление обобщенной реализации

Концепция обобщенной реализации может быть достаточно сложной для понимания. Предметная область полна патологических случаев (тех же рекурсивных шаблонов). Поэтому здесь нужно выделить несколько основных принципов:

  • Реализация любого метода для обобщенного типа является обобщенной.
  • В некоторых случаях реализация методов является обобщенной только для определенного типа (например, вышеупомянутый тип с обобщенным параметром типа значения GenericType).
  • Типы с обобщенным параметром ссылочного типа используют полностью обобщенную реализацию, рассматривая параметры всех типов как System.Object.
  • Типы с параметрами двух и более типов могут быть частично обобщенными, если как минимум один из типов параметров является ссылочным.

Обобщенные методы

Обобщенная реализация используется не только для обобщенных типов, но и для обобщенных методов. Обратите внимание, что в исходном скриптовом коде метод UsesDifferentGenericParameter использует параметр другого типа, нежели класс GenericType. Но при рассмотрении обобщенной реализации для класса GenericType мы не видели этого метода. Введя в поиск «UsesDifferentGenericParameter», мы видим, что реализация этого метода находится в файле GenericMethods0.cpp:

extern "C" Object_t * GenericType_1_UsesDifferentGenericParameter_TisObject_t_m15243_gshared (GenericType_1_t2159 * __this, Object_t * ___value, MethodInfo* method) < < Object_t * L_0 = ___value; return L_0; >>

Это полностью обобщенная реализация, принимающая тип Object_t*. И хотя этот метод обобщенного типа, поведение было бы таким же для необобщенного. Можно утверждать, что il2cpp.exe всегда пытается генерировать минимальное количество кода для реализации методов с обобщенными параметрами.

Заключение

Обобщенная реализация – одно из самых важных улучшений в IL2CPP с момента ее выхода, позволяющее значительно уменьшить размер кода C++ для реализаций методов с одинаковым поведением. Мы продолжаем искать решения для уменьшения размера бинарных файлов и пытаемся использовать больше преимуществ и возможностей обобщенной реализации.

В следующей статье мы поговорим о генерации оберток p/invoke, а также о маршалинге типов между управляемым и неуправляемым кодом.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *