Compartir a través de


Integración del conjunto de herramientas y extensibilidad del sistema de Visual Studio C++ Project

El sistema de proyectos de Visual C++ se usa para archivos .vcxproj. Se basa en el Visual Studio Common Project System (CPS) y proporciona puntos adicionales específicos de C++ para facilitar la integración de nuevos conjuntos de herramientas, arquitecturas de compilación y plataformas de destino.

Estructura de objetivos de MSBuild de C++

Todos los archivos .vcxproj importan estos archivos:

<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

Estos archivos definen poco por sí mismos. En su lugar, importan otros archivos en función de estos valores de propiedad:

  • $(ApplicationType)

    Ejemplos: Tienda Windows, Android, Linux

  • $(ApplicationTypeRevision)

    Debe ser una cadena de versión válida, con el formato major.minor[.build[.revision]].

    Ejemplos: 1.0, 10.0.0.0

  • $(Platform)

    La arquitectura de compilación, denominada "Plataforma" por motivos históricos.

    Ejemplos: Win32, x86, x64, ARM

  • $(PlatformToolset)

    Ejemplos: v140, v141, v141_xp, llvm

Estos valores de propiedad especifican nombres de carpeta en la carpeta raíz $(VCTargetsPath):

$(VCTargetsPath)\
    tipo de aplicación\
        $(ApplicationType)\
            $(ApplicationTypeRevision)\
                Plataformas\
                    $(Platform)\
                        PlatformToolsets\
                            $(PlatformToolset)
    Plataformas\
        $(Platform)\
            PlatformToolsets\
                $(PlatformToolset)

La carpeta $(VCTargetsPath)\Platforms\ se usa cuando $(ApplicationType) está vacía, para proyectos de escritorio de Windows.

Adición de un nuevo conjunto de herramientas de plataforma

Para agregar un nuevo conjunto de herramientas, por ejemplo, "MyToolset" para la plataforma Win32 existente, cree una carpeta MyToolset en $(VCTargetsPath)\Platforms\Win32\PlatformToolsets\y cree Toolset.props y Toolset.targets archivos.

Cada nombre de carpeta PlatformToolsets aparece en el cuadro de diálogo Propiedades del proyecto como un Conjunto de herramientas de plataforma disponible para la plataforma especificada, como se muestra aquí:

la propiedad Platform Toolset del cuadro de diálogo Páginas de propiedades del proyecto

Cree carpetas MyToolset similares y archivos Toolset.props y Toolset.targets en cada carpeta de plataforma existente que admite este conjunto de herramientas.

Adición de una nueva plataforma

Para agregar una nueva plataforma, por ejemplo, "MyPlatform", cree una carpeta MyPlatform en $(VCTargetsPath)\Platforms\y cree archivos Platform.default.props, Platform.propsy Platform.targets. Cree también una carpeta $(VCTargetsPath)\Platforms\MyPlatform\PlatformToolsets\ y cree al menos un conjunto de herramientas en él.

Todos los nombres de carpeta bajo la carpeta Platforms para cada $(ApplicationType) y $(ApplicationTypeRevision) aparecen en el IDE como opciones Platform disponibles para un proyecto.

La opción Nueva plataforma en el cuadro de diálogo Nueva plataforma de proyecto

Agregar un nuevo tipo de aplicación

Para agregar un nuevo tipo de aplicación, cree una carpeta MyApplicationType en $(VCTargetsPath)\Application Type\ y cree un archivo Defaults.props en él. Se requiere al menos una revisión para un tipo de aplicación, por lo que también cree una carpeta $(VCTargetsPath)\Application Type\MyApplicationType\1.0 y cree un archivo Defaults.props en él. También debe crear una carpeta $(VCTargetsPath)\ApplicationType\MyApplicationType\1.0\Platforms y crear al menos una plataforma en ella.

Las propiedades $(ApplicationType) y $(ApplicationTypeRevision) no se muestran en la interfaz de usuario. Se definen en las plantillas de proyecto y no se pueden cambiar después de crear el proyecto.

Árbol de importación de .vcxproj

Un árbol simplificado de importaciones para propiedades y archivos de destinos de Microsoft C++ tiene el siguiente aspecto:

