Freigeben über


Manifestgenerierung für C/C++-Programme

Ein Manifest ist ein XML-Dokument, das eine Assembly eindeutig identifiziert. Es enthält Informationen, die für die Bindung und Aktivierung verwendet werden, wie COM-Klassen, Benutzeroberflächen und Typbibliotheken. Ein Manifest kann eine externe XML-Datei oder eine Ressource sein, die in eine Anwendung oder eine Assembly eingebettet ist. Das Manifest einer isolierten Anwendung wird verwendet, um die Namen und Versionen der freigegebenen nebeneinander Assemblies zu verwalten, an die die Anwendung zur Laufzeit binden soll. Das Manifest einer parallelen Assembly gibt deren Abhängigkeiten von Namen, Versionen, Ressourcen und anderen Assemblys an.

Es gibt zwei Möglichkeiten, ein Manifest für eine isolierte Anwendung oder eine parallele Assembly zu erstellen. Zuerst kann der Autor der Assembly manuell eine Manifestdatei erstellen, indem er den Regeln und den Namensanforderungen folgt. Weitere Informationen finden Sie im Verweis auf Manifestdateien. Alternativ, wenn ein Programm nur von MSVC-Assemblies wie CRT, MFC, ATL oder anderen abhängt, kann der Linker ein Manifest automatisch generieren.

Die Kopfzeilen der MSVC-Bibliotheken enthalten Assemblyinformationen, und wenn die Bibliotheken im Anwendungscode enthalten sind, wird diese Assemblyinformation vom Linker verwendet, um ein Manifest für das endgültige binär zu bilden. Standardmäßig bettet der Linker die Manifestdatei nicht in die Binärdatei ein. Die Verwendung eines Manifests als externe Datei funktioniert möglicherweise nicht in allen Szenarios. Zum Beispiel wird empfohlen, dass private Assemblies eingebettete Manifeste haben. In Befehlszeilen-Builds, wie solche, die NMAKE zur Erstellung von Code verwenden, können Sie die /MANIFEST:EMBED Linker-Option nutzen, um das Manifest einzubetten. Alternativ kann ein Manifest mit dem Manifest-Tool eingebettet werden. Für weitere Informationen siehe Manifestgeneration an der Befehlszeile. Wenn Sie in Visual Studio erstellen, kann ein Manifest durch Einstellen einer Eigenschaft für das Manifest-Tool im Projekt Eigenschaften Dialogfeld eingebettet werden, wie im nächsten Abschnitt beschrieben.

Manifestgenerierung in Visual Studio

Sie können Visual Studio anweisen, eine Manifestdatei für ein bestimmtes Projekt im Dialogfeld „Eigenschaftenseite“ des Projekts zu generieren. Unter Konfigurationseigenschaften aktivieren Sie Linker>Manifestdatei>Manifest generieren. Standardmäßig sind die Projekteigenschaften neuer Projekte so eingestellt, dass eine Manifestdatei generiert wird. Es ist jedoch möglich, die Generation des Manifests für ein Projekt zu deaktivieren, indem Sie die Manifest generieren-Eigenschaft des Projekts verwenden. Wenn diese Eigenschaft auf Ja gesetzt ist, wird das Manifest für das Projekt generiert. Andernfalls ignoriert der Linker die Assemblyinformationen beim Auflösen der Abhängigkeiten des Anwendungscodes und generiert das Manifest nicht.

Das Buildsystem in Visual Studio ermöglicht, dass das Manifest in die endgültige binäre Anwendungsdatei eingebettet oder als externe Datei generiert wird. Dieses Verhalten wird durch die Option Manifest einbetten im Dialogfeld Projekteigenschaften gesteuert. Öffnen Sie den Knoten Manifesttool, und klicken Sie auf Eingabe und Ausgabe, um diese Eigenschaft festzulegen. Wenn das Manifest nicht eingebettet ist, wird es als externe Datei generiert und im selben Verzeichnis wie die endgültige Binärdatei gespeichert. Wenn das Manifest eingebettet ist, bettet Visual Studio die endgültigen Manifeste mithilfe des folgenden Prozesses ein:

  1. Nach der Kompilierung des Quellcodes in Objektdateien sammelt der Linker abhängige Assemblyinformationen. Während der Linker das endgültige binär verknüpft, generiert er ein Zwischenmanifest, das später zur Erstellung des endgültigen Manifests verwendet wird.

  2. Nachdem das Zwischenmanifest und das Verknüpfen fertiggestellt sind, führt das Manifest-Tool ein finales Manifest zusammen und speichert es als externe Datei.

  3. Das Buildsystem des Projekts erkennt dann, ob das vom Manifesttool generierte Manifest andere Informationen enthält als das bereits in die Binärdatei eingebettete Manifest.

  4. Wenn das im Binär eingebettete Manifest von dem durch das Manifest-Tool generierten Manifest abweicht oder das Binär kein eingebettetes Manifest enthält, ruft Visual Studio den Linker erneut auf, um die externe Manifestdatei als Ressource in das Binär einzubetten.

  5. Wenn das in die Binärdatei eingebettete Manifest dasselbe ist wie das vom Manifest Generation and Editing Tool generierte Manifest, geht das Erstellen zu den nächsten Schritten über.

