Как настроить таргетинг на конкретную версию среды выполнения C++?

У нас есть очень большой проект, в основном написанный на C#, в котором есть небольшие, но важные компоненты, написанные на C++. Мы ориентируемся на RTM .NET 2.0 как на минимальную требуемую версию. До сих пор, чтобы выполнить это требование, мы позаботились о том, чтобы в нашей сборочной коробке была только RTM .NET 2.0, чтобы части C++ связывались с этой версией.

Обновление. Сборка C++, вызывающая проблему, представляет собой сборку C++ смешанного режима, загружаемую в управляемый процесс.

К сожалению, когда конфигуратор должен был что-то сделать 1 апреля, наши корпоративные ИТ-специалисты приложили огромные усилия, чтобы все исправили и обновили, и в результате все до версии 3.5 SP1 было установлено в сборочной коробке. Мы пытались удалить все, что случалось раньше, но теперь мы не можем выполнить наши минимальные требования, поскольку все, что построено на этой конкретной машине, требует .NET 2.0 SP1.

Поскольку коробка, похоже, связана с тем, что мы не можем просто удалить проблемные версии, есть ли способ собрать сборки и явно указать им использовать RTM .NET 2.0 (то есть v2.0.50727.42)? Я видел страницы, которые ссылаются на использование манифеста, но я не могу понять, как на самом деле реализовать правильный манифест и добавить его в сборки. Мой опыт связан с управляемым миром, поэтому я немного растерялся в этом.

Кто-нибудь может объяснить, как заставить эти сборки ориентироваться на сборки .NET 2.0 RTM SxS?

Спасибо!


person John Clayton    schedule 06.07.2009    source источник


Ответы (6)


Хотя я почти уверен, что ответ Кристофера и пример кода (спасибо, Кристофер!) являются частью более элегантного решения, мы были под прицелом, чтобы вывести это за дверь, и нашли очень похожее, но другое решение.

Первым шагом является создание манифеста для сборки:

<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type='win32' name='Microsoft.VC80.DebugCRT' version='8.0.50608.0' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' />
    </dependentAssembly>
  </dependency>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type='win32' name='Microsoft.VC80.CRT' version='8.0.50608.0' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' />
    </dependentAssembly>
  </dependency>
</assembly>

Затем вы должны установить для параметра «Создать манифест» значение «Нет» в разделе «Свойства конфигурации» -> «Компоновщик» -> «Файл манифеста» и установить для параметра «Встроить манифест» значение «Нет» в разделе «Свойства конфигурации» -> «Инструмент манифеста» -> «Ввод и вывод». .

Наконец, чтобы добавить новый манифест в сборку, добавьте следующую команду на этапе после сборки проекта:

mt.exe /manifest "$(ProjectDir)cppassembly.dll.manifest" /outputresource:"$(TargetDir)\cppassembly.dll";#2 -out:"$(TargetDir)\cppassembly.dll.manifest"

После создания мы можем открыть dll в Visual Studio, чтобы просмотреть манифест в RT_MANIFEST и убедиться, что он имеет наш манифест!

Когда я поместил код Кристофера в stdafx.h, он добавил его как дополнительную зависимость... манифест все еще искал версию 8.0.50727.762. Сгенерированный манифест выглядел так:

<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type="win32" name="Microsoft.VC80.DebugCRT" version="8.0.50608.0" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>
    </dependentAssembly>
  </dependency>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type="win32" name="Microsoft.VC80.DebugCRT" version="8.0.50727.762" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>
    </dependentAssembly>
  </dependency>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type="win32" name="Microsoft.VC80.CRT" version="8.0.50727.762" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>
    </dependentAssembly>
  </dependency>
</assembly>

Я не смог отследить другой переключатель, который удалял бы или очищал существующие зависимости. Мне нравится подход Кристофера больше, чем шаг после сборки, но пока это работает. Если у кого-то есть какие-либо дополнительные сведения о том, как очистить любые существующие зависимости, это было бы здорово.

Спасибо!

