Partilhar via


Noções básicas sobre geração de manifesto para programas do C/C++

Um manifesto é um documento XML que identifica exclusivamente um assembly. Ele contém informações usadas para vinculação e ativação, como classes COM, interfaces e bibliotecas de tipos. Um manifesto pode ser um arquivo XML externo ou um recurso incorporado em um aplicativo ou assembly. O manifesto de um aplicativo isolado é usado para gerenciar os nomes e as versões de assemblies compartilhados lado a lado aos quais o aplicativo deve se vincular em tempo de execução. O manifesto de um assembly lado a lado especifica suas dependências em nomes, versões, recursos e outros assemblies.

Há duas maneiras de criar um manifesto para um aplicativo isolado ou um assembly lado a lado. Primeiro, o autor do assembly pode criar manualmente um arquivo de manifesto seguindo as regras e os requisitos de nomenclatura. Para obter mais informações, consulte Referência de arquivos de manifesto. Como alternativa, se um programa depender apenas de assemblies MSVC, como CRT, MFC, ATL ou outros, o vinculador poderá gerar um manifesto automaticamente.

Os cabeçalhos das bibliotecas MSVC contêm informações de assembly e, quando as bibliotecas são incluídas no código do aplicativo, essas informações de assembly são usadas pelo vinculador para formar um manifesto para o binário final. Por padrão, o vinculador não incorpora o arquivo manifesto dentro do binário. Ter um manifesto como um arquivo externo pode não funcionar para todos os cenários. Por exemplo, é recomendável que os assemblies privados tenham manifestos incorporados. Em compilações de linha de comando, como aquelas que usam NMAKE para compilar código, você pode usar a opção de vinculador /MANIFEST:EMBED para incorporar o manifesto. Como alternativa, um manifesto pode ser incorporado usando a ferramenta de manifesto. Para obter mais informações, consulte Geração de manifesto na linha de comando. Ao compilar no Visual Studio, um manifesto pode ser incorporado definindo uma propriedade para a ferramenta de manifesto na caixa de diálogo Propriedades do projeto, conforme descrito na próxima seção.

Geração de manifesto no Visual Studio

Você pode dizer ao Visual Studio para gerar um arquivo de manifesto para um projeto específico na caixa de diálogo Páginas de propriedade do projeto. Em Propriedades de configuração, selecione Vinculador>Arquivo de manifesto>Gerar manifesto. Por padrão, as propriedades do projeto de novos projetos são definidas para gerar um arquivo de manifesto. No entanto, é possível desabilitar a geração do manifesto para um projeto usando a propriedade Gerar manifesto do projeto. Quando esta propriedade é definida como Sim, o manifesto do projeto é gerado. Caso contrário, o vinculador ignora as informações do assembly ao resolver dependências do código do aplicativo e não gera o manifesto.

O sistema de build do Visual Studio permite que o manifesto seja inserido no arquivo de aplicativo binário final ou gerado como um arquivo externo. Esse comportamento é controlado pela opção Inserir Manifesto na caixa de diálogo Propriedades do Projeto. Para definir essa propriedade, abra o nó Ferramenta de Manifesto e selecione Entrada e Saída. Se o manifesto não estiver incorporado, ele será gerado como um arquivo externo e salvo no mesmo diretório que o binário final. Se o manifesto estiver inserido, o Visual Studio inserirá os manifestos finais usando o seguinte processo:

  1. Depois que o código-fonte for compilado em arquivos-objeto, o vinculador coletará informações de assembly dependentes. Enquanto vincula o binário final, o vinculador gera um manifesto intermediário que é usado posteriormente para gerar o manifesto final.

  2. Após a conclusão do manifesto intermediário e da vinculação, a ferramenta de manifesto mescla um manifesto final e o salva como um arquivo externo.

  3. Então, o sistema de build do projeto detectará se o manifesto gerado pela ferramenta de manifesto contém informações diferentes do manifesto já inserido no binário.

  4. Se o manifesto inserido no binário for diferente do manifesto gerado pela ferramenta de manifesto ou o binário não contiver um manifesto inserido, o Visual Studio invocará o vinculador mais uma vez para incorporar o arquivo de manifesto externo dentro do binário como um recurso.

  5. Se o manifesto inserido no binário for o mesmo que o manifesto gerado pela ferramenta de manifesto, a compilação continuará nas próximas etapas de compilação.

