Microsoft net native runtime что это
Создание собственных двоичных файлов
Метаданные, описывающие сборку, ее зависимости, типы, которые она содержит, и их члены. Метаданные используется для отражения и доступа через позднее связывание, а также в некоторых случаях для средств компиляции и построения.
Код реализации. Он состоит из кодов операций промежуточного языка (IL). Во время выполнения JIT-компилятор преобразует его в машинный код для целевой платформы.
В дополнение к основной сборке приложения для приложения требуется следующее:
Все дополнительные библиотеки классов и сборки сторонних производителей, необходимые приложению. Эти сборки точно так же включают метаданные, описывающие сборку, ее типы и члены, а также IL-код, который реализует все члены типов.
Обратите внимание, для успешного выполнения приложения должны присутствовать: вся среда CLR, метаданные, IL-код для всех типов в сборках, специфичных для приложения, сторонние сборки и системные сборки.
JIT-компиляция
Так как входные данные .NET Native — промежуточный язык (IL) и метаданные, записанные в сборки управляемого кода, то вы по-прежнему можете выполнять создание собственного кода или другие пользовательские операции посредством событий "перед сборкой" и "после сборки" или путем изменения файла проекта MSBuild.
Везде, где возможно, делается попытка исключить все метаданные.
.exe — исполняемый файл-заглушка, который просто передает управление Специальному Main экспорту в .dll.
mrt100_app.dll — оптимизированная среда выполнения, которая предоставляет сервисы реального времени, такие как сборка мусора.
APPX-манифестом приложения регистрируются все зависимости. Помимо EXE-файла приложения, библиотеки DLL и среды выполнения mrt100_app.dll, которые входят непосредственно в APPX-пакет, пакет включает два дополнительных файла:
msvcr140_app.dll — библиотека языка C времени выполнения (CRT), используемая mrt100_app.dll. Она включается по ссылке платформы в пакете.
mrt100.dll. Эта библиотека содержит функции, которые могут повысить производительность библиотеки mrt100_app.dll, хотя ее отсутствие не препятствует функционированию mrt100_app.dll. Она загружается из папки system32 на локальном компьютере, если там она имеется.
динамический вызов или вызов посредством позднего связывания;
сериализация и десериализация;
Различия настроек компиляции в отладке и релизе
Локальная нативная компиляция с релизной конфигурацией позволяет вам протестировать приложение в окружении, близком к тому, что будет у конечного пользователя. Важно регулярно тестировать в таком режиме по мере разработке.
Все три архитектуры выбраны по умолчанию
Важно отметить, что вы по-прежнему можете собирать AnyCPU-библиотеки и использовать соответствующие DLL в вашем UWP-приложении. Эти компоненты будут скомпилированы в бинарные библиотеки под соответствующие архитектуры, указанные в настройках проекта.
Пакет .appxupload отправляется в магазин; папка Test содержит пакет appx для локальной устровки
Два следствия из этого: первое, вы как разработчик более не имеете доступа к номеру ревизии вашего приложения (четвертое число). Магазин резервирует это число как способ версионирования пакета приложения, если по какой-либо причине потребуется перекомпиляция в облаке. Не беспокойтесь, вы по-прежнему можете управлять тремя другими числами.
Выберите “Yes” для загрузки в магазин
Когда вы используете помощника для создания пакетов приложения, вам нужно выбрать “Yes” в ответ на вопрос Visual Studio, хотите ли вы создать пакет для загрузки в магазин. Я также рекомендую выбрать “Always” для опции “Generate app bundle”, что приведет к созданию единого файла .appxupload, готового для загрузки. Полная инструкция по созданию пакетов для магазина доступна в статье «Пакетирование универсальных приложений Windows для Windows 10».
- Регулярно тестируйте ваше приложение в режиме релиза
- Убедитесь, что вы оставляете номер ревизии пакета как 0. Visual Studio не даст вам его изменить, но также не стоит это делать в других редакторах.
- Загружайте в магазин только .appxupload, собранные в процессе создания пакета для магазина, если вы загрузите .appx для UWP-приложения, вы получите ошибку в магазине.
Известные проблемы и способы решения
Подводя итоги
Текст объемный и рассчитан на:
Примеры процессов выполнения описаны для ОС Windows, но работают по тому же принципу и на других ОС (с учетом различных расширений исполняемых файлов и нативных библиотек).
0. Pay-for-Play
BCL располагается в GAC, откуда приложения загружают необходимые для работы зависимости.
Примеры компонентов, которые поставляются через NuGet:
Этот подход называется «pay-for-play»; другими словами, приложения загружают только ту функциональность, которая им необходима, но каждая такая функциональность содержится в отдельной сборке.
1. FDD vs SCD
- Portable (Framework-dependent deployment — FDD)
- Standalone (Self-contained deployment — SCD)
В Standalone (SCD)-приложении все компоненты для выполнения (CoreCLR, CoreFX), а также сторонние библиотеки, то есть абсолютно все зависимости, поставляются вместе с самим приложением (чаще всего в одной папке).
Важно понимать, что Standalone-приложение привязано к определенной ОС и архитектуре (например, Windows 7 x64 или OSX 10.12 x64). Такой идентификатор называется Runtime identifier (RID). Для каждой ОС/архитектуры существует своя версия библиотеки Core CLR (и прочих нативных компонентов), поэтому для Standalone-приложений на этапе компиляции в свойстве RuntimeIdentifier нужно указывать параметры целевой системы (RID).
Файлы фреймворка(-ов) хранятся в папке C:\Program Files\dotnet\shared.
Можно установить несколько версий фреймворка:
Для выполнения Portable-приложения необходимо запустить хост-процесс dotnet.exe и передать ему в качестве аргумента путь к управляемой сборке.
«C:\Program Files\dotnet» добавляется к значению переменной среды PATH, благодаря чему Portable-приложения теперь могут запускаться из командной строки:
Этот файл является обязательным для Portable-приложений.
Уменьшение количества файлов объясняется тем, что в Core FX 1.0 отсутствовали многие библиотеки, поэтому они шли в составе приложения, как обычные зависимости. В Core FX 2.0 эти сборки были добавлены, поэтому они больше не поставляются с приложением, а берутся из папки фреймворка.
Наблюдается картина, противоположная Portable-приложениям — чем больше становится Core FX, тем больше файлов поставляется с приложением.
Рекомендации по выбору типа развертывания
5. Runtime Configuration Files
dotnet.exe ([AppName].exe) использует файл [AppName].deps.json для определения абсолютных путей всех зависимостей приложения при его запуске.
Структура [AppName].deps.json:
Секция targets определяет платформу и дерево зависимостей для нее в формате
[ID зависимости (пакета)]/[версия]: dependencies: < список зависимостей (пакетов) данного пакета >,
относительные пути к управляемым и нативным файлам данного пакета
>
Рассмотрим подробнее содержимое файла deps.json Standalone-приложения:
В свойстве dependencies перечислены зависимости (пакеты) конкретного пакета.
Свойство runtimeTargets используется в deps-файле Portable-приложения и определяет пути файлов библиотек для конкретного RID. Такие RID-specific библиотеки поставляются вместе с Portable-приложением в папке runtimes.
Свойства runtime и native содержат относительные пути управляемых (managed) и нативных библиотек соответственно. Свойство resources содержит относительные пути и локали локализованных сборок-ресурсов.
Пути относительны к NuGet package cache, а не deps-файлу.
Добавить сторонний deps-файл можно передав значение аргумента --additional-deps или переменную среды DOTNET_ADDITIONAL_DEPS.
Такая возможность доступна только для Portable приложений.
Когда dotnet.exe (MyApp.exe) определяет пути зависимостей приложения, для каждой отдельной библиотеки составляется список из runtime- и native-путей.
6.1. Запуск приложения
выполняется при помощи мультплексора (muxer) из командной строки (одинаково на любой ОС).
6.2. [corehost] Поиск и загрузка Framework Resolver (hostfxr.dll)
На этом этапе dotnet.exe идет в папку [own directory]/host/fxr/. Для Portable-приложений эта библиотека расположена в общей папке C:\Program Files\dotnet\host\fxr\[FXR version]\hostfxr.dll. Если версий будет несколько, dotnet.exe будет всегда использовать последнюю.
После загрузки hostfxr.dll (Framework Resolver) процесс запуска переходит в рамки этой библиотеки.
6.3. [hostfxr] Определение режима выполнения (standalone, muxer, split/FX)
Первая задача hostfxr — определить режим, в котором будет работать хост процесс и таким образом тип приложения — Portable (FDD) или Standalone (SCD). В Portable (FDD)-режиме он также определяет: это запускаемое приложение или команда SDK.
— если среди аргументов есть такой, значение которого оканчивается на .dll или .exe — процесс запуска продолжится в режиме выполнение указанного файла. Если такого аргумента нет, управление будет передано SDK. Для этого из папки [own directory]\sdk\[version] (если такая существует) будет запущен dotnet.dll (как Portable приложение), и этой сборке будут переданы аргументы текущего хост процесса.
Алгоритм проверки очень простой — если в папке, откуда был запущен мультиплексор [AppName].exe (в нашем случае dotnet.exe), отсутствует coreclr.dll или [AppName].dll, то приложение Portable. Если один из этих двух файлов существует, то далее идет проверка — приложение Portable (split/FX) или Standalone. Если существует [AppName].dll, то приложение Standalone, иначе — Portable (split/FX).
Запуск Portable-приложения может также осуществляться в так называемом Exec mode.
Для этого команда запуска первым аргументом должна содержать exec C:\> dotnet exec . .
При запуске в таком режиме можно явно указать пути к файлам конфигурации:
--depsfile
--runtimeconfig
которые будут использованы вместо файлов в папке приложения.
На текущем этапе hostfxr определяет (по данным файла конфигурации), является ли приложение Portable или Standalone.
При выборе версии учитывается параметр Roll Forward On No Candidate Fx, который указывает строгость соответствия заданной версии и имеющихся на машине.
6.5. [hostfxr] Поиск и загрузка hostpolicy.dll
На текущем этапе всё готово для определения путей runtime-компонентов. Этой задачей занимается библиотека hostpolicy.dll, которая называется Host library.
Если файл не был найден на предыдущем этапе, hostpolicy.dll будет найдено в папке фреймворка.
Как только опеределена hostpolicy.dll, hostfxr загружает эту библиотеку и передает ей управление.
6.6. [hostpolicy] Определение списка зависимостей
Библиотека hostpolicy.dll отвечает за определение абсолютных путей всех зависимостей приложения.
Прежде всего hostpolicy создаст компонент под названием Dependencies Resolver, который в свою очередь загрузит два deps-файла — файл фреймворка и файл приложения.
Сперва загружается список из deps-файл фреймворка, где будут определены такие зависимости, как CoreCLR и библиотеки CoreFX. Затем список из deps-файла приложения, в котором указаны сборки нашего приложения и их зависимости.
Для каждого deps-файла Dependency Resolver составляет список всех зависимостей для указанной runtimeTarget.
Для каждого пакета сначала составляется список файлов из всех секций runtimeTargets (RID specific зависимости), далее — список всех файлов из секций native и runtime. Такой объединенный список относительных путей всех зависимостей в условном формате
ID пакета — RID — тип asset'а (runtime, native) — пути к файлам называется Target assets.
После того, как были составлены эти два списка файлов зависимостей (RID и не RID), выполняется процесс под названием Reconciling libraries with targets (согласования). Он заключается в том, что для каждого пакета из секции libraries проверяется, существует ли RID specific-файлы, которые должны переопределить обычные.
6.7. [hostpolicy] Определение путей TPA, Core CLR и CLR Jit
Далее Dependency resolver составляет список абсолютных путей файлов управляемых сборок — зависимостей приложения. Этот список называется TPA (Trusted Platform Assemblies) и передается Core CLR для настройки AppDomain. Также составляется список абсолютных путей директорий, в которых находятся остальных файлы зависимостей (кроме coreclr, corejit).
Определение абсолютных путей управляемых сборок происходит путем поиска файлов в Probe paths (путей зондирования). По умолчанию их два — папка фреймворка и папка приложения, и они основаны на расположении deps-файлов. Также можно добавить дополнительные пути:
1) передав аргумент --additionalprobingpath, например
--additionalprobingpath %UserProfile%\\.nuget\\packages
В папке фреймворка и приложения наличие файла проверятся (при условии, что он был указан в соответствующем deps-файле) без учета относительного пути, в остальных директориях с учетом относительно пути, потому что эти директории рассматриваются как кеш NuGet-пакета.
- папка приложения;
- папка фреймворка
- Probe paths
После составления списка TPA, определяются пути CoreCLR и CLRJit.
При отсутствии deps-файла приложения, dotnet.exe вначале попытается найти эти библиотеки в [app directory]\lib\. При обычном выполнении пути берутся из папки фреймворка (отбросив относительный путь и взяв только имя файла).
Устанавливаются следующие настройки CoreCLR:
- TRUSTED_PLATFORM_ASSEMBLIES — список обсолютных путей всех управляемых библиотек приложения.
- NATIVE_DLL_SEARCH_DIRECTORIES — абсолютные пути директорий, где найдены нативные зависимости.
- PLATFORM_RESOURCE_ROOTS — абсолютные пути директорий, где найдены зависимости-ресурсы
- AppDomainCompatSwitch — константа «UseLatestBehaviorWhenTFMNotSpecified».
- APP_CONTEXT_BASE_DIRECTORY — папка приложения.
- APP_CONTEXT_DEPS_FILES — абсолютные пути deps-файлов приложения и фреймворка.
- FX_DEPS_FILE — абсолютный путь deps-файла фреймворка.
- PROBING_DIRECTORIES — дополнительные пути зондирования (если они были указаны).
Процесс запуска Standalone-приложения отличается от Portable только начальным этапом, а также местоположением компонентов, которые по умолчанию должны располагаться в папке приложения.
7.2. Процесс запуска
происходит так же, как у Portable-приложения, за исключением того, что существует только один deps-файл и все зависимости ищутся в папке приложения или по указанным --additionalprobepaths.
- Open source и ориентированность на сообщество GitHub.
- Кроссплатформенная реализация.
- Поддержка использования специфических платформозависимых возможностей, таких как Windows Forms и WPF под Windows, а также нативных привязок (bindings) к каждой нативной платформе из Xamarin.
- Высокая производительность.
- Side-by-side инсталляция.
- Маленький размер файлов проектов (SDK-стиль).
- Интерфейс командной строки (CLI) с широкими возможностями.
- Интеграция с Visual Studio, Visual Studio for Mac и Visual Studio Code.
Исполняющие среды
Высокая производительность и продуктивность
JIT-компиляторы хорошо подходят для долго работающих облаков и клиентских сценариев. Они способны генерировать код, учитывающий особенности аппаратной конфигурации, в том числе специфические процессорные инструкции. Также JIT может заново генерировать методы во время исполнения, эта методика позволяет компилировать с высокой скоростью, в то же время создавая тонко настроенную версию кода, если какие-то методы используются часто.
Инструменты разработчиков — ещё одна сфера, в которой JIT прекрасно себя зарекомендовала, например, dotnet watch или режим “edit and continue”. Для работы инструментов часто требуется многократно компилировать и загружать код в одном и том же процессе без перезапуска, и делать это нужно очень быстро.
Быстрый запуск, низкое потребление ресурсов процессора (footprint) и уменьшение потребления памяти
Есть два типа AOT-решений:
- Требующие полной AOT-компиляции.
- Решения, большая часть кода которых AOT-скомпилирована, но всё же позволяющие использовать JIT или интерпретатор для таких паттернов кода, которые не дружат с AOT (например, дженерики).
AOT-компиляция останется необходимой для iOS, WebAssembly и некоторых игровых приставок. Мы сделаем её опциональной для приложений, которые встраиваются в технику (appliance-like), для которых требуется быстрый запуск и/или низкое потребление ресурсов процессора.
Основы и схожие требования
Для нас критически важно продолжать развиваться как платформа со средствами управления запуском, производительностью, потреблением памяти, надёжностью и диагностики. В то же время целесообразно сосредоточить наши усилия. Мы станем больше работать над повышением производительности и надежности в CoreCLR, а также над улучшением запуска и снижением размера файлов компиляторе Mono AOT. Нам это кажется хорошим сочетанием. Производительность и надежность идут рука об руку, как и скорость запуска со снижением размера файлов.
В улучшение одних характеристик целесообразно вкладывать разные ресурсы, а в улучшение других — нет.
Рождение проекта
Теперь мы двигаем проект как единая команда. С декабря мы далеко продвинулись в нескольких проектах:
Заключение
разрабатывайте приложение универсальная платформа Windows (UWP)и протестируйте отладочные сборки приложения, чтобы убедиться, что оно работает правильно.
Вручную разрешите отсутствующие метаданные и повторяйте шаг 3 до тех пор, пока все вопросы не будут разрешены.
Шаг 1. Разработка и тестирование отладочных сборок приложения UWP
При разработке нового приложения или миграции существующего выполняется тот же процесс, что и для любого приложения Windows.
При разработке приложения, обратите внимание на любое использование сериализации или отражения в коде.
Шаг 2. Обработка дополнительных операций использования отражения и сериализации
Файл директив среды выполнения служит для определения метаданных, которые понадобятся вашему приложению во время выполнения. В некоторых случаях версии этого файла по умолчанию может быть достаточно. Однако для кода, в котором используется сериализация или отражение, могут потребоваться дополнительные записи в файле директив среды выполнения.
Сериализация
Существует две категории сериализаторов и обе могут потребовать дополнительных записей в файле директив среды выполнения:
сериализаторы, работающие без использования отражения. сериализаторы из библиотеки классов .NET Framework, например, DataContractSerializer, DataContractJsonSerializerи классы XmlSerializer не используют отражение. Тем не менее, они требуют генерировать код на основе объекта для сериализации или десериализации. Дополнительные сведения см. в разделе "Сериализаторы Microsoft" в Serialization and Metadata.
Сериализаторы сторонних поставщиков. Библиотеки сериализации сторонних поставщиков, наиболее распространенной из которых является сериализатор Newtonsoft JSON, обычно работают на основе отражения и требуют выполнения записей в файл *. rd.xml файл для поддержки сериализации и десериализации объектов. Дополнительные сведения см. в разделе "Сериализаторы сторонних поставщиков" в Serialization and Metadata.
Методы, основанные на отражении
В некоторых случаях использование отражения в коде не очевидно. Некоторые общие интерфейсы API или шаблоны программирования не считаются частью API-интерфейса отражения, но используют отражение для успешного выполнения. К ним относятся следующие методы создания экземпляров типов и методы создания методов:
Дополнительные сведения см. в разделе APIs That Rely on Reflection.
Имена типов в файлах директив среды выполнения должны быть полными. Например, файл должен определять "System.String" вместо "String".
Шаг 3. Развертывание и тестирование выпускаемых сборок приложения
Если приложение работает неправильно (особенно в случаях, когда оно создает исключения MissingMetadataException или MissingInteropDataException во время выполнения), следуйте инструкциям в следующем разделе. Шаг 4. разрешение отсутствующих метаданных вручную. Включение исключений первого шанса может помочь в обнаружении этих ошибок.
Шаг 4. Устранение проблем с отсутствующими метаданными вручную
Укажите директивы среды выполнения на высоком уровне, чтобы ваше приложение было устойчиво к изменениям кода. Рекомендуется добавить директивы среды выполнения на уровне пространства имен и типов, а не на уровне членов. Обратите внимание, что может потребоваться компромисс между устойчивостью и большими по размеру двоичными файлами с более длительным временем компиляции.
При устранении исключений, связанных с отсутствующими метаданными, обратите внимание на следующие моменты:
Что пыталось выполнить приложение перед возникновением исключения?
- Например, была ли это привязка данных, сериализация и десериализация данных или прямое использование API-интерфейса отражения?
Это изолированный случай или вы считаете, что эта же проблема возникнет с другими типами?
- Например, исключение MissingMetadataException возникает при сериализации типа в объектной модели приложения. Если известны другие типы, которые будут сериализованы, можно одновременно добавить директивы среды выполнения для этих типов (или для их содержащих пространств имен, в зависимости от того, насколько хорошо организован код).
Можно ли переписать код так, чтобы он не использовал отражение?
Например, использует ли код ключевое слово dynamic , если известно, какой должен быть тип?
Вызывает ли код метод, зависящий от отражения, когда доступен несколько лучший вариант?
Конкретные примеры обработки исключений и других проблем, возникающих при тестировании приложения, см. в:
Читайте также: