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. Например:
- Версия Project SDK установлена на 10, ссылка с mincore.lib = Работает только на Windows 10, но не на сервере 8.1/2012 R2 или Windows 7/2008 R2.
- Версия Project SDK установлена на 8.1, ссылка с mincore.lib = Работает как на сервере Windows 10, так и на сервере 8.1/2012 R2, но не на сервере Windows 7/2008 R2.
- Версия Project SDK установлена на 10, ссылка с mincore_downlevel.lib = Работает на всех!
В итоге:
- Не связывайте статически, оставьте время выполнения DLL C по умолчанию выбранным в настройках проекта.
- Вам не нужны старые SDK, они могут разрабатываться с последним Windows 10 SDK, но вы должны связать их с "mincore_downlevel.lib", а не "mincore.lib", если вы хотите поддерживать более старые версии Windows.
- Для простоты использования добавьте это в ваш 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.
- Загрузите распространяемый файл с https://www.microsoft.com/en-us/download/details.aspx?id=52685
- Поместите msvcp140d.dll, vccorlib140d.dll, vcruntime140d.dll и ucrtbased.dll.
Примечание. Разместите версии dll в соответствии с архитектурой процессора вашей системы (x86, x64..).
Если вы не пытаетесь заменить среду выполнения своей собственной, то не имеет значения, будет ли
- У вас включен/отключен набор текста во время выполнения
- У вас включены/отключены исключения C++
- Независимо от того, настроена ли ваша библиотека времени выполнения на многопоточную DLL или нет (установка ее на не-DLL по-прежнему встраивает ее в ваш двоичный файл)
Единственное, что вам нужно убедиться, это то, что вы не используете какие -либо его возможности, и Visual Studio автоматически не связывается с ним. Т.е. Никаких утверждений, никаких вызовов чего-либо в string.h или stdio.h, ничего. Все, что компилятор может заменить своими собственными внутренними функциями, допустимо, как и проверки компилятора, такие как static_assert.