O manifesto é incorporado no binário final como um recurso de texto. Você pode exibi-lo abrindo o binário final como um arquivo no Visual Studio. Para garantir que o manifesto aponte para as bibliotecas corretas, siga as etapas descritas em Noções básicas de dependências de um aplicativo Visual C++. Ou siga as sugestões descritas no artigo Solução de problemas.

Geração de manifesto na linha de comando

Quando você cria aplicativos C/C++ a partir da linha de comando usando NMAKE ou ferramentas semelhantes, o manifesto é gerado depois que o vinculador processa todos os arquivos de objeto e cria o binário final. O vinculador coletará as informações de assembly armazenadas nos arquivos de objeto e combinará essas informações em um arquivo de manifesto final. Por padrão, o vinculador gera um arquivo chamado <binary_name>.<extension>.manifest para descrever o binário final. O vinculador pode incorporar um arquivo de manifesto dentro do binário especificando a opção de vinculador /MANIFEST:EMBED.

Há várias outras maneiras de incorporar um manifesto no binário final, como usar a ferramenta Manifest (mt.exe) ou compilar o manifesto em um arquivo de recurso. Você deve seguir regras específicas ao incorporar um manifesto para habilitar recursos como vinculação incremental, assinatura e Editar e Continuar. Essas regras e outras opções são discutidas na próxima seção.

Como incorporar um manifesto dentro de um aplicativo C/C++

Recomendamos que você incorpore o manifesto do seu aplicativo ou biblioteca dentro do binário final. Essa abordagem garante o comportamento correto do tempo de execução na maioria dos cenários. Por padrão, o Visual Studio tenta inserir o manifesto quando ele compila um projeto. No entanto, se você criar seu aplicativo usando o NMAKE, precisará fazer algumas alterações no makefile. Esta seção mostra como alterar os makefiles para que ele insira automaticamente o manifesto dentro do binário final.

Duas abordagens

Há duas maneiras de inserir o manifesto dentro de um aplicativo ou uma biblioteca.

  1. Se você não estiver fazendo um build incremental, poderá inserir diretamente o manifesto usando uma linha de comando semelhante à seguinte como uma etapa pós-build:

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

    ou

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

    Use 1 para um EXE e 2 para uma DLL.

  2. Se você estiver fazendo uma compilação incremental, use as seguintes etapas:

    • Vincule o binário para gerar o arquivo MyApp.exe.manifest.

    • Converta o manifesto em um arquivo de recurso.

    • Vincule novamente (incrementalmente) para inserir o recurso de manifesto no binário.

Os exemplos a seguir mostram como alterar os makefiles para incorporar ambas as técnicas.

Makefiles (antes)

Considere o script NMAKE para MyApp.exe, um aplicativo simples criado a partir de um arquivo:

# 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 esse script for executado inalterado com o Visual Studio, ele criará MyApp.exe com êxito. Ele também cria o arquivo de manifesto externo MyApp.exe.manifest, para uso pelo sistema operacional para carregar assemblies dependentes em tempo de execução.

O script NMAKE para MyLibrary.dll é semelhante:

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

Para compilar com manifestos inseridos, você precisa fazer quatro pequenas alterações nos makefiles originais. Para o 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.target.inc
#^^^^^^^^^^^^^^^^^^^^^^^^^ Change #4. (Add full path if necessary.)

No 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.)

Os makefiles agora incluem dois arquivos que fazem o trabalho real, makefile.inc e makefile.target.inc.

Crie makefile.inc e copie o seguinte conteúdo nele:

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

Agora crie makefile.target.inc e copie o seguinte conteúdo nele:

# 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

Confira também

Como compilar assemblies lado a lado e aplicativos isolados do C/C++
Conceitos de aplicações isoladas e montagens lado a lado
Solução de problemas de aplicativos isolados C/C++ e assemblies lado a lado
/INCREMENTAL (Vincular incrementalmente)
/MANIFEST (Criar manifesto de assembly lado a lado)
Assemblies de nome forte (assinatura de assemblies) (C++/CLI)
Editar e continuar