Основные сведения о создании манифестов для программ на C/C++
Манифест — это XML-документ, который однозначно идентифицирует сборку. Он содержит сведения, используемые для привязки и активации, таких как классы COM, интерфейсы и библиотеки типов. Манифест может быть внешним XML-файлом или ресурсом, внедренным в приложение или сборку. Манифест изолированного приложения используется для управления именами и версиями общих параллельных сборок, к которым приложение должно привязаться во время выполнения. Манифест параллельной сборки задает зависимости от имен, версий, ресурсов и других сборок.
Существует два способа создания манифеста для изолированного приложения или параллельной сборки. Во-первых, автор сборки может вручную создать файл манифеста, следуя правилам и требованиям именования. Дополнительные сведения см . в справочнике по файлам манифеста. Кроме того, если программа зависит только от сборок MSVC, таких как CRT, MFC, ATL или другие, компоновщик может автоматически создать манифест.
Заголовки библиотек MSVC содержат сведения о сборке и когда библиотеки включены в код приложения, эта информация о сборке используется компоновщиком для формирования манифеста для окончательного двоичного файла. По умолчанию компоновщик не внедряет файл манифеста в двоичный файл. Наличие манифеста в качестве внешнего файла может подходить не для всех сценариев. Например, рекомендуется, чтобы частные сборки имели внедренные манифесты. В сборках командной строки, таких как те, которые используют NMAKE для сборки кода, можно использовать /MANIFEST:EMBED
параметр компоновщика для внедрения манифеста. Кроме того, манифест можно внедрить с помощью средства манифеста. Дополнительные сведения см. в разделе "Создание манифеста" в командной строке. При сборке в Visual Studio манифест можно внедрить, задав свойство для средства манифеста в диалоговом окне "Свойства проекта", как описано в следующем разделе.
Создание манифестов в Visual Studio
Вы можете сообщить Visual Studio создать файл манифеста для определенного проекта в диалоговом окне страниц свойств проекта. В разделе "Свойства конфигурации" выберите файл> манифеста компоновщика>. По умолчанию свойства проекта новых проектов задаются для создания файла манифеста. Однако можно отключить создание манифеста для проекта с помощью свойства Generate Manifest проекта. Если для этого свойства задано значение "Да", создается манифест для проекта. В противном случае компоновщик игнорирует сведения о сборке при разрешении зависимостей кода приложения и не создает манифест.
Система сборки в Visual Studio позволяет внедрять манифест в окончательный двоичный файл приложения или создавать его как внешний файл. Это поведение управляется параметром Внедрить манифест в диалоговом окне Свойства проекта. Чтобы задать это свойство, откройте узел Инструмент манифеста, а затем выберите Вход и выход. Если манифест не внедрен, он создается как внешний файл и сохраняется в том же каталоге, что и окончательный двоичный файл. Если манифест внедрен, Visual Studio внедряет окончательные манифесты с помощью следующего процесса.
После компиляции исходного кода в объектные файлы компоновщик собирает сведения о зависимых сборках. Хотя он связывает окончательный двоичный файл, компоновщик создает промежуточный манифест, который используется позже для создания окончательного манифеста.
После завершения промежуточного манифеста и связывания средство манифеста объединяет окончательный манифест и сохраняет его в виде внешнего файла.
Затем система сборки проекта определяет, отличается ли информация в манифесте, сгенерированном инструментом манифеста, от той, которая содержится в манифесте, уже внедренном в двоичный файл.
Если манифест, внедренный в двоичный файл, отличается от манифеста, созданного средством манифеста, или двоичный файл не содержит внедренный манифест, Visual Studio вызывает компоновщик еще раз, чтобы внедрить внешний файл манифеста в двоичный файл в качестве ресурса.
Если манифест, внедренный в двоичный файл, совпадает с манифестом, созданным средством манифеста, сборка продолжает выполнять следующие действия сборки.
Манифест внедрен в последний двоичный файл в виде текстового ресурса. Его можно просмотреть, открыв последний двоичный файл в Visual Studio. Чтобы убедиться, что манифест указывает на правильные библиотеки, выполните действия, описанные в разделе "Общие сведения о зависимостях приложения Visual C++". Или следуйте рекомендациям, описанным в статье по устранению неполадок.
Создание манифеста в командной строке
При создании приложений C/C++ из командной строки с помощью NMAKE или аналогичных средств манифест создается после обработки всех файлов объектов компоновщика и создания окончательного двоичного файла. Компоновщик собирает сведения о сборке, хранящиеся в объектных файлах, и объединяет эту информацию в окончательный файл манифеста. По умолчанию компоновщик создает файл с именем <binary_name>.<extension>.manifest
для описания окончательного двоичного файла. Компоновщик может внедрить файл манифеста в двоичный файл, указав /MANIFEST:EMBED
параметр компоновщика.
Существует несколько других способов внедрения манифеста в окончательный двоичный файл, например использование средства манифеста (mt.exe
) или компиляция манифеста в файл ресурсов. При внедрении манифеста необходимо следовать определенным правилам, чтобы включить такие функции, как добавочное связывание, подпись и изменение и продолжение. Эти правила и другие параметры рассматриваются в следующем разделе.
Внедрение манифеста в приложение C/C++
Мы рекомендуем внедрить манифест приложения или библиотеки в окончательный двоичный файл. Этот подход гарантирует правильное поведение среды выполнения в большинстве сценариев. По умолчанию Visual Studio пытается внедрить манифест при сборке проекта. Однако если вы создаете приложение с помощью NMAKE, необходимо внести некоторые изменения в файл makefile. В этом разделе показано, как изменить файлы makefile таким образом, чтобы манифест автоматически внедрялся в конечный двоичный файл.
Два подхода
Существует два способа внедрения манифеста в приложение или библиотеку.
Если вы не выполняете добавочную сборку, вы можете напрямую внедрить манифест с помощью командной строки, аналогичной следующему этапу после сборки:
mt.exe -manifest MyApp.exe.manifest -outputresource:MyApp.exe;1
or
mt.exe -manifest MyLibrary.dll.manifest -outputresource:MyLibrary.dll;2
Используйте значение 1 для файла EXE и 2 для библиотеки DLL.
Если вы выполняете добавочную сборку, выполните следующие действия:
Свяжите двоичный файл, чтобы создать
MyApp.exe.manifest
файл.Преобразуйте манифест в файл ресурсов.
Повторное связывание (добавочное) для внедрения ресурса манифеста в двоичный файл.
В приведенных ниже примерах показано, как изменить файлы makefile для применения обоих методов.
Файлы makefile (до изменения)
Рассмотрим скрипт NMAKE для MyApp.exe
простого приложения, созданного из одного файла:
# build MyApp.exe
!if "$(DEBUG)" == "1"
CPPFLAGS=$(CPPFLAGS) /MDd
LFLAGS=$(LFLAGS) /INCREMENTAL
!else
CPPFLAGS=$(CPPFLAGS) /MD
!endif
MyApp.exe : MyApp.obj
link $** /out:$@ $(LFLAGS)
MyApp.obj : MyApp.cpp
clean :
del MyApp.obj MyApp.exe
Если этот скрипт выполняется без изменений в Visual Studio, он успешно создает MyApp.exe
. Он также создает внешний файл MyApp.exe.manifest
манифеста для использования операционной системой для загрузки зависимых сборок во время выполнения.
Скрипт NMAKE для MyLibrary.dll
выглядит примерно так:
# build MyLibrary.dll
!if "$(DEBUG)" == "1"
CPPFLAGS=$(CPPFLAGS) /MDd
LFLAGS=$(LFLAGS) /DLL /INCREMENTAL
!else
CPPFLAGS=$(CPPFLAGS) /MD
LFLAGS=$(LFLAGS) /DLL
!endif
MyLibrary.dll : MyLibrary.obj
link $** /out:$@ $(LFLAGS)
MyLibrary.obj : MyLibrary.cpp
clean :
del MyLibrary.obj MyLibrary.dll
Файлы makefile (после изменения)
Чтобы создать внедренные манифесты, необходимо внести четыре небольших изменения в исходные файлы makefile. MyApp.exe
Для файла makefile:
# build MyApp.exe
!include makefile.inc
#^^^^^^^^^^^^^^^^^^^^ Change #1. (Add full path if necessary.)
!if "$(DEBUG)" == "1"
CPPFLAGS=$(CPPFLAGS) /MDd
LFLAGS=$(LFLAGS) /INCREMENTAL
!else
CPPFLAGS=$(CPPFLAGS) /MD
!endif
MyApp.exe : MyApp.obj
link $** /out:$@ $(LFLAGS)
$(_VC_MANIFEST_EMBED_EXE)
#^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Change #2
MyApp.obj : MyApp.cpp
clean :
del MyApp.obj MyApp.exe
$(_VC_MANIFEST_CLEAN)
#^^^^^^^^^^^^^^^^^^^^^^^^ Change #3
!include makefile.target.inc
#^^^^^^^^^^^^^^^^^^^^^^^^^ Change #4. (Add full path if necessary.)
Для файла makefile библиотеки MyLibrary.dll:
# build MyLibrary.dll
!include makefile.inc
#^^^^^^^^^^^^^^^^^^^^ Change #1. (Add full path if necessary.)
!if "$(DEBUG)" == "1"
CPPFLAGS=$(CPPFLAGS) /MDd
LFLAGS=$(LFLAGS) /DLL /INCREMENTAL
!else
CPPFLAGS=$(CPPFLAGS) /MD
LFLAGS=$(LFLAGS) /DLL
!endif
MyLibrary.dll : MyLibrary.obj
link $** /out:$@ $(LFLAGS)
$(_VC_MANIFEST_EMBED_DLL)
#^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Change #2.
MyLibrary.obj : MyLibrary.cpp
clean :
del MyLibrary.obj MyLibrary.dll
$(_VC_MANIFEST_CLEAN)
#^^^^^^^^^^^^^^^^^^^^^^^^ Change #3.
!include makefile.target.inc
#^^^^^^^^^^^^^^^^^^^^^^^^^ Change #4. (Add full path if necessary.)
Теперь файлы makefile включают два файла, которые выполняют реальную работу, makefile.inc
и makefile.target.inc
.
Создайте и скопируйте makefile.inc
в него следующее содержимое:
# makefile.inc -- Include this file into existing makefile at the very top.
# _VC_MANIFEST_INC specifies whether build is incremental (1 - incremental).
# _VC_MANIFEST_BASENAME specifies name of a temporary resource file.
!if "$(DEBUG)" == "1"
CPPFLAGS=$(CPPFLAGS) /MDd
LFLAGS=$(LFLAGS) /INCREMENTAL
_VC_MANIFEST_INC=1
_VC_MANIFEST_BASENAME=__VC90.Debug
!else
CPPFLAGS=$(CPPFLAGS) /MD
_VC_MANIFEST_INC=0
_VC_MANIFEST_BASENAME=__VC90
!endif
####################################################
# Specifying name of temporary resource file used only in incremental builds:
!if "$(_VC_MANIFEST_INC)" == "1"
_VC_MANIFEST_AUTO_RES=$(_VC_MANIFEST_BASENAME).auto.res
!else
_VC_MANIFEST_AUTO_RES=
!endif
####################################################
# _VC_MANIFEST_EMBED_EXE - command to embed manifest in EXE:
!if "$(_VC_MANIFEST_INC)" == "1"
#MT_SPECIAL_RETURN=1090650113
#MT_SPECIAL_SWITCH=-notify_resource_update
MT_SPECIAL_RETURN=0
MT_SPECIAL_SWITCH=
_VC_MANIFEST_EMBED_EXE= \
if exist $@.manifest mt.exe -manifest $@.manifest -out:$(_VC_MANIFEST_BASENAME).auto.manifest $(MT_SPECIAL_SWITCH) & \
if "%ERRORLEVEL%" == "$(MT_SPECIAL_RETURN)" \
rc /r $(_VC_MANIFEST_BASENAME).auto.rc & \
link $** /out:$@ $(LFLAGS)
!else
_VC_MANIFEST_EMBED_EXE= \
if exist $@.manifest mt.exe -manifest $@.manifest -outputresource:$@;1
!endif
####################################################
# _VC_MANIFEST_CLEAN - command to clean resources files generated temporarily:
!if "$(_VC_MANIFEST_INC)" == "1"
_VC_MANIFEST_CLEAN=-del $(_VC_MANIFEST_BASENAME).auto.res \
$(_VC_MANIFEST_BASENAME).auto.rc \
$(_VC_MANIFEST_BASENAME).auto.manifest
!else
_VC_MANIFEST_CLEAN=
!endif
# End of makefile.inc
####################################################
Теперь создайте и скопируйте makefile.target.inc
в него следующее содержимое:
# makefile.target.inc - include this at the very bottom of the existing makefile
####################################################
# Commands to generate initial empty manifest file and the RC file
# that references it, and for generating the .res file:
$(_VC_MANIFEST_BASENAME).auto.res : $(_VC_MANIFEST_BASENAME).auto.rc
$(_VC_MANIFEST_BASENAME).auto.rc : $(_VC_MANIFEST_BASENAME).auto.manifest
type <<$@
#include <winuser.h>
1RT_MANIFEST"$(_VC_MANIFEST_BASENAME).auto.manifest"
<< KEEP
$(_VC_MANIFEST_BASENAME).auto.manifest :
type <<$@
<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
</assembly>
<< KEEP
# end of makefile.target.inc
См. также
Создание изолированных приложений и параллельных сборок C/C++
Основные понятия изолированных приложений и параллельных сборок
Устранение неполадок изолированных приложений C/C++ и параллельных сборок
/INCREMENTAL
(Приращение ссылки)
/MANIFEST
(Создание параллельного манифеста сборки)
Сборки строгого имени (подпись сборки) (C++/CLI)
Изменить и продолжить