Compartir a través de


Extensibilidad del sistema de proyectos de C++ de Visual Studio e integración de conjuntos de herramientas

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

Estructura de destinos 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)\
                Platforms\
                    $(Platform)\
                        PlatformToolsets\
                            $(PlatformToolset)
    Platforms\
        $(Platform)\
            PlatformToolsets\
                $(PlatformToolset)

La carpeta $(VCTargetsPath)\Platforms\ se usa cuando $(ApplicationType) está vacía para los 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 los archivos Toolset.props y Toolset.targets en ella.

Cada nombre de carpeta contenida en 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 Conjunto de herramientas de plataforma en el 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 admita 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 los archivos Platform.default.props, Platform.props y Platform.targets dentro de ella. Cree también una carpeta $(VCTargetsPath)\Platforms\MyPlatform\PlatformToolsets\ y cree al menos un conjunto de herramientas en ella.

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

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

Adición de un nuevo tipo de aplicación

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

Las propiedades $(ApplicationType) y $(ApplicationTypeRevision) no son visibles 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 accesorios y archivos de destino 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 carpetas de la plataforma $(Platform). Esta propiedad es

$(VCTargetsPath)\Platforms\$(Platform)

para aplicaciones de escritorio de Windows, y

$(VCTargetsPath)\Application Type\$(ApplicationType)\$(ApplicationTypeRevision)\Platforms\$(Platform)

para cualquier otra cosa.

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 .targets 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

Los archivos Toolset.props y Toolset.targets 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, algunas de las interfaces de usuario del IDE, como el contenido del cuadro de diálogo 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 le interesa que el conjunto de herramientas modifique o agregue algunos pasos de compilación, o 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 .targets 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 tienen Windows como 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 definidos 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 usa de manera predeterminada, se recomienda respetar esta separación.

Los destinos que se ejecutan dentro de cada paso se controlan mediante estas propiedades:

  • $(BuildGenerateSourcesTargets)

  • $(BuildCompileTargets)

  • $(BeforeBuildLinkTargets)

Cada paso también tiene las propiedades 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 destinos que se incluyen en cada paso:

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

