Искать на сайте Unity

Поделиться

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

Основы - набор инструментов и аргументы командной строки (этот пост).

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

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

Что такое IL2CPP?

Технология, которую мы называем IL2CPP, состоит из двух отдельных частей:

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

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

AOT компилятор

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

Утилита Il2cpp.exe принимает управляемые сборки, собранные с компилятором Mono, который поставляется с Unity, и генерирует C++ код, который мы передаем в C++ компилятор конкретной платформы.

Вы можете думать об инструментах IL2CPP так:

il2cpp toolchain smaller

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

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

Вы можете найти некоторые подсказки о том, как код libil2cpp организован глядя на файлы заголовков для libil2cpp, которые поставляются с Unity (вы найдете их в директории Editor\Data\PlaybackEngines\webglsupport\BuildTools\Libraries\libil2cpp\include на Windows, или в Contents/Frameworks/il2cpp/libil2cpp на OSX). Например, интерфейс между генерацией 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 к главной камере в сцене:

[csharp]using UnityEngine;

public class HelloWorld : MonoBehaviour {
void Start () {
Debug.Log("Hello, IL2CPP!");
}
}[/csharp]

Когда я соберу проект для WebGL, я могу использовать Process Explorer, чтобы увидеть команду Unity, используемую для запуска 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 запускает этот исполняемый файл:

"C:\Program Files\Unity\Editor\Data\MonoBleedingEdge\bin\mono.exe"

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

"C:\Program Files\Unity\Editor\Data\il2cpp/il2cpp.exe"

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

  • --copy-level=None
    • Указывает, что il2cpp.exe не следует выполнять специальные копии файлов генерируемого C++ кода.
  • --enable-generic-sharing
    • Функция уменьшения размера кода и бинарника. IL2CPP поделятся реализацией генерированных методов, когда это возможно.
  • --enable-unity-event-support
    • Специальная поддержка кода для событий Unity, доступ к которым осуществляется с помощью рефлексии.
  • --output-format=Compact
    • Создание C++ кода в формате, который требует меньше символов для имен типов и методов. Этот код трудно отлаживать, поскольку имена в коде IL не сохраняются, но часто компилируется быстрее, так как будет меньше кода для разбора компилятором C++.
  • --extra-types.file="C:\Program Files\Unity\Editor\Data\il2cpp\il2cpp_default_extra_types.txt"
    • Использует значение по умолчанию (или пустой) дополнительный файл типов. Этот файл может быть добавлен в проект Unity, чтобы знать, какие il2cpp.exe типы будут созданы во время выполнения, но не присутствуют в коде IL.

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

В итоге у нас есть два файла и одна директория:

  • "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" в Player Settings WebGL на "Full" добавляет аргументы –emit-null-checks, –enable-stacktrace, и –enable-array-bounds-check к вызову il2cpp.exe.

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

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

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

Как мы разрабатываем, тестируем и выпускаем IL2CPP

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

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

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

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

С помощью нашего сообщества мы работаем над тем, чтобы IL2CPP работал стабильно и быстро, насколько возможно. Кстати, если это интересно вам, у нас есть вакансия (просто говорю).

Дальше - больше

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

6 мая 2015 г. через Технологии | 10 мин. читать
Партнеры
Unity, логотипы Unity и другие торговые знаки Unity являются зарегистрированными торговыми знаками компании Unity Technologies или ее партнеров в США и других странах (подробнее здесь). Остальные наименования и бренды являются торговыми знаками соответствующих владельцев.