Visual Studio 2015 зависимости времени выполнения или как избавиться от Universal CRT?

Скомпилировал пару.dll с использованием Visual Studio 2015 и попытался развернуть на некоторых старых Windows 7 / 64 бит. Попытался также угадать, какие DLL необходимы для запуска приложения, и скопировал MSVCP140.DLL & VCRUNTIME140.DLL - но приложение не смогло загрузить vs2015 dll. Начал анализировать, что не так - и обходчик зависимостей показал зависимости от следующих DLL:

API-MS-WIN-CRT-MATH-L1-1-0.DLL
API-MS-WIN-CRT-HEAP-L1-1-0.DLL
API-MS-WIN-CRT-CONVERT-L1-1-0.DLL
API-MS-WIN-CRT-STRING-L1-1-0.DLL
API-MS-WIN-CRT-STDIO-L1-1-0.DLL
API-MS-WIN-CRT-RUNTIME-L1-1-0.DLL
API-MS-WIN-CRT-FILESYSTEM-L1-1-0.DLL
API-MS-WIN-CRT-TIME-L1-1-0.DLL

Это было особенно удивительно, поскольку, насколько я понимаю, CRT отвечает за запуск dll/exe, он не предоставляет никаких услуг более высокого уровня.

Хорошо, попытался выяснить, как от них избавиться или хотя бы минимизировать.

Нашел одну статью: https://blogs.msdn.microsoft.com/vcblog/2015/03/03/introducing-the-universal-crt/

В нем упоминается о выпуске статических библиотек - поэтому я подумал, что смогу связать их и избавиться от ада зависимости *L1-1-0.DLL*, но, что бы я ни пытался - у меня ничего не получилось. Я пытался связать с libvcruntime.lib, libucrt.lib, libcmt.lib, пытался отключить с помощью опции компоновщика "/nodefaultlib:vcruntime.lib", и даже пытался добавить каталог включения $(UniversalCRT_IncludePath), а также переопределил некоторые из определения, как я пытался угадать, они работают - ни одна из моих попыток не помогла.

В качестве промежуточного решения я прибегаю к использованию Visual Studio 2013, где CRT-библиотеки DLL только два: msvcp120.dll, msvcr120.dll.

Конечно, вы, вероятно, порекомендуете установить Visual Studio 2015 во время выполнения, но одним из наших требований является поддержка отдельного исполняемого файла, который работает без какой-либо установки, поэтому дополнительная установка пока не обсуждается.

Можете ли вы порекомендовать мне что-нибудь еще, кроме как ждать Visual Studio 2017, чтобы прибыть?

6 ответов

Решение

(Обновлено 11.10.2016).

Можно избавиться от универсального CRT, связав его статически, я расскажу об этом позже, но давайте посмотрим, если вы продолжите использовать универсальный CRT как таковой.

Согласно статье https://blogs.msdn.microsoft.com/vcblog/2015/03/03/introducing-the-universal-crt/ - приложение можно запустить с помощью универсальных дистрибутивов crt dll из следующей папки:C:\Program Files (x86)\Windows Kits\10\Redist\ucrt

Всего в списке 41 файл размером 1,8 Мб. (пример для 64-битной платформы)

Конечно, этого недостаточно, вам потребуется дополнительно vcruntime140.dll и msvcp140.dll из следующей папки:C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\redist\x64\Microsoft.VC140.CRT

Таким образом, после этого вы отправите 43 дополнительных DLL-файла помимо вашего приложения.

Также возможно статически скомпилировать библиотеку ucrt внутри вашего приложения, после чего вам не понадобятся 43 dll - но будет ли статическая ссылка после ссылки или нет - зависит от вашего приложения - сколько dll и какие API используются. Как правило, после того, как ucrt будет связан с двумя разными dll, они не обязательно будут использовать одни и те же глобальные переменные - что может привести к ошибкам.

Вам нужно создать ссылку на vcruntime.lib / msvcrt.lib, но этого недостаточно - есть дополнительные _VCRTIMP= а также _ACRTIMP=определяет, какие из них нужно отключить при извлечении функций из ucrt.

Если вы используете premake5, вы можете настроить свой проект следующим образом:

defines { "_VCRTIMP="}
linkoptions { "/nodefaultlib:vcruntime.lib" }
links { "libvcruntime.lib" }

с последующим:

defines { "_ACRTIMP="}
linkoptions { "/nodefaultlib:msvcrt.lib" }
links { "libcmt.lib" }

Microsoft не документирует определения, поэтому возможно, что в будущем они могут измениться.

Помимо ваших собственных проектов, вам нужно будет перекомпилировать все статические библиотеки, которые используются в ваших проектах.

Что касается библиотек boost - мне удалось также скомпилировать boost, используя b2.exe boostrapper

boost>call b2 threading=multi toolset=msvc-14.0 address-model=64 --stagedir=release_64bit --build-dir=intermediate_64but release link=static,shared --with-atomic --with-thread --with-date_time --with-filesystem define=_VCRTIMP= define=_ACRTIMP=

При устранении неполадок со связыванием проблем - обратите внимание, что нерешенные __imp* имена функций из-за dllimport использование ключевых слов - и если вы ссылаетесь на libvcruntime.lib, у вас не должно быть никаких __imp* Рекомендации.

