Informazioni sulla generazione di manifesti per programmi C/C++

Un manifesto è un documento XML che identifica in modo univoco un assembly. Contiene informazioni usate per l'associazione e l'attivazione, ad esempio classi COM, interfacce e librerie dei tipi. Un manifesto può essere un file XML esterno o una risorsa incorporata in un'applicazione o in un assembly. Il manifesto di un'applicazione isolata viene usato per gestire i nomi e le versioni degli assembly condivisi side-by-side a cui l'applicazione deve essere associata in fase di esecuzione. Il manifesto di un assembly side-by-side specifica le relative dipendenze da nomi, versioni, risorse e altri assembly.

Esistono due modi per creare un manifesto per un'applicazione isolata o un assembly affiancato. Prima di tutto, l'autore dell'assembly può creare manualmente un file manifesto seguendo le regole e i requisiti di denominazione. Per altre informazioni, vedere Informazioni di riferimento sui file manifesto. In alternativa, se un programma dipende solo da assembly MSVC, ad esempio CRT, MFC, ATL o altri, il linker può generare automaticamente un manifesto.

Le intestazioni delle librerie MSVC contengono informazioni sull'assembly e, quando le librerie sono incluse nel codice dell'applicazione, queste informazioni sull'assembly vengono usate dal linker per formare un manifesto per il file binario finale. Per impostazione predefinita, il linker non incorpora il file manifesto all'interno del file binario. La presenza di un manifesto come file esterno potrebbe non funzionare per tutti gli scenari. Ad esempio, è consigliabile che gli assembly privati abbiano manifesti incorporati. Nelle compilazioni della riga di comando, ad esempio quelle che usano NMAKE per compilare il codice, è possibile usare l'opzione /MANIFEST:EMBED del linker per incorporare il manifesto. In alternativa, un manifesto può essere incorporato usando lo strumento manifesto. Per altre informazioni, vedere Generazione di manifesti nella riga di comando. Quando si compila in Visual Studio, un manifesto può essere incorporato impostando una proprietà per lo strumento manifesto nella finestra di dialogo Proprietà progetto, come descritto nella sezione successiva.

Generazione di manifesti in Visual Studio

È possibile indicare a Visual Studio di generare un file manifesto per un determinato progetto nella finestra di dialogo Pagine delle proprietà del progetto. In Proprietà di configurazione selezionare Genera manifesto> del linker.> Per impostazione predefinita, le proprietà del progetto dei nuovi progetti vengono impostate per generare un file manifesto. Tuttavia, è possibile disabilitare la generazione del manifesto per un progetto usando la proprietà Generate Manifest del progetto. Quando questa proprietà è impostata su , viene generato il manifesto per il progetto. In caso contrario, il linker ignora le informazioni sull'assembly durante la risoluzione delle dipendenze del codice dell'applicazione e non genera il manifesto.

Il sistema di compilazione in Visual Studio consente di incorporare il manifesto nel file dell'applicazione binaria finale o generato come file esterno. Questo comportamento è controllato dall'opzione Incorpora manifesto nella finestra di dialogo Proprietà progetto. Per impostare questa proprietà, aprire il nodo Strumento manifesto, quindi selezionare Input e output. Se il manifesto non è incorporato, viene generato come file esterno e salvato nella stessa directory del file binario finale. Se il manifesto è incorporato, Visual Studio incorpora i manifesti finali usando il processo seguente:

  1. Dopo la compilazione del codice sorgente in file oggetto, il linker raccoglie informazioni sull'assembly dipendente. Mentre collega il file binario finale, il linker genera un manifesto intermedio usato successivamente per generare il manifesto finale.

  2. Al termine del manifesto intermedio e del collegamento, lo strumento manifesto unisce un manifesto finale e lo salva come file esterno.

  3. Il sistema di compilazione del progetto rileva quindi se il manifesto generato dallo strumento manifesto contiene informazioni diverse rispetto al manifesto già incorporato nel file binario.

  4. Se il manifesto incorporato nel file binario è diverso dal manifesto generato dallo strumento manifesto o il file binario non contiene un manifesto incorporato, Visual Studio richiama il linker una volta più per incorporare il file manifesto esterno all'interno del file binario come risorsa.

  5. Se il manifesto incorporato nel file binario è uguale al manifesto generato dallo strumento manifesto, la compilazione continua con i passaggi di compilazione successivi.