person John Clayton    schedule 07.07.2009
comment
Джон, мне удалось заставить это решение работать без этапа сборки (в VS 2005). В настройках проекта Manifest Tool -> Input and Output -> Embed Manifest на Yes, затем измените Output Manifest File на имя файл, который вы используете. В моем случае я поместил манифест в каталог проекта (такой же, как каталог .vcproj), включил его в файлы проекта и просто ввел имя без пути. Я подтвердил, что манифест встроен как есть, без сгенерированных зависимостей. Это решило мою проблему! Фантастика! - person Jay; 11.01.2011

да. В свойствах вашего проекта есть страница, которая указывает время выполнения. В раскрывающемся списке перечислены все доступные среды выполнения. Выберите тот, который подходит для вас. (Для VS 2008: щелкните правой кнопкой мыши проект -> свойства, вкладка "Компиляция", кнопка "Дополнительные параметры компилятора" -> целевая структура)

Мы делаем это прямо сейчас. Мы хотели бы перейти на VS 2008, но делаем это постепенно. Итак, сейчас у нас есть решение VS 2008, но все проекты по-прежнему ориентированы на .Net 2.0. Таким образом, когда мы компилируем и развертываем, нам не нужны компоненты .Net 3.5, установленные на наших тестовых блоках.

ОБНОВЛЕНИЕ:

Чтобы заставить собственную программу ссылаться на определенные версии .dll, вы, вероятно, захотите использовать что-то вроде этого:

#pragma message ("Explicit link to generate a manifest entry for MFC.")

#if defined (_DEBUG)

#pragma comment(linker, "\"/manifestdependency:type='win32' name='Microsoft.VC80.DebugMFC' version='8.0.50608.0' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b'\"")

#else

#pragma comment(linker, "\"/manifestdependency:type='win32' name='Microsoft.VC80.MFC' version='8.0.50608.0' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b'\"")

#endif

За исключением того, что вместо MFC вы должны найти правильные значения для .Net .DLL.

Разумно полагать, что у вас не может быть .Net 2.0 SP1 и .Net 2.0 на одном компьютере. Так что заставить это работать на этой коробке, вероятно, будет очень, очень болезненно. Вероятно, лучше запустить новую сборочную виртуальную машину, на которую вы можете установить старую, неисправленную платформу .Net (если вы вообще можете ее получить).

В противном случае вам нужно будет скопировать все файлы времени сборки в вашу текущую коробку, а затем внести коррективы в пути включения и библиотеки в зависимости от вашего типа сборки. Вероятно, это гораздо большая головная боль, чем оно того стоит.

person Christopher    schedule 06.07.2009
comment
Я считаю, что это работает только для проектов .Net. Я не думаю, что это работает для неуправляемого проекта C++. Я всегда считал, что Visual Studio ориентируется на последнюю версию среды выполнения при компиляции кода C++. - person Soo Wei Tan; 06.07.2009
comment
Правильно... это работает только для управляемых проектов. Хотел бы я, чтобы это было так просто для неуправляемых. :) - person John Clayton; 06.07.2009
comment
Извините, я думал, вам нужен управляемый C++. Вы можете сделать то же самое для собственного C++, выбрав SDK, на который вы ориентируетесь. Это в основном включает в себя установку правильных путей компилятора. Для VS2005 есть пакетный файл с именем vcvars.bat. Вы используете make-файлы для сборки или devenv? - person Christopher; 06.07.2009
comment
Мы используем MSBuild, который под капотом вызывает vcbuild для проектов VC. Это, безусловно, больше похоже на то, что я считаю нужным. Не могли бы вы пояснить, куда я бы поместил приведенный выше код (я не очень силен в C++)? Если я правильно понимаю ваше обновление, действительно ли этот фрагмент кода генерирует/встраивает манифест во время сборки? - person John Clayton; 06.07.2009
comment
Код находится в заголовочном файле, включенном во все единицы перевода (файлы реализации кода C++), которым он нужен. На самом деле это должно быть только в одной единице перевода для каждой .dll, но я предпочитаю просто помещать ее в соответствующий заголовок. Этот фрагмент представляет собой директиву препроцессора, которая указывает компилятору генерировать манифест во время сборки. - person Christopher; 06.07.2009