Я смог решить эту проблему, установив C/C++ > Code Generation > Runtime Library опция компилятора

  • Для отладки: от /MDd в /MTd
  • Для выпуска: от /MD в /MT

Это удалило все API-MS-WIN-CRT-* и dll-ссылки времени выполнения и заставили весь код CRT быть статически связанным.

Подробная информация о новом универсальном ЭЛТ VS2015 (динамическом и статическом) находится здесь: https://msdn.microsoft.com/en-us/library/abx4dbyh.aspx

Я тоже боролся со статическим связыванием решения с несколькими зависимостями компонентов / библиотек проектов, импортируя функции из различных частей MSVCRT, UCRT и Kernel. Надежда заключалась в том, что полученный EXE-файл можно было просто скопировать туда, где он был нужен (это не был продукт, который оправдывал бы полную установку MSI).

После того, как я почти сдался, я обнаружил, что лучшим решением было следовать указаниям, скрытым в объявлении Universal C Runtime, а именно:

Мы настоятельно рекомендуем не использовать статическую компоновку библиотек Visual C++ как по соображениям производительности, так и по удобству обслуживания.

Просто удалите все "специальные" опции компоновщика, которые вы пробовали, откройте /MT|/MD (Multi-Threaded CRT DLL Release|Debug) библиотеку времени выполнения, и она будет работать везде, например, на новых рабочих станциях Windows 10, серверах 2012 R2 и Windows 7). Просто установите / перераспределите MSVCRT (VC_Redist*.exe) и KB2999226 (UCRT через Центр обновления Windows), как Microsoft говорит нам сделать, потому что, как они также говорят:

Универсальный ЭЛТ является компонентом операционной системы Windows. Он входит в состав Windows 10, начиная с январского Технического предварительного просмотра, и доступен для более старых версий операционной системы через Центр обновления Windows.

Таким образом, логически единственной дополнительной зависимостью развертывания, которую наши решения C++ добавляют для клиента, является MSVCRT, потому что UCRT уже должен присутствовать на современных / хорошо обслуживаемых машинах. Конечно, это добавляет немного неопределенности; Вы не можете просто скопировать EXE и запустить на любой машине, хорошей или плохой.

Если вы создаете достойный пакет развертывания, такой как MSI, то его легко включить, если у вас есть такие инструменты, как WIX. Также следует отметить, что, поскольку в последнем SDK вы можете локально включать 40 с лишним DLL, но это не соответствует принципу обновления безопасности, поэтому я бы не стал этого делать.

Это действительно единственный поддерживаемый способ сделать это, посмотрите другой пример здесь. В этой статье также предлагается, чтобы мы ссылались на "mincore_downlevel.lib", который является важным советом, крайне важным для того, чтобы получить эти "api-ms-win*" недостающие ошибки DLL. Например:

  1. Версия Project SDK установлена ​​на 10, ссылка с mincore.lib = Работает только на Windows 10, но не на сервере 8.1/2012 R2 или Windows 7/2008 R2.
  2. Версия Project SDK установлена ​​на 8.1, ссылка с mincore.lib = Работает как на сервере Windows 10, так и на сервере 8.1/2012 R2, но не на сервере Windows 7/2008 R2.
  3. Версия Project SDK установлена ​​на 10, ссылка с mincore_downlevel.lib = Работает на всех!

В итоге:

  1. Не связывайте статически, оставьте время выполнения DLL C по умолчанию выбранным в настройках проекта.
  2. Вам не нужны старые SDK, они могут разрабатываться с последним Windows 10 SDK, но вы должны связать их с "mincore_downlevel.lib", а не "mincore.lib", если вы хотите поддерживать более старые версии Windows.
  3. Для простоты использования добавьте это в ваш targetver.h или stdafx.h, который также документирует ваш выбор (удалите другую строку):
// Libraries
#pragma comment(lib, "mincore.lib")             // Lowest OS support is same as SDK
#pragma comment(lib, "mincore_downlevel.lib")   // Support OS older than SDK

Настройка: Свойства конфигурации - Дополнительно - Использование MFC - "Использовать MFC в статической библиотеке" у меня сработало (с консольным приложением, а не с приложением MFC/ATL как таковым).

Я слишком много боролся с поиском библиотек DLL времени выполнения, необходимых для запуска приложения, созданного в Visual Studio 2015.

Здесь я обнаружил следующие вещи, которые позволяют запускать встроенное приложение VS-2015.

Примечание. Разместите версии dll в соответствии с архитектурой процессора вашей системы (x86, x64..).

Если вы не пытаетесь заменить среду выполнения своей собственной, то не имеет значения, будет ли

  • У вас включен/отключен набор текста во время выполнения
  • У вас включены/отключены исключения C++
  • Независимо от того, настроена ли ваша библиотека времени выполнения на многопоточную DLL или нет (установка ее на не-DLL по-прежнему встраивает ее в ваш двоичный файл)

Единственное, что вам нужно убедиться, это то, что вы не используете какие -либо его возможности, и Visual Studio автоматически не связывается с ним. Т.е. Никаких утверждений, никаких вызовов чего-либо в string.h или stdio.h, ничего. Все, что компилятор может заменить своими собственными внутренними функциями, допустимо, как и проверки компилятора, такие как static_assert.

Другие вопросы по тегам