Il manifesto viene incorporato all'interno del file binario finale come risorsa di testo. È possibile visualizzarlo aprendo il file binario finale come file in Visual Studio. Per assicurarsi che il manifesto punti alle librerie corrette, seguire la procedura descritta in Informazioni sulle dipendenze di un'applicazione Visual C++. In alternativa, seguire i suggerimenti descritti nell'articolo Risoluzione dei problemi .

Generazione di manifesti dalla riga di comando

Quando si compilano applicazioni C/C++ dalla riga di comando usando NMAKE o strumenti simili, il manifesto viene generato dopo che il linker ha elaborato tutti i file oggetto e compilato il file binario finale. Il linker raccoglie le informazioni sull'assembly archiviate nei file oggetto e combina queste informazioni in un file manifesto finale. Per impostazione predefinita, il linker genera un file denominato <binary_name>.<extension>.manifest per descrivere il file binario finale. Il linker può incorporare un file manifesto all'interno del file binario specificando l'opzione del /MANIFEST:EMBED linker.

Esistono diversi altri modi per incorporare un manifesto all'interno del file binario finale, ad esempio usando lo strumento Manifesto (mt.exe) o compilando il manifesto in un file di risorse. È necessario seguire regole specifiche quando si incorpora un manifesto per abilitare funzionalità come il collegamento incrementale, la firma e modifica e continuazione. Queste regole e altre opzioni sono illustrate nella sezione successiva.

Come incorporare un manifesto all'interno di un'applicazione C/C++

È consigliabile incorporare il manifesto dell'applicazione o della libreria all'interno del file binario finale. Questo approccio garantisce un comportamento di runtime corretto nella maggior parte degli scenari. Per impostazione predefinita, Visual Studio tenta di incorporare il manifesto quando compila un progetto. Tuttavia, se si compila l'applicazione usando NMAKE, è necessario apportare alcune modifiche al makefile. Questa sezione illustra come modificare i makefile in modo che incorpora automaticamente il manifesto all'interno del file binario finale.

Due approcci

Esistono due modi per incorporare il manifesto all'interno di un'applicazione o di una libreria.

  1. Se non si esegue una compilazione incrementale, è possibile incorporare direttamente il manifesto usando una riga di comando simile alla seguente come passaggio di post-compilazione:

    mt.exe -manifest MyApp.exe.manifest -outputresource:MyApp.exe;1
    

    oppure

    mt.exe -manifest MyLibrary.dll.manifest -outputresource:MyLibrary.dll;2
    

    Usare 1 per un file EXE e 2 per una DLL.

  2. Se si esegue una compilazione incrementale, seguire questa procedura:

    • Collegare il file binario per generare il MyApp.exe.manifest file.

    • Convertire il manifesto in un file di risorse.

    • Ricollegare (incrementalmente) per incorporare la risorsa manifesto nel file binario.

Negli esempi seguenti viene illustrato come modificare i makefile per incorporare entrambe le tecniche.

Makefiles (Before)

Si consideri lo script NMAKE per MyApp.exe, una semplice applicazione creata 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 viene eseguito senza modifiche con Visual Studio, viene creato MyApp.execorrettamente . Crea anche il file MyApp.exe.manifestmanifesto esterno , da usare dal sistema operativo per caricare gli assembly dipendenti in fase di esecuzione.

Lo script NMAKE è MyLibrary.dll simile al seguente:

# 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

Makefiles (After)

Per compilare con manifesti incorporati, è necessario apportare quattro piccole modifiche ai makefile originali. Per il 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.)

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.target.inc
#^^^^^^^^^^^^^^^^^^^^^^^^^ Change #4. (Add full path if necessary.)

I makefile includono ora due file che eseguono il lavoro reale e makefile.incmakefile.target.inc.

Creare makefile.inc e copiare il contenuto seguente:

# 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 Creare e copiare ora il contenuto seguente:

# 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

Vedi anche

Compilazione di applicazioni isolate C/C++ e di assembly side-by-side
Concetti relativi alle applicazioni isolate e agli assembly side-by-side
Risoluzione dei problemi relativi alle applicazioni isolate C/C++ e agli assembly side-by-side
/INCREMENTAL (Collegamento incrementale)
/MANIFEST (Crea manifesto dell'assembly side-by-side)
Assembly con nome sicuro (firma dell'assembly) (C++/CLI)
Modifica e continuazione