$(VCTargetsPath)\ Microsoft.Cpp.Default.props
    $(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props
    $(VCTargetsPath)\ImportBefore\Default\*.props
    $(VCTargetsPath)\Application Type\$(ApplicationType)\Default.props
    $(VCTargetsPath)\Application Type\$(ApplicationType)\$(ApplicationTypeRevision)\Default.props
    $(VCTargetsPath)\Application Type\$(ApplicationType)\$(ApplicationTypeRevision)\Platforms\$(Platform)\Platform.default.props
    $(VCTargetsPath)\ImportAfter\Default\*.props

Los proyectos de escritorio de Windows no definen $(ApplicationType), por lo que solo importan

$(VCTargetsPath)\ Microsoft.Cpp.Default.props
    $(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props
    $(VCTargetsPath)\ImportBefore\Default\*.props
    $(VCTargetsPath)\Platforms\$(Platform)\Platform.default.props
    $(VCTargetsPath)\ImportAfter\Default\*.props

Usaremos la propiedad $(_PlatformFolder) para almacenar las ubicaciones de las carpetas de la plataforma $(Platform). This property is

$(VCTargetsPath)\Platforms\$(Platform)

para aplicaciones de escritorio de Windows y

$(VCTargetsPath)\Tipo de Aplicación\$(ApplicationType)\$(ApplicationTypeRevision)\Plataformas\$(Platform)

para todo lo demás.

Los archivos props se importan en este orden:

$(VCTargetsPath)\Microsoft.Cpp.props
    $(_PlatformFolder)\Platform.props
        $(VCTargetsPath)\ Microsoft.Cpp.Platform.props
            $(_PlatformFolder)\ImportBefore\*.props
            $(_PlatformFolder)\PlatformToolsets\$(PlatformToolset)\Toolset.props
            $(_PlatformFolder)\ImportAfter\*.props

Los archivos de destino se importan en este orden:

$(VCTargetsPath)\Microsoft.Cpp.targets
    $(VCTargetsPath)\Microsoft.Cpp.Current.targets
        $(_PlatformFolder)\Platform.targets
            $(VCTargetsPath)\Microsoft.Cpp.Platform.targets
                $(_PlatformFolder)\ImportBefore\*.targets
                $(_PlatformFolder)\PlatformToolsets\$(PlatformToolset)\Toolset.target
                $(_PlatformFolder)\ImportAfter\*.targets

Si necesita definir algunas propiedades predeterminadas para el conjunto de herramientas, puede agregar archivos a las carpetas ImportBefore e ImportAfter adecuadas.

Creación de archivos Toolset.props y Toolset.targets

Toolset.props y Toolset.targets archivos tienen control total sobre lo que sucede durante una compilación cuando se usa este conjunto de herramientas. También pueden controlar los depuradores disponibles, parte de la interfaz de usuario del IDE, como el contenido en el cuadro de diálogo de las páginas de propiedades, y otros aspectos del comportamiento del proyecto.

Aunque un conjunto de herramientas puede invalidar todo el proceso de compilación, normalmente solo quiere que el conjunto de herramientas modifique o agregue algunos pasos de compilación, o para usar diferentes herramientas de compilación, como parte de un proceso de compilación existente. Para lograr este objetivo, hay una serie de propiedades comunes y archivos de destino que el conjunto de herramientas puede importar. En función de lo que quiera que haga el conjunto de herramientas, estos archivos pueden ser útiles para usarlos como importaciones o como ejemplos:

  • $(VCTargetsPath)\Microsoft.CppCommon.targets

    Este archivo define las partes principales del proceso de compilación nativo y también importa:

    • $(VCTargetsPath)\Microsoft.CppBuild.targets

    • $(VCTargetsPath)\Microsoft.BuildSteps.targets

    • $(MSBuildToolsPath)\Microsoft.Common.Targets

  • $(VCTargetsPath)\ Microsoft.Cpp.Common.props

    Establece los valores predeterminados de los conjuntos de herramientas que usan los compiladores de Microsoft y Windows de destino.

  • $(VCTargetsPath)\ Microsoft.Cpp.WindowsSDK.props

    Este archivo determina la ubicación de Windows SDK y define algunas propiedades importantes para las aplicaciones destinadas a Windows.

Integración de destinos específicos del conjunto de herramientas con el proceso de compilación predeterminado de C++

El proceso de compilación predeterminado de C++ se define en Microsoft.CppCommon.targets. Los destinos no llaman a ninguna herramienta de compilación específica; especifican los pasos de compilación principales, su orden y sus dependencias.

La compilación de C++ tiene tres pasos principales, que se representan mediante los siguientes destinos:

  • BuildGenerateSources

  • BuildCompile

  • BuildLink

Dado que cada paso de compilación se puede ejecutar de forma independiente, los destinos que se ejecutan en un paso no pueden depender de los grupos de elementos y las propiedades definidas en los destinos que se ejecutan como parte de un paso diferente. Esta división permite ciertas optimizaciones de rendimiento de compilación. Aunque no se utiliza por defecto, se recomienda igualmente respetar esta separación.

Los objetivos que se ejecutan en cada paso están controlados por estas propiedades:

  • $(BuildGenerateSourcesTargets)

  • $(BuildCompileTargets)

  • $(BeforeBuildLinkTargets)

Cada paso también tiene propiedades de Antes y Después.

<Target
  Name="_BuildGenerateSourcesAction"
  DependsOnTargets="$(CommonBuildOnlyTargets);$(BeforeBuildGenerateSourcesTargets);$(BuildGenerateSourcesTargets);$(AfterBuildGenerateSourcesTargets)" />

<Target
  Name="\_BuildCompileAction"
  DependsOnTargets="$(CommonBuildOnlyTargets);$(BeforeBuildCompileTargets);$(BuildCompileTargets);$(AfterBuildCompileTargets)" />

<Target
  Name="\_BuildLinkAction"
  DependsOnTargets="$(CommonBuildOnlyTargets);$(BeforeBuildLinkTargets);$(BuildLinkTargets);$(AfterBuildLinkTargets)" />

Consulte el archivo Microsoft.CppBuild.targets para obtener ejemplos de los objetivos que se incluyen en cada paso:

<BuildCompileTargets Condition="'$(ConfigurationType)'\!='Utility'">
  $(BuildCompileTargets);
  _ClCompile;
  _ResGen;
  _ResourceCompile;
  $(BuildLibTargets);
</BuildCompileTargets>

Si observa los objetivos, como _ClCompile, verá que no hacen nada directamente por ellos mismos, sino que dependen de otros objetivos, incluidos ClCompile:

<Target Name="_ClCompile"
  DependsOnTargets="$(BeforeClCompileTargets);$(ComputeCompileInputsTargets);MakeDirsForCl;ClCompile;$(AfterClCompileTargets)" >
</Target>

ClCompile y otros destinos específicos de la herramienta de compilación se definen como destinos vacíos en Microsoft.CppBuild.targets:

<Target Name="ClCompile"/>

Dado que el destino de ClCompile está vacío, a menos que un conjunto de herramientas lo invalide, no se realiza ninguna acción de compilación real. Los destinos del conjunto de herramientas pueden sobrescribir el destino ClCompile; es decir, pueden contener una definición alternativa de ClCompile después de importar Microsoft.CppBuild.targets:

<Target Name="ClCompile"
  Condition="'@(ClCompile)' != ''"
  DependsOnTargets="SelectClCompile">
  <!-- call some MSBuild tasks -->
</Target>

A pesar de su nombre, que se creó antes de que Visual Studio implementara compatibilidad multiplataforma, el objetivo ClCompile no está obligado a llamar a CL.exe. También puede llamar a Clang, gcc u otros compiladores mediante las tareas adecuadas de MSBuild.

El destino ClCompile no debe tener ninguna dependencia, excepto el destino SelectClCompile, que es necesario para que el comando de compilación de archivo único funcione en el IDE.

Tareas de MSBuild que se van a usar en destinos del conjunto de herramientas

Para invocar una herramienta de compilación real, el destino debe llamar a una tarea de MSBuild. Hay una tarea exec básica que permite especificar una línea de comandos que se va a ejecutar. Sin embargo, las herramientas de compilación suelen tener muchas opciones, entradas y salidas para realizar un seguimiento de las compilaciones incrementales, por lo que tiene más sentido tener tareas especiales para ellas. Por ejemplo, la tarea CL traduce las propiedades de MSBuild en conmutadores de CL.exe, los escribe en un archivo de respuesta y llama a CL.exe. También realiza un seguimiento de todos los archivos de entrada y salida para compilaciones incrementales posteriores. Para obtener más información, consulte Compilaciones incrementales y comprobaciones actualizadas.

El Microsoft.Cpp.Common.Tasks.dll implementa estas tareas:

  • BSCMake

  • CL

  • ClangCompile (conmutadores clang-gcc)

  • LIB

  • LINK

  • MIDL

  • Mt

  • RC

  • XDCMake

  • CustomBuild (como Exec, pero con seguimiento de entrada y salida)

  • SetEnv

  • GetOutOfDateItems

Si tiene una herramienta que realiza la misma acción que una herramienta existente y que tiene modificadores de línea de comandos similares (como clang-cl y CL), puede usar la misma tarea para ambas.

Si necesita crear una nueva tarea para una herramienta de compilación, puede elegir entre las siguientes opciones:

  1. Si usa esta tarea rara vez o si unos segundos no importan para la compilación, puede usar las tareas "insertadas" de MSBuild:

    • Tarea Xaml (una regla de compilación personalizada)

      Para obtener un ejemplo de una declaración de tarea Xaml, consulta $(VCTargetsPath)\BuildCustomizations\masm.xml, y para su uso, consulta $(VCTargetsPath)\BuildCustomizations\masm.targets.

    • Tarea de código

  2. Si desea mejorar el rendimiento de las tareas o simplemente necesita una funcionalidad más compleja, use el proceso normal de escritura de tareas de MSBuild.

    Si no todas las entradas y salidas de la herramienta se muestran en la línea de comandos de la herramienta, como en los casos de CL, MIDLy RC, y si desea el seguimiento automático de archivos de entrada y salida y creación de archivos .tlog, derive la tarea de la clase Microsoft.Build.CPPTasks.TrackedVCToolTask. En la actualidad, aunque hay documentación para la clase ToolTask base, no hay ejemplos ni documentación para los detalles de la clase TrackedVCToolTask. Si esto es de especial interés, haga oír su voz en una solicitud en Developer Community.

Compilaciones incrementales y comprobaciones actualizadas

Los destinos de compilación incremental de MSBuild predeterminados usan atributos Inputs y Outputs. Si los especifica, MSBuild llama al destino solo si alguna de las entradas tiene una marca de tiempo más reciente que todas las salidas. Dado que los archivos de origen suelen incluir o importar otros archivos, y las herramientas de compilación generan diferentes salidas en función de las opciones de la herramienta, es difícil especificar todas las entradas y salidas posibles en destinos de MSBuild.

Para administrar este problema, la compilación de C++ usa una técnica diferente para admitir compilaciones incrementales. La mayoría de los destinos no especifican entradas y salidas y, como resultado, siempre se ejecutan durante la compilación. Las tareas llamadas por los destinos escriben información sobre todas las entradas y salidas en archivos tlog que tienen una extensión .tlog. Las compilaciones posteriores usan los archivos .tlog para comprobar lo que ha cambiado y se debe volver a generar y lo que es up-to-date. Los archivos .tlog son también la única fuente para la verificación de fecha de la compilación predeterminada up-toen el IDE.

Para determinar todas las entradas y salidas, las tareas de herramientas nativas usan tracker.exe y la clase de FileTracker proporcionada por MSBuild.

Microsoft.Build.CPPTasks.Common.dll define la clase base TrackedVCToolTask abstracta pública. La mayoría de las tareas de herramientas nativas se derivan de esta clase.

A partir de la actualización 15.8 de Visual Studio 2017, puede usar la tarea de GetOutOfDateItems implementada en Microsoft.Cpp.Common.Tasks.dll para generar archivos .tlog para destinos personalizados con entradas y salidas conocidas. Como alternativa, puede crearlos mediante la tarea WriteLinesToFile. Consulte el destino de _WriteMasmTlogs en $(VCTargetsPath)\BuildCustomizations\masm.targets como ejemplo.

Archivos .tlog

Hay tres tipos de archivos .tlog: leer, escribiry línea de comandos. Las compilaciones incrementales usan los archivos .tlog de lectura y escritura y la comprobación actualizada en el IDE. Los archivos .tlog de la línea de comandos solo se usan en compilaciones incrementales.

MSBuild proporciona estas clases auxiliares para leer y escribir archivos .tlog:

La clase FlatTrackingData se puede usar para tener acceso a archivos .tlog de lectura y escritura e identificar las entradas que son más recientes que las salidas, o si falta una salida. Se usa en la comprobación actualizada.

Los archivos .tlog de la línea de comandos contienen información sobre las líneas de comandos usadas en la compilación. Solo se usan para compilaciones incrementales, no comprobaciones actualizadas, por lo que el formato interno viene determinado por la tarea de MSBuild que las genera.

Leer el formato .tlog

Los archivos de lectura .tlog (*.read.*.tlog) contienen información sobre los archivos de origen y sus dependencias.

Un caret (^) al principio de una línea indica una o varias fuentes. Las fuentes que comparten las mismas dependencias están separadas por una barra vertical (|).

Los archivos de dependencia se muestran después de los orígenes, cada uno en su propia línea. Todos los nombres de archivo son rutas de acceso completas.

Por ejemplo, supongamos que los orígenes del proyecto se encuentran en F:\test\ConsoleApplication1\ConsoleApplication1. Si el archivo de origen, Class1.cpp, tiene estos elementos,

#include "stdafx.h" //precompiled header
#include "Class1.h"

a continuación, el archivo CL.read.1.tlog contiene el archivo de origen seguido de sus dos dependencias:

^F:\TEST\CONSOLEAPPLICATION1\CONSOLEAPPLICATION1\CLASS1.CPP
F:\TEST\CONSOLEAPPLICATION1\CONSOLEAPPLICATION1\DEBUG\CONSOLEAPPLICATION1.PCH
F:\TEST\CONSOLEAPPLICATION1\CONSOLEAPPLICATION1\CLASS1.H

No es necesario escribir nombres de archivo en mayúsculas, pero es una comodidad para algunas herramientas.

Escribir formato .tlog

Los archivos de escritura .tlog (*.write.*.tlog) conectan orígenes y salidas.

Un caret (^) al principio de una línea indica una o más fuentes. Varios fuentes están separados por una barra vertical (|).

Los archivos de salida creados a partir de las fuentes deben aparecer después de las fuentes, cada uno en su propia línea. Todos los nombres de archivo deben ser rutas de acceso completas.

Por ejemplo, para un proyecto consoleApplication simple que tenga un archivo de origen adicional Class1.cpp, el archivo link.write.1.tlog puede contener:

^F:\TEST\CONSOLEAPPLICATION1\CONSOLEAPPLICATION1\DEBUG\CLASS1.OBJ|F:\TEST\CONSOLEAPPLICATION1\CONSOLEAPPLICATION1\DEBUG\CONSOLEAPPLICATION1.OBJ|F:\TEST\CONSOLEAPPLICATION1\CONSOLEAPPLICATION1\DEBUG\STDAFX.OBJ
F:\TEST\CONSOLEAPPLICATION1\DEBUG\CONSOLEAPPLICATION1.ILK
F:\TEST\CONSOLEAPPLICATION1\DEBUG\CONSOLEAPPLICATION1.EXE
F:\TEST\CONSOLEAPPLICATION1\DEBUG\CONSOLEAPPLICATION1.PDB

Compilación en tiempo de diseño

En el IDE, los proyectos .vcxproj usan un conjunto de objetivos de MSBuild para obtener información adicional del proyecto y volver a generar archivos de salida. Algunos de estos objetivos solo se utilizan en compilaciones en tiempo de diseño, pero muchos de ellos se emplean tanto en compilaciones normales como en compilaciones en tiempo de diseño.

Para obtener información general sobre las compilaciones en tiempo de diseño, consulte la documentación sobre compilaciones en tiempo de diseño de CPS. Esta documentación solo es aplicable parcialmente a proyectos de Visual C++.

Los destinos CompileDesignTime y Compile mencionados en la documentación de compilaciones en tiempo de diseño nunca se ejecutan para proyectos de .vcxproj. Los proyectos de Visual C++ .vcxproj usan diferentes objetivos de tiempo de diseño para obtener información de IntelliSense.

Destinos en tiempo de diseño para la información de IntelliSense

Los destinos de tiempo de diseño usados en proyectos .vcxproj se definen en $(VCTargetsPath)\Microsoft.Cpp.DesignTime.targets.

El destino de GetClCommandLines recopila opciones del compilador para IntelliSense:

<Target
  Name="GetClCommandLines"
  Returns="@(ClCommandLines)"
  DependsOnTargets="$(DesignTimeBuildInitTargets);$(ComputeCompileInputsTargets)">
  • DesignTimeBuildInitTargets: destinos solo en tiempo de diseño, necesarios para la inicialización de compilación en tiempo de diseño. Entre otras cosas, estos destinos deshabilitan parte de la funcionalidad de compilación normal para mejorar el rendimiento.

  • ComputeCompileInputsTargets: un conjunto de destinos que modifica las opciones y elementos del compilador. Estos destinos se ejecutan tanto en tiempo de diseño como en compilaciones normales.

El destino llama a la tarea CLCommandLine para crear la línea de comandos que se usará para IntelliSense. De nuevo, a pesar de su nombre, puede controlar no solo las opciones cl, sino también las opciones de Clang y gcc. El tipo de opciones del compilador se controla mediante la propiedad ClangMode.

Actualmente, la línea de comandos generada por la tarea CLCommandLine siempre usa conmutadores CL (incluso en modo Clang) porque son más fáciles para que el motor de IntelliSense los analice.

Si va a agregar un destino que se ejecuta antes de la compilación, ya sea normal o en tiempo de diseño, asegúrese de que no interrumpe las compilaciones en tiempo de diseño ni afecta al rendimiento. La manera más sencilla de probar su objetivo es abrir una línea de comandos para desarrolladores y ejecutar este comando:

msbuild /p:SolutionDir=*solution-directory-with-trailing-backslash*;Configuration=Debug;Platform=Win32;BuildingInsideVisualStudio=true;DesignTimebuild=true /t:\_PerfIntellisenseInfo /v:d /fl /fileloggerparameters:PerformanceSummary \*.vcxproj

Este comando genera un registro de compilación detallado, msbuild.log, que tiene un resumen de rendimiento para los destinos y las tareas al final.

Asegúrese de usar Condition ="'$(DesignTimeBuild)' != 'true'" en todas las operaciones que solo tengan sentido para las compilaciones normales y no para las compilaciones en tiempo de diseño.

Objetivos en tiempo de diseño que generan códigos fuente

Esta característica está deshabilitada de forma predeterminada para proyectos nativos de escritorio y no se admite actualmente en proyectos almacenados en caché.

Si se definen metadatos GeneratorTarget para un elemento del proyecto, el objetivo se ejecuta automáticamente tanto al cargar el proyecto como al cambiar el archivo de origen.

Por ejemplo, para generar automáticamente archivos .cpp o .h a partir de archivos .xaml, los archivos de $(VSInstallDir)\MSBuild\Microsoft\WindowsXaml\v16.0\*\Microsoft.Windows.UI.Xaml.CPP.Targets definen estas entidades:

<ItemDefinitionGroup>
  <Page>
    <GeneratorTarget>DesignTimeMarkupCompilation</GeneratorTarget>
  </Page>
  <ApplicationDefinition>
    <GeneratorTarget>DesignTimeMarkupCompilation</GeneratorTarget>
  </ApplicationDefinition>
</ItemDefinitionGroup>
<Target Name="DesignTimeMarkupCompilation">
  <!-- BuildingProject is used in Managed builds (always true in Native) -->
  <!-- DesignTimeBuild is used in Native builds (always false in Managed) -->
  <CallTarget Condition="'$(BuildingProject)' != 'true' Or $(DesignTimeBuild) == 'true'" Targets="DesignTimeMarkupCompilationCT" />
</Target>

Para usar Task.HostObject para obtener el contenido no guardado de los archivos de origen, los destinos y la tarea deben registrarse como MsbuildHostObjects para los proyectos especificados en una pkgdef:

\[$RootKey$\\Projects\\{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\\MSBuildHostObjects\]
\[$RootKey$\\Projects\\{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\\MSBuildHostObjects\\DesignTimeMarkupCompilationCT;CompileXaml\]
@="{83046B3F-8984-444B-A5D2-8029DEE2DB70}"

Extensibilidad del proyecto de Visual C++ en el IDE de Visual Studio

El sistema de proyectos de Visual C++ se basa en VS Project Systemy usa sus puntos de extensibilidad. Sin embargo, la implementación de la jerarquía del proyecto es específica de Visual C++ y no se basa en CPS, por lo que la extensibilidad de la jerarquía se limita a los elementos del proyecto.

Páginas de propiedades del proyecto

Para obtener información general de diseño, consulte Framework Multi-Targeting for VC++ Projects.

En términos simples, las páginas de propiedades que ve en el cuadro de diálogo Propiedades del proyecto para un proyecto de C++ se definen mediante archivos regla. Un archivo de reglas especifica un conjunto de propiedades que se van a mostrar en una página de propiedades y cómo y dónde deben guardarse en el archivo de proyecto. Los archivos .xml son archivos de regla que usan el formato Xaml. Los tipos usados para serializarlos se describen en Microsoft.Build.Framework.XamlTypes. Para obtener más información sobre el uso de archivos de reglas en proyectos, consulte los archivos de reglas XML de página de propiedades.

Los archivos de regla se deben agregar al grupo de elementos de PropertyPageSchema:

<ItemGroup>
  <PropertyPageSchema Include="$(VCTargetsPath)$(LangID)\general.xml;"/>
  <PropertyPageSchema Include="$(VCTargetsPath)$(LangID)\general_file.xml">
    <Context>File</Context>
  </PropertyPageSchema>
</ItemGroup>

Context la visibilidad de las reglas de límites de metadatos, que también se controla mediante el tipo de regla, y puede tener uno de estos valores:

Project | File | PropertySheet

CPS admite otros valores para el tipo de contexto, pero no se usan en proyectos de Visual C++.

Si la regla debe estar visible en más de un contexto, use punto y coma (;) para separar los valores de contexto, como se muestra aquí:

<PropertyPageSchema Include="$(MyFolder)\MyRule.xml">
  <Context>Project;PropertySheet</Context>
</PropertyPageSchema>

Formato de regla y tipos principales

El formato de regla es sencillo, por lo que en esta sección solo se describen los atributos que afectan al aspecto de la regla en la interfaz de usuario.

<Rule
  Name="ConfigurationGeneral"
  DisplayName="General"
  PageTemplate="generic"
  Description="General"
  xmlns="http://schemas.microsoft.com/build/2009/properties">

El atributo PageTemplate define cómo se muestra la regla en las páginas de propiedades del cuadro de diálogo. El atributo puede tener uno de estos valores:

Atributo Descripción
generic Todas las propiedades se muestran en una página en encabezados de categoría
La regla puede estar visible para contextos de Project y PropertySheet, pero no File.

Ejemplo: $(VCTargetsPath)\1033\general.xml
tool Las categorías se muestran como subpáginas.
La regla puede estar visible en todos los contextos: Project, PropertySheet y File.
La regla solo está visible en Propiedades del proyecto si el proyecto tiene elementos con el ItemType definido en Rule.DataSource, a menos que el nombre de la regla se incluya en el grupo de elementos ProjectTools.

Ejemplo: $(VCTargetsPath)\1033\clang.xml
debugger La página se muestra como parte de la página de depuración.
Actualmente se omiten las categorías.
El nombre de la regla debe coincidir con el atributo ExportDebugger del objeto MEF del Lanzador de depuración.

Ejemplo: $(VCTargetsPath)\1033\debugger_local_windows.xml
custom Plantilla personalizada. El nombre de la plantilla debe coincidir con el atributo ExportPropertyPageUIFactoryProvider del objeto PropertyPageUIFactoryProvider MEF. Consulte Microsoft.VisualStudio.ProjectSystem.Designer.Properties.IPropertyPageUIFactoryProvider.

Ejemplo: $(VCTargetsPath)\1033\userMacros.xml

Si la regla usa una de las plantillas basadas en Property Grid, puede usar estos puntos de extensibilidad para sus propiedades:

Extensión de una regla

Si desea usar una regla existente, pero necesita agregar o quitar (es decir, ocultar) solo algunas propiedades, puede crear una regla de extensión de .

Invalidación de una regla

Quizás quiera que el conjunto de herramientas use la mayoría de las reglas predeterminadas del proyecto, pero reemplace solo una o algunas de ellas. Por ejemplo, supongamos que solo desea cambiar la regla de C/C++ para mostrar diferentes opciones del compilador. Usted puede proporcionar una nueva regla con el mismo nombre y nombre para mostrar que la regla existente e incluirla en el grupo de elementos de PropertyPageSchema después de la importación de objetivos predeterminados de C++. Solo se usa una regla con un nombre determinado en el proyecto y la última incluida en el grupo de elementos de PropertyPageSchema gana.

Elementos del proyecto

El archivo ProjectItemsSchema.xml define los valores de ContentType y ItemType para Elementos que se tratan como elementos de proyecto y define FileExtension elementos para determinar a qué grupo de elementos se agrega un nuevo archivo.

El archivo ProjectItemsSchema predeterminado se encuentra en $(VCTargetsPath)\1033\ProjectItemsSchema.xml. Para ampliarlo, debe crear un archivo de esquema con un nuevo nombre, como MyProjectItemsSchema.xml:

<ProjectSchemaDefinitions xmlns="http://schemas.microsoft.com/build/2009/properties">

  <ItemType Name="MyItemType" DisplayName="C/C++ compiler"/>

  <ContentType
    Name="MyItems"
    DisplayName="My items"
    ItemType=" MyItemType ">
  </ContentType>

  <FileExtension Name=".abc" ContentType=" MyItems"/>

</ProjectSchemaDefinitions>

A continuación, en el archivo de destinos, agregue:

<ItemGroup>
  <PropertyPageSchema Include="MyProjectItemsSchema.xml"/>
</ItemGroup>

Ejemplo: $(VCTargetsPath)\BuildCustomizations\masm.xml

Depuradores

El servicio de depuración en Visual Studio admite la extensibilidad para el motor de depuración. Para obtener más información, consulte estos ejemplos:

Para especificar los motores de depuración y otras propiedades para la sesión de depuración, debe implementar un componente MEF de selector de depuración y agregar una regla de debugger. Para obtener un ejemplo, consulte el archivo $(VCTargetsPath)\1033\debugger_local_windows.xml.

Desplegar

Los proyectos .vcxproj usan la extensibilidad de Visual Studio Project System para Implementar proveedores.

Comprobación actualizada

De forma predeterminada, la comprobación de compilación up-to-date requiere que durante la compilación se creen en la carpeta $(TlogLocation) los archivos de lectura .tlog y los archivos de escritura .tlog para todas las entradas y salidas de compilación.

Para usar una comprobación actualizada personalizada:

  1. Deshabilite la comprobación actualizada predeterminada agregando la funcionalidad NoVCDefaultBuildUpToDateCheckProvider en el archivo Toolset.targets:

    <ItemGroup>
      <ProjectCapability Include="NoVCDefaultBuildUpToDateCheckProvider" />
    </ItemGroup>
    
  2. Implemente su propio IBuildUpToDateCheckProvider.

Actualización del proyecto

Actualizador predeterminado de proyecto .vcxproj

El actualizador predeterminado del proyecto .vcxproj modifica PlatformToolset, ApplicationTypeRevision, la versión del conjunto de herramientas MSBuild y el .NET Framework. Los dos últimos siempre se cambian a los valores predeterminados de la versión de Visual Studio, pero PlatformToolset y ApplicationTypeRevision se pueden controlar mediante propiedades especiales de MSBuild.

El actualizador usa estos criterios para decidir si un proyecto se puede actualizar o no:

  1. Para los proyectos que definen ApplicationType y ApplicationTypeRevision, hay una carpeta con un número de revisión mayor que el actual.

  2. La propiedad _UpgradePlatformToolsetFor_<safe_toolset_name> se define para el conjunto de herramientas actual y su valor no es igual al conjunto de herramientas actual.

    En estos nombres de propiedad, <safe_toolset_name> representa el nombre del conjunto de herramientas con todos los caracteres no alfanuméricos reemplazados por un carácter de subrayado (_).

Cuando un proyecto se puede actualizar, participa en Solución Retargeting. Para obtener más información, consulte IVsTrackProjectRetargeting2.

Si desea adornar los nombres de proyecto en Explorador de soluciones cuando los proyectos usan un conjunto de herramientas específico, defina una propiedad _PlatformToolsetShortNameFor_<safe_toolset_name>.

Para obtener ejemplos de definiciones de propiedades de _UpgradePlatformToolsetFor_<safe_toolset_name> y _PlatformToolsetShortNameFor_<safe_toolset_name>, consulte el archivo de Microsoft.Cpp.Default.props. Para obtener ejemplos de uso, consulte el archivo $(VCTargetPath)\Microsoft.Cpp.Platform.targets.

Actualizador de proyecto personalizado

Para usar un objeto de actualizador de proyecto personalizado, implemente un componente MEF, como se muestra aquí:

/// </summary>
[Export("MyProjectUpgrader", typeof(IProjectRetargetHandler))]
[Export(typeof(IProjectRetargetHandler))]
[ExportMetadata("Name", "MyProjectUpgrader")]
[OrderPrecedence(20)]
[PartMetadata(ProjectCapabilities.Requires, ProjectCapabilities.VisualC)]

internal class MyProjectUpgrader: IProjectRetargetHandler
{
    // ...
}

El código puede importar y llamar al objeto .vcxproj de actualización predeterminado.

// ...
[Import("VCDefaultProjectUpgrader")]
// ...
    IProjectRetargetHandler Lazy<IProjectRetargetHandler>
    VCDefaultProjectUpgrader { get; set; }
// ...

IProjectRetargetHandler se define en Microsoft.VisualStudio.ProjectSystem.VS.dll y es similar a IVsRetargetProjectAsync.

Defina la propiedad VCProjectUpgraderObjectName para indicar al sistema de proyecto que use el objeto de actualizador personalizado:

<PropertyGroup>
  <VCProjectUpgraderObjectName>MyProjectUpgrader</VCProjectUpgraderObjectName>
</PropertyGroup>

Deshabilitar la actualización del proyecto

Para deshabilitar las actualizaciones del proyecto, use un valor de NoUpgrade:

<PropertyGroup>
  <VCProjectUpgraderObjectName>NoUpgrade</VCProjectUpgraderObjectName>
</PropertyGroup>

Caché y extensibilidad del proyecto

Para mejorar el rendimiento al trabajar con soluciones de C++ de gran tamaño en Visual Studio 2017, se introdujo la caché de proyectos . Se implementa como una base de datos de SQLite rellenada con datos del proyecto y, a continuación, se usa para cargar proyectos sin cargar proyectos de MSBuild o CPS en memoria.

Dado que no hay ningún objeto CPS presente para .vcxproj proyectos cargados desde la memoria caché, no se pueden crear los componentes MEF de la extensión que importan UnconfiguredProject o ConfiguredProject. Para admitir la extensibilidad, la memoria caché del proyecto no se usa cuando Visual Studio detecta si un proyecto usa (o es probable que use) extensiones MEF.

Estos tipos de proyecto siempre se cargan completamente y tienen objetos CPS en memoria, por lo que todas las extensiones MEF se crean para ellos:

  • Proyectos de startups

  • Los proyectos que tienen un actualizador de proyecto personalizado, es decir, definen una propiedad VCProjectUpgraderObjectName

  • Los proyectos que no tienen como destino Windows de escritorio, es decir, definen una propiedad ApplicationType

  • Proyectos de elementos compartidos (.vcxitems) y los proyectos que hacen referencia a ellos mediante la importación de proyectos .vcxitems.

Si no se detecta ninguna de estas condiciones, se crea una memoria caché del proyecto. La memoria caché incluye todos los datos del proyecto MSBuild necesarios para responder consultas get en interfaces VCProjectEngine. Esto significa que todas las modificaciones en el nivel de archivo de propiedades y destinos de MSBuild realizadas por una extensión solo deben funcionar en proyectos cargados desde la memoria caché.

Envío de la extensión

Para obtener información sobre cómo crear archivos VSIX, vea Envío de extensiones de Visual Studio. Para obtener información sobre cómo agregar archivos a ubicaciones de instalación especiales, por ejemplo, para agregar archivos en $(VCTargetsPath), vea Instalación fuera de la carpeta de extensiones.

Recursos adicionales

El sistema de compilación de Microsoft (MSBuild) proporciona el motor de compilación y el formato extensible basado en XML para los archivos de proyecto. Debe estar familiarizado con los conceptos básicos de MSBuild y cómo funciona MSBuild para Visual C++ con el fin de ampliar el sistema de proyectos de Visual C++.

Managed Extensibility Framework (MEF) proporciona las API de extensión que usa CPS y el sistema de proyectos de Visual C++. Para obtener información general sobre cómo CPS usa MEF, consulte CPS y MEF en la información general de VSProjectSystem de MEF.

Puede personalizar el sistema de compilación existente para agregar pasos de compilación o nuevos tipos de archivo. Para obtener más información, consulte MSBuild (Visual C++) Descripción general y Trabajar con las propiedades del proyecto.