Si observa los destinos, como _ClCompile, verá que no hacen nada directamente por sí mismos, sino que dependen de otros destinos, incluyendo 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 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 invalidar el destino ClCompile, es decir, pueden contener otra definición 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 la compatibilidad multiplataforma, el destino ClCompile no tiene que 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 de ejecución básica que permite especificar la 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 convierte las propiedades de MSBuild en modificadores de CL.exe, las 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 (modificadores 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 raramente usa esta tarea 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, consulte $(VCTargetsPath)\BuildCustomizations\masm.xml y, para su uso, consulte $(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 CL, MIDL y RC, y si desea el seguimiento automático de archivos de entrada y salida y la 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 de base, no hay ejemplos ni documentación para los detalles de la clase TrackedVCToolTask. Si esto es de especial interés, añada su voz a una solicitud en Developer Community.

Compilaciones incrementales y comprobaciones actualizadas

Los destinos de compilación incremental de MSBuild predeterminados usan los 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 destinos escriben información sobre todas las entradas y salidas en archivos tlog que tienen la 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 está actualizado. Los archivos .tlog también son el único origen de la comprobación actualizada de la compilación predeterminada en el IDE.

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

Microsoft.Build.CPPTasks.Common.dll define la clase base abstracta pública TrackedVCToolTask. 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 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 _WriteMasmTlogs en $(VCTargetsPath)\BuildCustomizations\masm.targets como ejemplo.

Archivos .tlog

Hay tres tipos de archivos .tlog: lectura, escritura y línea de comandos. Las compilaciones incrementales y las comprobaciones actualizadas usan los archivos .tlog de lectura y escritura en el IDE. Los archivos .tlog de la línea de comandos solo se usan en compilaciones incrementales.

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

La clase FlatTrackingData se puede usar para tener acceso a los 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 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 para comprobaciones actualizadas, por lo que el formato interno viene determinado por la tarea de MSBuild que las genera.

Formato .tlog de lectura

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

Un símbolo de intercalación (^) al principio de una línea indica uno o varios orígenes. Los orígenes que comparten las mismas dependencias están separados 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, suponga que los orígenes del proyecto se encuentran en F:\test\ConsoleApplication1\ConsoleApplication1. Si el archivo de origen, Class1.cpp, los incluye,

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

entonces 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 cómodo para algunas herramientas.

Formato .tlog de escritura

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

Un símbolo de intercalación (^) al principio de una línea indica uno o varios orígenes. Varios orígenes están separados por una barra vertical (|).

Los archivos de salida creados a partir de los orígenes deben aparecer después de los orígenes, 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 destinos de MSBuild para obtener información adicional del proyecto y volver a generar archivos de salida. Algunos de estos destinos solo se usan en compilaciones en tiempo de diseño, pero muchos de ellos se usan tanto en compilaciones normales y 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 de CPS para compilaciones en tiempo de diseño. 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 .vcxproj de Visual C++ usan diferentes destinos en tiempo de diseño para obtener información de IntelliSense.

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

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

El destino 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 inhabilitan parte de la funcionalidad de compilación normal para mejorar el rendimiento.

  • ComputeCompileInputsTargets: un conjunto de destinos que modifica las opciones y los 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 va a usar para IntelliSense. De nuevo, a pesar de su nombre, puede controlar no solo las opciones de CL, sino también las opciones de Clang y gcc. El tipo de modificadores del compilador se controla mediante la propiedad ClangMode.

Actualmente, la línea de comandos generada por la tarea CLCommandLine siempre usa modificadores CL (incluso en modo Clang) porque son más fáciles de analizar por parte del motor de IntelliSense.

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 el destino es abrir un símbolo del sistema 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.

Destinos en tiempo de diseño que generan orígenes

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

Si los metadatos GeneratorTarget se definen para un elemento de proyecto, el destino se ejecuta automáticamente cuando se carga el proyecto y cuando se cambia el archivo de origen.

Por ejemplo, para generar automáticamente archivos .cpp o .h a partir de archivos .xaml, los archivos $(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 un 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 el Sistema de proyectos de VS y usa sus puntos de extensión. 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 Multidestino de marco para proyectos de VC++.

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 de reglas. 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 de reglas son archivos .xml 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 Archivos de reglas XML de página de propiedades.

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

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

Los metadatos Context limitan la visibilidad de las reglas, 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, tal como se muestra aquí:

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

Formato y tipos principales de reglas

El formato de las reglas es sencillo, por lo que en esta sección solo se describen los atributos que afectan al aspecto de las reglas 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 el cuadro de diálogo Páginas de propiedades. El atributo puede tener uno de los siguientes valores:

Atributo Descripción
generic Todas las propiedades se muestran en una página bajo el encabezado Categoría
La regla puede ser visible para los contextos Project y PropertySheet, pero no File.

Ejemplo: $(VCTargetsPath)\1033\general.xml
tool Las categorías se muestran como subpáginas.
La regla puede ser 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 Depuración.
Actualmente se omiten las categorías.
El nombre de la regla debe coincidir con el atributo ExportDebugger del objeto Debug Selector MEF.

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

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

Si la regla usa una de las plantillas basadas en la cuadrícula de propiedades, puede usar estos puntos de extensión 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.

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 que muestre distintos modificadores del compilador. Puede proporcionar una nueva regla con el mismo nombre y el mismo nombre para mostrar que la regla existente e incluirla en el grupo de elementos PropertyPageSchema después de la importación de destinos de cpp predeterminados. Solo se usa una regla con un nombre determinado en el proyecto y la última incluida en el grupo de elementos PropertyPageSchema gana.

Artículos de proyectos

El archivo ProjectItemsSchema.xml define los valores ContentType y ItemType para los elementos que se tratan como elementos de proyecto y define los elementos FileExtension 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 por ejemplo 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 Debug Launches y agregar una regla debugger. Para obtener un ejemplo, consulte el archivo $(VCTargetsPath)\1033\debugger_local_windows.xml.

Implementar

Los proyectos .vcxproj usan la extensibilidad del Visual Studio Project System para implementar proveedores.

Comprobación actualizada de la compilación

De manera predeterminada, la comprobación actualizada de la compilación requiere que se creen archivos .tlog de lectura y de escritura en la carpeta $(TlogLocation) durante la compilación para todas las entradas y salidas de compilación.

Para usar una comprobación actualizada personalizada:

  1. Inhabilite 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 de proyecto

Actualizador del proyecto .vcxproj predeterminado

El actualizador de proyectos .vcxproj predeterminado cambia PlatformToolset, ApplicationTypeRevision, la versión del conjunto de herramientas de 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 pueden estar controlados por 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 guion bajo (_).

Cuando se puede actualizar un proyecto, participa en Cambio de destino de la solución. Para obtener más información, consulte IVsTrackProjectRetargeting2.

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

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

Actualizador de proyectos personalizado

Para usar un objeto de actualizador de proyectos 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 de actualizador de .vcxproj 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 proyectos que use el objeto de actualizador personalizado:

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

Inhabilitar la actualización de proyectos

Para inhabilitar las actualizaciones de proyectos, use un valor NoUpgrade:

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

Caché y extensibilidad de proyectos

Para mejorar el rendimiento al trabajar con soluciones de C++ de gran tamaño en Visual Studio 2017, se introdujo el caché de proyecto. 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 la memoria.

Dado que no hay ningún objeto CPS presente para proyectos .vcxproj cargados de la memoria caché, los componentes MEF de la extensión que importan UnconfiguredProject o ConfiguredProject no se pueden crear. 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 de MEF.

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

  • Proyecto de inicio

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

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

  • Los 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 de MSBuild necesarios para responder a las consultas get en las interfaces VCProjectEngine. Esto significa que todas las modificaciones en el nivel de archivo .props y .targets de MSBuild realizadas por una extensión solo deben funcionar en proyectos cargados desde la memoria caché.

Publicación de la extensión

Para obtener información sobre cómo crear archivos VSIX, consulte Publicación 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), consulte 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 de MSBuild básicos y con 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 Introducción a 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 Introducción a MSBuild (Visual C++) y Trabajar con propiedades de proyecto.