Das Manifest ist als eingebettete Ressource im endgültigen binär als Textressource enthalten. Sie können es anzeigen, indem Sie die endgültige Binärdatei als Datei in Visual Studio öffnen. Um sicherzustellen, dass das Manifest auf die richtigen Bibliotheken verweist, folgen Sie den in Verstehen der Abhängigkeiten einer Visual C++ Anwendung beschriebenen Schritten. Oder folgen Sie den Vorschlägen, die im Problembehandlung Artikel beschrieben sind.

Manifestgenerierung über die Befehlszeile

Wenn Sie C/C++-Anwendungen von der Befehlszeile aus mit NMAKE oder ähnlichen Tools erstellen, wird das Manifest generiert, nachdem der Linker alle Objektdateien verarbeitet und die endgültige Binärdatei erstellt hat. Der Linker erfasst die in den Objektdateien gespeicherten Assemblyinformationen und fasst sie in einer endgültigen Manifestdatei zusammen. Standardmäßig generiert der Linker eine Datei mit dem Namen <binary_name>.<extension>.manifest, um die endgültige Binärdatei zu beschreiben. Der Linker kann eine Manifestdatei in das Binär einbetten, indem die /MANIFEST:EMBED Linker-Option angegeben wird.

Es gibt mehrere andere Möglichkeiten, ein Manifest in die endgültige Binärdatei einzubetten, wie zum Beispiel die Verwendung des Manifest-Tools (mt.exe) oder das Kompilieren des Manifests in eine Ressourcendatei. Sie müssen spezifischen Regeln folgen, wenn Sie ein Manifest einbetten, um Funktionen wie inkrementelles Verknüpfen, Signieren und Bearbeiten und Fortfahren zu aktivieren. Diese Regeln und andere Optionen werden im nächsten Abschnitt diskutiert.

Vorgehensweise zum Einbetten eines Manifests in eine C/C++-Anwendung

Wir haben empfohlen, dass Sie das Manifest Ihrer Anwendung oder Bibliothek in das endgültige binär einbetten. Dieser Ansatz garantiert korrektes Verhalten zur Laufzeit in den meisten Szenarien. Standardmäßig versucht Visual Studio, das Manifest einzubetten, wenn ein Projekt erstellt wird. Wenn Sie jedoch Ihre Anwendung mit NMAKE erstellen, müssen Sie einige Änderungen am Makefile vornehmen. In diesem Abschnitt wird gezeigt, wie Sie das Makefile ändern, sodass das Manifest automatisch in die endgültige Binärdatei eingebettet wird.

Zwei Ansätze

Es gibt zwei Möglichkeiten, das Manifest in eine Anwendung oder eine Bibliothek einzubetten.

  1. Wenn Sie keinen inkrementellen Build durchführen, können Sie das Manifest direkt über eine Befehlszeile wie die folgende als Bereitstellungsschritt einbetten:

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

    oder

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

    Verwenden Sie 1 für eine EXE und 2 für eine DLL.

  2. Wenn Sie einen inkrementellen Build durchführen, folgen Sie den folgenden Schritten:

    • Verknüpfen Sie die binär, um die MyApp.exe.manifest Datei zu generieren.

    • Konvertieren Sie das Manifest in eine Ressourcendatei.

    • Inkrementelle Verknüpfung, um die Manifestressource in die Binärdatei einzubetten.

In den folgenden Beispielen wird gezeigt, wie Makefiles geändert werden, sodass sie beide Methoden integrieren.

Makefiles (vorher)

Betrachten Sie das NMAKE-Skript für MyApp.exe, eine einfache Anwendung, die aus einer Datei erstellt wurde:

# 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

Wenn dieses Skript unverändert mit Visual Studio ausgeführt wird, erstellt es erfolgreich MyApp.exe. Es erstellt auch die externe Manifestdatei MyApp.exe.manifest, zur Nutzung durch das Betriebssystem, um abhängige Assemblies zur Laufzeit zu laden.

Das NMAKE-Skript für MyLibrary.dll sieht ähnlich aus:

# 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 (nachher)

Um mit eingebetteten Manifests zu erstellen, müssen Sie vier kleine Änderungen an den ursprünglichen Makefiles vornehmen. Für die 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.)

Für das 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.)

Die Makefiles enthalten nun zwei Dateien, die die eigentliche Arbeit erledigen, makefile.inc und makefile.target.inc.

Erstellen Sie makefile.inc und kopieren Sie den folgenden Inhalt hinein:

# 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
####################################################

Erstellen Sie jetzt makefile.target.inc und kopieren Sie den folgenden Inhalt hinein:

# 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

Weitere Informationen

Erstellen von C/C++-Anwendungen im App Service (isoliert) und nebeneinander-Assemblies
Begriffe von isolierten Anwendungen und nebeneinander Assemblys
Problembehandlung von C/C++-Anwendungen im App Service (isoliert) und nebeneinander ausgeführten Assemblys
/INCREMENTAL Verknüpfung inkrementell schrittweise erhöhen
/MANIFEST Erstellen eines nebeneinander Assemblymanifests
Starker Name für Assemblys (Assembly-Signierung) (C++/CLI)
Bearbeiten und Fortsetzen