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

Скомпилировал пару .dll с помощью Visual Studio 2015 и попытался развернуть на некоторых старых версиях Windows 7/64. Пытался также угадать, какие библиотеки необходимы для запуска приложения, и скопировал MSVCP140.DLL и VCRUNTIME140.DLL, но приложение не смогло загрузить DLL vs2015. Начал анализировать, что не так - и обходчик зависимостей показал зависимости от следующих 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/introduction-the-universal-crt/

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

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

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

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


person TarmoPikaro    schedule 04.03.2016    source источник
comment
CRT не просто запускает DLL или EXE, он обеспечивает реализацию всей библиотеки C с определенными функциями языка и компилятора. Если вы не переписываете свое приложение, чтобы ничего из этого не использовалось, вам все это понадобится.   -  person Ross Ridge    schedule 04.03.2016
comment
Хорошо, несмотря на именование - crt раньше был довольно простым стартером, отвечающим за запуск конструкторов / деструкторов - я знаю это, потому что я уже изменил его поведение - см. Здесь: codeproject.com/Articles/442784/Best-gotchas-of-Cplusplus-CLI Но так ли это, что в vs2015 они решили взорвать msvcp140.dll, msvcr140.dll на 100 маленьких dll?   -  person TarmoPikaro    schedule 04.03.2016
comment
Нет, ЭЛТ всегда был таким, как я описал. Файл crtdll.c - это всего лишь небольшая часть CRT, он также включает в себя множество других вещей, таких как реализация printf, как описано в статье Code Project, которую вы связали. Единственная разница в том, что теперь CRT разделен на отдельные библиотеки и DLL. Если вы почему они сделали это, вы можете попробовать прочитать запись блога MSDN, на которую вы указали ссылку в своем сообщении, вместе с записями блога, на которые она ссылается в начале. В качестве бонуса, если вы потратите время, чтобы прочитать его до конца, вы также найдете решение своей проблемы.   -  person Ross Ridge    schedule 05.03.2016
comment
Я действительно нашел что-то похожее на решение, но, к сожалению, оно не решает полностью мою проблему, но я опубликую его здесь в качестве ответа. В самой статье не говорится о том, как правильно перенастроить проект.   -  person TarmoPikaro    schedule 05.03.2016
comment
Это дефект в Dependency Walker, он не поддерживался в течение очень долгого времени и ничего не знает о последних нововведениях в загрузчиках Windows. Как эти форвардеры MinWin. Вам нужно прекратить его использовать. Монитор процессов SysInternals может сказать вам, почему он не может найти DLL, которая нужна вашей программе, вы можете увидеть, как программа ищет DLL, а также где она ее ищет.   -  person Hans Passant    schedule 05.03.2016
comment
С моей точки зрения, нормально, если .exe удалось успешно загрузить .dll, но этого не произошло. Кстати - я согласен с вами, что dependency walker показывает что-то странное - он показывает зависимость от API-MS-WIN-CRT - *. Dll, даже если их имена dll явно не указаны в ссылочной dll - попробуйте выполнить поиск с помощью шестнадцатеричного редактора. Поэтому я подозреваю, что загрузка VCRUNTIME140.DLL принесла также и другие библиотеки DLL, даже при этом моя dll не зависит от нее напрямую.   -  person TarmoPikaro    schedule 05.03.2016
comment
У нас есть требование иметь возможность запускать наше приложение без какой-либо установки в Windows 7/8/10. До сих пор мы поставляли crt dll вместе с другими .exe / .dll - и исполняемый файл запускался нормально. Но теперь - универсальный crt - как его перенести на Windows 7/8 - чтобы не требовалось никакой установки? Означает ли универсальный, что он будет совместим с Windows 11? Или изобретут еще одну супер универсальную совместимую портативную ЭЛТ?   -  person TarmoPikaro    schedule 29.06.2016


Ответы (6)


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

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

Это удалило все API-MS-WIN-CRT-* и ссылки на DLL среды выполнения и привело к статической привязке всего кода CRT.

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

