Procedura: incorporare un manifesto in un'applicazione C/C++
Aggiornamento: novembre 2007
È opportuno che il manifesto di un'applicazione (o libreria) C/C++ sia incorporato all'interno del binario finale poiché in questo modo è possibile garantire un comportamento corretto in fase di esecuzione nella maggior parte degli scenari. Per impostazione predefinita, Visual Studio tenta di incorporare il manifesto al momento della compilazione di un progetto dai file di origine. Per informazioni dettagliate; vedere Generazione di manifesti in Visual Studio. Tuttavia, se un'applicazione viene generata tramite nmake, è necessario apportare alcune modifiche al makefile esistente. In questa sezione viene illustrato come modificare makefile esistenti per incorporare automaticamente il manifesto all'interno del file binario finale.
Due approcci
Ci sono due modi per incorporare il manifesto all'interno di un'applicazione o una libreria.
Se non si sta eseguendo una generazione incrementale, è possibile incorporare direttamente il manifesto utilizzando una riga di comando simile alla seguente come operazione di post-generazione:
mt.exe –manifest MyApp.exe.manifest -outputresource:MyApp.exe;1
oppure
mt.exe –manifest MyLibrary.dll.manifest -outputresource:MyLibrary.dll;2
(1 per un EXE, 2 per una DLL.)
Se si sta eseguendo una compilazione incrementale, la modifica diretta della risorsa come illustrato in questo caso disattiverà la compilazione incrementale e causerà una ricompilazione completa. Sarà quindi necessario adottare un approccio diverso:
Collegare il binario per generare il file MyApp.exe.manifest.
Convertire il manifesto in un file di risorse.
Eseguire di nuovo il collegamento (in modo incrementale) per incorporare la risorsa del manifesto nel binario.
Negli esempi seguenti viene illustrato come modificare makefile per incorporare entrambe le tecniche.
Makefile (prima)
Considerare lo script nmake per MyApp.exe, una semplice applicazione generata da un file:
# 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
Se questo script è eseguito immutato con Visual C++ 2005, crea correttamente MyApp.exe. Crea anche il file manifesto esterno MyApp.exe.manifest, utilizzato dal sistema operativo per caricare gli assembly dipendenti in fase di esecuzione.
Lo script nmake per MyLibrary.dll è molto simile:
# 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 (dopo)
Per eseguire la compilazione con manifesti incorporati è necessario apportare quattro piccole modifiche a ognuno dei makefile originali. Per il makefile MyApp.exe:
# 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.targ.inc
#^^^^^^^^^^^^^^^^^^^^^^^^^ Change #4. (Add full path if necessary.)
Per il 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.targ.inc
#^^^^^^^^^^^^^^^^^^^^^^^^^ Change #4. (Add full path if necessary.)
Il lavoro effettivo viene eseguito dai due file inclusi nei makefile, ovvero makefile.inc e makefile.targ.inc.
Creare makefile.inc e copiarvi quanto segue:
# 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
####################################################
Creare ora makefile.targ.inc e copiarvi quanto segue:
# makefile.targ.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.targ.inc
Vedere anche
Concetti
Informazioni sulla generazione di manifesti per programmi C/C++