Share via


Introducción a la generación de manifiestos para los programas de C/C++

Un manifiesto es un documento XML que identifica exclusivamente un ensamblado. Contiene información usada para el enlace y la activación, como clases COM, interfaces y bibliotecas de tipos. Un manifiesto puede ser un archivo XML externo o un recurso insertado en una aplicación o un ensamblado. El manifiesto de una aplicación aislada se usa para administrar los nombres y las versiones de los ensamblados en paralelo compartidos con los que se debe enlazar la aplicación en tiempo de ejecución. El manifiesto de un ensamblado en paralelo especifica sus dependencias de nombres, versiones, recursos y otros ensamblados.

Hay dos maneras de crear un manifiesto para una aplicación aislada o un ensamblado en paralelo. En primer lugar, el autor del ensamblado puede crear manualmente un archivo de manifiesto siguiendo las reglas y los requisitos de nomenclatura. Para obtener más información, consulte Referencia de archivos de manifiesto. Como alternativa, si un programa solo depende de ensamblados de MSVC, como CRT, MFC, ATL u otros, el enlazador puede generar automáticamente un manifiesto.

Los encabezados de las bibliotecas de MSVC contienen información sobre el ensamblado y, cuando las bibliotecas se incluyen en el código de la aplicación, el enlazador usa esa información a fin de formar un manifiesto para el archivo binario final. De forma predeterminada, el enlazador no inserta el archivo de manifiesto dentro del archivo binario. Es posible que no en todos los casos se pueda tener un manifiesto como archivo externo. Por ejemplo, se recomienda que los ensamblados privados tengan manifiestos insertados. En compilaciones de línea de comandos, como las que usan NMAKE para compilar código, puede usar la opción del enlazador /MANIFEST:EMBED para insertar el manifiesto. Como alternativa, un manifiesto se puede insertar mediante la herramienta de manifiesto. Para obtener más información, vea Generación de manifiestos en la línea de comandos. Al compilar código en Visual Studio, se puede insertar un manifiesto mediante el establecimiento de una propiedad para la herramienta de manifiesto en el cuadro de diálogo Propiedades del proyecto, tal como se describe en la sección siguiente.

Generación de manifiestos en Visual Studio

Puede indicar a Visual Studio que genere un archivo de manifiesto para un proyecto determinado en el cuadro de diálogo Páginas de propiedades del proyecto. En Propiedades de configuración, seleccioneEnlazador>Archivo de manifiesto>Generar manifiesto. De forma predeterminada, las propiedades de los proyectos nuevos se establecen para generar un archivo de manifiesto. Aun así, es posible deshabilitar la generación del manifiesto para un proyecto mediante la propiedad Generar manifiesto del proyecto. Cuando esta propiedad se establece en , se genera el manifiesto para el proyecto. En caso contrario, el enlazador omite la información del ensamblado al resolver las dependencias del código de la aplicación y no genera el manifiesto.

El sistema de compilación de Visual Studio permite insertar el manifiesto en el archivo de aplicación binario final o generarlo como un archivo externo. Este comportamiento se controla mediante la opción Incrustar manifiesto en el cuadro de diálogo Propiedades del proyecto. Para establecer esta propiedad, abra el nodo Herramienta Manifiesto y seleccione Entrada y salida. Si el manifiesto no está insertado, se genera como un archivo externo y se guarda en el mismo directorio que el archivo binario final. Si el manifiesto está insertado, Visual Studio inserta los manifiestos finales mediante el siguiente proceso:

  1. Una vez que el código fuente se ha compilado en los archivos objeto, el enlazador recopila información de ensamblado dependiente. Al enlazar el archivo binario final, el enlazador genera un manifiesto intermedio que se usa posteriormente para generar el manifiesto final.

  2. Una vez que se hayan completado el manifiesto intermedio y el enlace, se ejecutará la herramienta de manifiesto para combinar un manifiesto final y guardarlo como un archivo externo.

  3. Después, el sistema de compilación del proyecto detecta si el manifiesto generado por la herramienta de manifiesto contiene información diferente a la del manifiesto que ya está insertado en el archivo binario.

  4. Si el manifiesto insertado en el archivo binario es diferente del manifiesto generado por la herramienta de manifiesto, o si el archivo binario no contiene un manifiesto insertado, Visual Studio invocará el enlazador una vez más para insertar el archivo de manifiesto externo en el archivo binario como un recurso.

  5. Si el manifiesto insertado en el archivo binario es el mismo que el manifiesto generado por la herramienta de manifiesto, la compilación continuará con los siguientes pasos de compilación.