person Ton Plooij    schedule 28.03.2016
comment
Вы тестировали это на виртуальной машине или на Windows 7? У меня этот параметр по умолчанию установлен во всех проектах - как в отладочной, так и в выпускной конфигурации, но это не решает проблемы. Самое интересное, что если вы будете искать в шестнадцатеричном редакторе строку API-MS- * - вы ее не найдете. Но у VCRUNTIME140.DLL есть эта зависимость, и я предполагаю, что она использует как-то измененную нагрузку, потому что обходчик зависимостей думает, что это моя зависимость .exe. Но VCRUNTIME140.DLL по-прежнему ссылается на API-MS * dll. Необходимо отключить зависимость VCRUNTIME140.DLL. - person TarmoPikaro; 02.04.2016
comment
Дважды проверьте настройки вашего проекта для генерации кода / MT. Я убедился, что в этом случае ссылка на vcruntime140.dll исчезает. - person Ton Plooij; 04.04.2016
comment
Дважды проверено проектами, вы правы - я использовал / MD. Но насколько я помню, / MT никогда не работал у меня успешно - вы видите, мы используем MFC, и MFC и / MT довольно хорошо борются друг с другом. Но, возможно, это было улучшено в vs2015 - может быть, я попробую еще раз, чтобы связать снова. Чувствую долгий путь разбитого стекла ... - person TarmoPikaro; 04.04.2016
comment
Хорошо, во-первых, я ошибался. Во-вторых, я был прав. MFC можно связать с помощью / MT (premake5 config flag flags {StaticRuntime}) - но / MT плохо работает с управляемым кодом, что, к сожалению, было в моем собственном коде. 2 ›cl: ошибка командной строки D8016: параметры командной строки '/ clr' и '/ MT' несовместимы - person TarmoPikaro; 05.04.2016
comment
Я считаю, что это следует выбрать как правильный ответ :) - person LPVOID; 15.04.2019
comment
На Win10 с VS2017, делая именно то, что вы предложили, я все еще получаю ту же проблему. - person kakyo; 22.08.2019
comment
Используя CMAKE с Visual Studio, я нашел эти настройки в CMakeSettings.json (мне пришлось нажать «Показать дополнительные настройки», чтобы увидеть их). - Хотя их больше одной группы, там куча настроек C_FLAGS, потом перерыв, а потом ниже настройки CXX_FLAGS. - Обязательно поменяйте их все! - person BrainSlugs83; 08.01.2021

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

Почти сдавшись, я обнаружил, что лучшим решением было следовать рекомендациям, скрытым в Объявление об универсальной среде выполнения C, в частности:

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

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

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

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

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

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

  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
person Tony Wall    schedule 31.08.2017
comment
Обратите внимание, что Microsoft специально заявляет, что двоичные файлы, которые ссылаются на MinCore.lib или MinCore_Downlevel.lib, не предназначены для работы в Windows 7, Windows Server 2008 R2 или более ранних версиях. Двоичные файлы, которые необходимо запускать в более ранних версиях Windows или Windows Server, не должны использовать MinCore.lib или MinCore_Downlevel.lib. msdn.microsoft.com/en -us / library / windows / desktop / - person Othrayte; 29.01.2018

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

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

Согласно статье https://blogs.msdn.microsoft.com/vcblog/2015/03/03/introduction-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* ссылок.

person TarmoPikaro    schedule 04.03.2016
comment
Размещенный вопрос для поддержки форума: sourceforge.net/p / boost / обсуждение / 127795 / thread / f74a4d33 / - person TarmoPikaro; 05.03.2016

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

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

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

person Nilesh Sironja    schedule 13.02.2018

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

person Den-Jason    schedule 11.03.2020
comment
Я сделал это, и мои ошибки времени выполнения типа отсутствия api-ms-win-xxx.dll превратились в ошибки linktime типа отсутствия __imp__SetBkMode. (Не спрашивайте меня, какой в ​​этом смысл.) Тогда я знал, где искать, и сразу решил свою проблему. - person adigostin; 25.10.2020

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

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

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

person G Huxley    schedule 18.01.2021