Джон действительно поставил меня на правильный путь, чтобы решить ту же проблему. Я вношу небольшое изменение в старый проект VS2005 C++ (не CLR). На моей машине разработки есть все обновления, поэтому VS2005 создавал ссылки на последние версии библиотек DLL MFC80 и MSVCx80, и исполняемый файл не запускался на целевых машинах, потому что эти версии были недоступны, и у меня нет возможности обновить эти машины. . Поэтому мне нужно контролировать зависимости assmelby в манифесте, который встроен в исполняемый файл. Похоже, это та же проблема, над которой работает Джон. Начиная с его дополнительной информации, это то, что сработало для меня.

В ProjectDir создайте файлы program.exe.debug.manifest и program.exe.release.manifest с соответствующей справочной информацией о сборке. Не добавляйте их в проект или компоновщик, пытаясь включить их обоих в каждую сборку. Затем установите свойства проекта следующим образом:

Linker-> Параметры файла манифеста

  • Создать манифест: Нет
  • Файл манифеста: пустой
  • Дополнительные зависимости манифеста: пусто
  • Разрешить изоляцию: Да

Инструменты манифеста->Параметры ввода и вывода

  • Дополнительные файлы манифеста: $(ProjectDir)$(TargetFileName).$(ConfigurationName).manifest
  • Манифесты входных ресурсов: пусто
  • Встроить манифест: Да
  • Выходной файл манифеста: (заполняется автоматически)
  • Файл манифеста ресурсов: (заполняется автоматически)
  • Создать файлы каталога: Нет
  • Файл информации о зависимостях: $(IntDir)\mt.dep (заполняется автоматически)

Из моего тестирования видно, что это не создает никаких других файлов манифеста и встраивает вашу закодированную вручную информацию манифеста в EXE как ресурс № 1 RT_MANIFTEST.

В параметрах инструмента манифеста «Выходной файл манифеста» и «Файл ресурсов манифеста» заполнялись автоматически, даже после того, как я их очистил.

Кажется, это позволяет мне контролировать зависимости сборки и запускать исполняемый файл на целевых машинах. Дополнительным преимуществом является то, что мне не пришлось использовать этап после сборки, который используется для других целей. Манипулируя параметрами Linker и Manifest Tool, можно получить тот же результат.

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

person James True    schedule 08.07.2011

Я знаю, что это взлом, но я прибегал к внешнему созданию манифеста и изменению его с помощью блокнота. В крайнем случае, это сделало свое дело для меня. В моем случае я хотел, чтобы приложение VC++ 2005 указывало на CRT .762.

Удачи! Терри

person Community    schedule 20.08.2009

Ответ Джона работает для нас. В Visual C++ 2005 компилятор создает манифесты, включающие как 762, так и 4053 версии MFC и CRT. Мы удалили версию 4053 из манифеста и перешли к ручному шагу, описанному выше. (Внутренний код фактически захватит 4053, поскольку это признанное исправление безопасности по сравнению с 762, но спецификация необходима, иначе связывание просто не удастся.)

Запись в блоге Теда (tedwvc.wordpress.com) дала нам подсказку, но его решение нам не помогло. Вот этот подход работает.

person Community    schedule 10.09.2009

Мне кажется, вам нужен CorBindToRuntime. Это позволит вам указать версию CLR, которую загружает ваш C++.

person Logan Capaldo    schedule 06.07.2009
comment
Если я что-то упустил, я не думаю, что это то, что мы ищем. CorBindToRuntime представляет собой неуправляемый API для переноса управляемого кода в неуправляемый процесс. Исполняемый файл и большая часть приложения управляются C#. Сборка, которую мы пытаемся загрузить в управляемый процесс, представляет собой сборку C++ смешанного режима. Есть что-то, что мне не хватает? - person John Clayton; 06.07.2009
comment
Ах. Большая часть взаимодействий, с которыми я имел дело, шла другим путем. Вы правы, это, вероятно, не поможет, если вы не перепроектируете приложение, чтобы иметь неуправляемый исполняемый файл, который загружает управляемый код. - person Logan Capaldo; 06.07.2009