El manifiesto se inserta en el archivo binario final como recurso de texto. Para verlo, abra el archivo binario final como un archivo en Visual Studio. Para asegurarse de que el manifiesto apunte a las bibliotecas correctas, siga los pasos que se describen en Descripción de las dependencias de una aplicación de Visual C++. También puede seguir las sugerencias descritas en el artículo Solución de problemas.

Generación de manifiestos en la línea de comandos

Al compilar aplicaciones en C/C++ desde la línea de comandos mediante NMAKE u otras herramientas similares, el manifiesto se genera después de que el enlazador haya procesado todos los archivos objeto y creado el archivo binario final. El enlazador recopila información de ensamblado almacenada en los archivos objeto y la combina en un archivo de manifiesto final. De forma predeterminada, el enlazador genera un archivo llamado <binary_name>.<extension>.manifest para describir el archivo binario final. El enlazador puede insertar un archivo de manifiesto dentro del archivo binario especificando la opción del enlazador /MANIFEST:EMBED.

Hay varias alternativas para insertar un manifiesto en el archivo binario final, como usar la herramienta de manifiesto (mt.exe) o compilar el manifiesto en un archivo de recursos. Al insertar un manifiesto para habilitar características como el enlace incremental, la firma y Editar y continuar, debe seguir reglas específicas. Estas reglas y otras opciones se explican en la sección siguiente.

Procedimiento para insertar un manifiesto en una aplicación en C/C++

Le recomendamos que inserte el manifiesto en la aplicación o biblioteca, dentro del archivo binario final. Este enfoque garantiza un comportamiento correcto en tiempo de ejecución en la mayoría de los casos. De forma predeterminada, Visual Studio intenta insertar el manifiesto al compilar un proyecto. Sin embargo, si compila la aplicación mediante NMAKE, tendrá que hacer algunos cambios en el archivo Make. En esta sección se muestra cómo cambiar los archivos Make para insertar automáticamente el manifiesto en el archivo binario final.

Dos enfoques

Hay dos maneras de insertar el manifiesto dentro de una aplicación o biblioteca.

  1. Si no va a llevar a cabo una compilación incremental, puede insertar directamente el manifiesto mediante una línea de comandos similar a la siguiente como paso posterior a la compilación:

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

    o

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

    Use 1 para un archivo EXE y 2 para un archivo DLL.

  2. Si va a llevar a cabo una compilación incremental, siga estos pasos:

    • Enlace el archivo binario para generar el archivo MyApp.exe.manifest.

    • Convierta el manifiesto en un archivo de recursos.

    • Vuelva a enlazar (de forma incremental) para insertar el recurso de manifiesto en el archivo binario.

En los ejemplos siguientes se muestra cómo cambiar los archivos Make para incorporar ambas técnicas.

Archivos Make (antes)

Considere la posibilidad de usar el script NMAKE de MyApp.exe, una aplicación sencilla compilada a partir de un archivo:

# 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

Si este script se ejecuta sin ninguna modificación con Visual Studio, crea MyApp.exe correctamente. También crea el archivo de manifiesto externo MyApp.exe.manifest para que el sistema operativo lo use con el objetivo de cargar los ensamblados dependientes en el tiempo de ejecución.

El script NMAKE de MyLibrary.dll se parece a esto:

# 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

Archivos Make (después)

Para compilar código con manifiestos insertados, debe hacer cuatro pequeños cambios en los archivos Make originales. Para el archivo Make 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.)

Para el archivo Make 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.)

Los archivos Make ahora incluyen dos archivos que se encargan del trabajo real, makefile.inc y makefile.target.inc.

Cree makefile.inc y copie lo siguiente en su interior:

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

Ahora, cree makefile.target.inc y copie lo siguiente en su interior:

# 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

Consulte también

Compilación de aplicaciones aisladas y ensamblados simultáneos de C/C++
Conceptos de aplicaciones aisladas y ensamblados en paralelo
Solución de problemas de aplicaciones aisladas de C/C++ y ensamblados en paralelo
/INCREMENTAL (enlazar incrementalmente)
/MANIFEST (crear el manifiesto del ensamblado en paralelo)
Ensamblados de nombre seguro (firma de ensamblados) (C++/CLI)
Editar y continuar