Share via


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 Common Project System (CPS) de Visual Studio y proporciona puntos de extensibilidad específicos adicionales de C++ 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 $(VCTargetsPath) carpeta raíz:

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

La $(VCTargetsPath)\carpeta 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 archivos Toolset.props y Toolset.targets en él.

Cada nombre de carpeta de 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í:

The Platform Toolset property in the project Property Pages dialog

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 archivos Platform.default.props, Platform.props y Platform.targets en él. Cree también una $(VCTargetsPath)carpeta \Platforms\MyPlatform\PlatformToolsets\ y cree al menos un conjunto de herramientas en él.

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

The New platform choice in the New Project Platform dialog

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 $(VCTargetsPath)carpeta \Application Type\MyApplicationType\1.0 y cree un archivo Defaults.props en él. También debe crear una $(VCTargetsPath)carpeta \ApplicationType\MyApplicationType\1.0\Platforms y crear al menos una plataforma en ella.

$(ApplicationType) y $(ApplicationTypeRevision) las propiedades no están 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 .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\*.Apoyos
    $(VCTargetsPath)\Tipo\\$(ApplicationType)de aplicación Default.props
    $(VCTargetsPath)\Tipo$(ApplicationTypeRevision)\$(ApplicationType)\\de aplicación Default.props
    $(VCTargetsPath)\Plataformas de tipo$(ApplicationTypeRevision)\\$(ApplicationType)\de aplicación Platform.default.props\$(Platform)\
    $(VCTargetsPath)\ImportAfter\Default\*.Apoyos

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\*.Apoyos
    $(VCTargetsPath)\Plataformas\\$(Platform)Platform.default.props
    $(VCTargetsPath)\ImportAfter\Default\*.Apoyos

Usaremos la $(_PlatformFolder) propiedad para almacenar las ubicaciones de carpetas de la $(Platform) plataforma. Esta propiedad es

$(VCTargetsPath)\Plataformas\$(Platform)

para aplicaciones de escritorio de Windows y

$(VCTargetsPath)\Plataformas de tipos de$(ApplicationTypeRevision)\$(ApplicationType)\\aplicación\$(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\*.Apoyos
            $(_PlatformFolder)\PlatformToolsets\\$(PlatformToolset)Toolset.props
            $(_PlatformFolder)\ImportAfter\*.Apoyos

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\*.Objetivos
                $(_PlatformFolder)\PlatformToolsets\\$(PlatformToolset)Toolset.target
                $(_PlatformFolder)\ImportAfter\*.Objetivos

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 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 usa de forma predeterminada, todavía 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 propiedades Before y After.

<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, 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 ClCompile destino 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 ClCompile destino, es decir, pueden contener otra ClCompile definición 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 ClCompile destino no tiene que llamar a CL.exe. También puede llamar a Clang, gcc u otros compiladores mediante las tareas adecuadas de MSBuild.

El ClCompile destino no debe tener ninguna dependencia excepto el SelectClCompile destino, 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 CL tarea traduce las propiedades de MSBuild en modificadores 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.

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 BuildCustomizations masm.xml y, para su uso, consulta\$(VCTargetsPath)\$(VCTargetsPath) BuildCustomizations\masm.targets.\

    • Tarea 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 CLcasos , 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 Microsoft.Build.CPPTasks.TrackedVCToolTask clase . En la actualidad, aunque hay documentación para la clase ToolTask base, no hay ejemplos ni documentación para los detalles de la TrackedVCToolTask clase. Si esto sería de especial interés, agregue su voz a una solicitud en la Comunidad de desarrolladores.

Compilaciones incrementales y comprobaciones actualizadas

Los destinos de compilación incremental de MSBuild predeterminados usan Inputs y Outputs atributos. 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 de 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 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 TrackedVCToolTask clase base 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 GetOutOfDateItems tarea 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 WriteLinesToFile tarea . Vea el _WriteMasmTlogs destino 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 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 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 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 .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, incluye,

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

después, 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

Escribir archivos .tlog (*.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 código fuente 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 en compilaciones normales y 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 CompileDesignTime destinos y Compile mencionados en la documentación de compilaciones en tiempo de diseño nunca se ejecutan para proyectos .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 GetClCommandLines destino 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 los elementos del compilador. Estos destinos se ejecutan tanto en tiempo de diseño como en compilaciones normales.

El destino llama a la CLCommandLine tarea 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 cl, sino también las opciones de Clang y gcc. El tipo de modificadores del compilador se controla mediante la ClangMode propiedad .

Actualmente, la línea de comandos generada por la CLCommandLine tarea siempre usa modificadores CL (incluso en modo Clang) porque son más fáciles de analizar el 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 GeneratorTarget los metadatos 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 $(VSInstallDir)\archivos Microsoft WindowsXaml\de MSBuild\\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 System y 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, vea 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 de 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 de regla 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, vea Archivos de reglas XML de página de propiedades.

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

<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 PageTemplate atributo define cómo se muestra la regla en el cuadro de diálogo Páginas de propiedades . 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 ser visible para Project los contextos 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: Projecty FilePropertySheet .
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 ProjectTools elementos.

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 del objeto ExportDebugger Debug Selector MEF.

Ejemplo: $(VCTargetsPath)\1033\debugger_local_windows.xml
custom Plantilla personalizada. El nombre de la plantilla debe coincidir con el ExportPropertyPageUIFactoryProvider atributo del PropertyPageUIFactoryProvider objeto MEF. Vea 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.

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 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 PropertyPageSchema grupo de elementos 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 PropertyPageSchema elementos gana.

Artículos de proyectos

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

Implementar

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 actualizada requiere que los archivos .tlog y .tlog de lectura se creen en la carpeta durante la $(TlogLocation) compilación 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 NoVCDefaultBuildUpToDateCheckProvider funcionalidad en el archivo Toolset.targets :

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

Actualización del proyecto

Actualizador de proyectos .vcxproj predeterminado

El actualizador de proyectos .vcxproj predeterminado cambia la PlatformToolsetversión del conjunto de herramientas de , ApplicationTypeRevision, MSBuild y .NET Framework. Los dos últimos siempre se cambian a los valores predeterminados de la versión de Visual Studio, pero PlatformToolset las ApplicationTypeRevision propiedades especiales de MSBuild pueden controlarlas.

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 se puede actualizar un proyecto, participa en el destino de la solución. Para obtener más información, vea IVsTrackProjectRetargeting2.

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

Para obtener ejemplos de definiciones de _UpgradePlatformToolsetFor_<safe_toolset_name> propiedades y _PlatformToolsetShortNameFor_<safe_toolset_name> , vea el archivo Microsoft.Cpp.Default.props . Para obtener ejemplos de uso, consulte el $(VCTargetPath)\archivo 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 upgrader .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 VCProjectUpgraderObjectName propiedad 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 NoUpgrade valor:

<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é del 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 memoria.

Dado que no hay objetos CPS presentes para proyectos .vcxproj cargados desde 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 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 inicio

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

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

  • 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 get a las consultas en VCProjectEngine las interfaces. 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 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, vea Información general de MSBuild (Visual C++) y Trabajar con propiedades del proyecto.