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í:
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.
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.targetsEste 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.propsEstablece los valores predeterminados de los conjuntos de herramientas que usan los compiladores de Microsoft y tienen Windows como destino.
$(VCTargetsPath)
\Microsoft.Cpp.WindowsSDK.propsEste 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:
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.
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
yRC
, 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 claseMicrosoft.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 claseTrackedVCToolTask
. 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:
Inhabilite la comprobación actualizada predeterminada agregando la funcionalidad
NoVCDefaultBuildUpToDateCheckProvider
en el archivo Toolset.targets:<ItemGroup> <ProjectCapability Include="NoVCDefaultBuildUpToDateCheckProvider" /> </ItemGroup>
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:
Para los proyectos que definen
ApplicationType
yApplicationTypeRevision
, hay una carpeta con un número de revisión mayor que el actual.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.