Visual Studio C++ 项目系统扩展性和工具集集成

Visual C++ 项目系统用于 .vcxproj 文件。 它基于 Visual Studio Common Project System (CPS), 并提供额外的 C++ 特定扩展点,以便轻松集成新工具集、生成体系结构和目标平台。

C++ MSBuild 目标结构

所有 .vcxproj 文件都导入这些文件:

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

这些文件本身定义很少。 而是基于以下属性值导入其他文件:

  • $(ApplicationType)

    示例:Windows 应用商店、Android、Linux

  • $(ApplicationTypeRevision)

    这必须是一个有效的版本字符串,格式为 major.minor[.build[.revision]]。

    示例:1.0、10.0.0.0

  • $(Platform)

    由于历史原因,生成体系结构名为“平台”。

    示例:Win32、x86、x64、ARM

  • $(PlatformToolset)

    示例:v140、v141、v141_xp、llvm

这些属性值指定根文件夹下 $(VCTargetsPath) 的文件夹名称:

$(VCTargetsPath)\
    应用程序类型\
        $(ApplicationType)\
            $(ApplicationTypeRevision)\
                平台\
                    $(Platform)\
                        PlatformToolsets\
                            $(PlatformToolset)
    平台\
        $(Platform)\
            PlatformToolsets\
                $(PlatformToolset)

$(VCTargetsPath)\Windows 桌面项目为空时$(ApplicationType),将使用 Platforms\ 文件夹。

添加新平台工具集

若要为现有 Win32 平台添加新的工具集,请在 \Platforms\Win32\PlatformToolsets\下创建 MyToolset 文件夹,并在其中创建 Toolset.propsToolset.targets 文件。$(VCTargetsPath)

PlatformToolsets的每个文件夹名称都以指定平台的可用平台工具集的形式显示在“项目属性”对话框中,如下所示:

The Platform Toolset property in the project Property Pages dialog

在工具集支持的每个现有平台文件夹中创建类似的 MyToolset 文件夹和 Toolset.propsToolset.targets 文件。

添加新平台

若要添加新平台,例如“MyPlatform”,请在 \Platforms\$(VCTargetsPath)创建 MyPlatform 文件夹,并在其中创建 Platform.default.propsPlatform.propsPlatform.targets 文件。 同时创建 $(VCTargetsPath)\Platforms\MyPlatform\PlatformToolsets\ 文件夹,并在其中创建至少一个工具集。

每个文件夹的“平台”文件夹下的所有文件夹名称,并$(ApplicationTypeRevision)作为项目的可用平台选项显示在 IDE $(ApplicationType) 中。

The New platform choice in the New Project Platform dialog

添加新的应用程序类型

若要添加新的应用程序类型,请在 \Application Type\ 下创建 MyApplicationType 文件夹,并在其中创建 Defaults.props 文件。$(VCTargetsPath) 应用程序类型至少需要一个修订,因此还要创建 $(VCTargetsPath)\Application Type\MyApplicationType\1.0 文件夹,并在其中创建 Defaults.props 文件。 还应创建 $(VCTargetsPath)\ApplicationType\MyApplicationType\1.0\Platforms 文件夹,并在其中创建至少一个平台。

$(ApplicationType)$(ApplicationTypeRevision) 属性在用户界面中不可见。 它们在项目模板中定义,在创建项目后无法更改。

.vcxproj 导入树

Microsoft C++ 属性和目标文件的导入简化树如下所示:

$(VCTargetsPath)\Microsoft.Cpp.Default.props
    $(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props
    $(VCTargetsPath)\ImportBefore\Default\*。道具
    $(VCTargetsPath)\应用程序类型\\$(ApplicationType)Default.props
    $(VCTargetsPath)\应用程序类型$(ApplicationTypeRevision)\$(ApplicationType)\\Default.props
    $(VCTargetsPath)\应用程序类型$(ApplicationTypeRevision)\$(ApplicationType)\\平台\$(Platform)\Platform.default.props
    $(VCTargetsPath)\ImportAfter\Default\*。道具

Windows 桌面项目未定义 $(ApplicationType),因此它们仅导入

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

我们将使用该 $(_PlatformFolder) 属性来保存 $(Platform) 平台文件夹位置。 此属性为

$(VCTargetsPath)\平台\$(Platform)

适用于 Windows 桌面应用,以及

$(VCTargetsPath)\应用程序类型\\$(ApplicationType)\$(ApplicationTypeRevision)平台\$(Platform)

对于其他所有内容。

属性文件按以下顺序导入:

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

目标文件按以下顺序导入:

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

如果需要为工具集定义一些默认属性,可以将文件添加到相应的 ImportBefore 和 ImportAfter 文件夹。

创作 Toolset.props 和 Toolset.targets 文件

使用此工具集时,Toolset.propsToolset.targets 文件可以完全控制生成过程中发生的情况。 它们还可以控制可用的调试器、某些 IDE 用户界面,例如“属性页”对话框中的内容,以及项目行为的其他一些方面。

尽管工具集可以覆盖整个生成过程,但通常你只想让工具集修改或添加一些生成步骤,或者将不同的生成工具用作现有生成过程的一部分。 为了实现此目标,工具集可以导入的一些常见属性和目标文件。 根据工具集要执行的操作,这些文件可用于用作导入或示例:

  • $(VCTargetsPath)\Microsoft.CppCommon.targets

    此文件定义本机生成过程的主要部分,并导入:

    • $(VCTargetsPath)\Microsoft.CppBuild.targets

    • $(VCTargetsPath)\Microsoft.BuildSteps.targets

    • $(MSBuildToolsPath)\Microsoft.Common.Targets

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

    设置使用 Microsoft 编译器和目标 Windows 的工具集的默认值。

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

    此文件确定 Windows SDK 位置,并为面向 Windows 的应用定义一些重要属性。

将特定于工具集的目标与默认 C++ 生成过程集成

默认 C++ 生成过程在 Microsoft.CppCommon.targets定义。 没有调用任何特定生成工具的目标;它们指定主要生成步骤、其顺序和依赖项。

C++ 生成有三个主要步骤,这些步骤由以下目标表示:

  • BuildGenerateSources

  • BuildCompile

  • BuildLink

由于每个生成步骤都可以独立执行,因此在一个步骤中运行的目标不能依赖于作为不同步骤一部分运行的目标中定义的项组和属性。 此划分允许某些生成性能优化。 虽然默认情况下未使用它,但仍鼓励你遵守这种分离。

在每个步骤中运行的目标由以下属性控制:

  • $(BuildGenerateSourcesTargets)

  • $(BuildCompileTargets)

  • $(BeforeBuildLinkTargets)

每个步骤还具有 Before 和 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)" />

有关每个步骤中包含的目标示例,请参阅 Microsoft.CppBuild.targets 文件:

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

如果你查看目标,例如 _ClCompile,你将看到他们自己不直接执行任何操作,而是依赖于其他目标,包括 ClCompile

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

ClCompile和其他特定于生成工具的目标在 Microsoft.CppBuild.targets定义为空目标:

<Target Name="ClCompile"/>

ClCompile由于目标为空,除非由工具集重写,否则不会执行任何实际生成操作。 工具集目标可以替代ClCompile目标,即导入 Microsoft.CppBuild.targets可以包含另一个ClCompile定义:

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

尽管在 Visual Studio 实现跨平台支持之前创建了名称, ClCompile 但目标不必调用 CL.exe。 它还可以使用适当的 MSBuild 任务调用 Clang、gcc 或其他编译器。

目标 ClCompile 不应具有任何依赖项,但目标除外 SelectClCompile ,单个文件编译命令需要在 IDE 中工作。

在工具集目标中使用的 MSBuild 任务

若要调用实际的生成工具,目标需要调用 MSBuild 任务。 有一个基本的 Exec 任务 ,可用于指定要运行的命令行。 但是,生成工具通常有许多选项,输入。 和输出来跟踪增量生成,因此为它们执行特殊任务更有意义。 例如,任务将 CL MSBuild 属性转换为 CL.exe 开关,将其写入响应文件中,并调用 CL.exe。 它还跟踪所有输入和输出文件,以便以后进行增量生成。 有关详细信息,请参阅增量生成和最新的检查

Microsoft.Cpp.Common.Tasks.dll 实现以下任务:

  • BSCMake

  • CL

  • ClangCompile (clang-gcc 开关)

  • LIB

  • LINK

  • MIDL

  • Mt

  • RC

  • XDCMake

  • CustomBuild (如 Exec,但具有输入和输出跟踪)

  • SetEnv

  • GetOutOfDateItems

如果你有一个执行与现有工具相同的操作的工具,并且具有类似的命令行开关(如 clang-cl 和 CL),则可以对两者使用相同的任务。

如果需要为生成工具创建新任务,可以从以下选项中进行选择:

  1. 如果很少使用此任务,或者如果几秒对生成无关紧要,则可以使用 MSBuild“内联”任务:

    • Xaml 任务(自定义生成规则)

      有关 Xaml 任务声明的一个示例,请参阅 $(VCTargetsPath)\BuildCustomizations\masm.xml 及其用法,请参阅 $(VCTargetsPath)\BuildCustomizations\masm.targets。

    • 代码任务

  2. 如果想要更好的任务性能或只需要更复杂的功能,请使用常规的 MSBuild 任务写入 过程。

    如果工具命令行上未列出该工具的所有输入和输出,如工具命令行中CLMIDLRC所示,以及需要自动输入和输出文件跟踪和 .tlog 文件创建,请从Microsoft.Build.CPPTasks.TrackedVCToolTask类派生任务。 目前,虽然基本 ToolTask 类有文档,但没有有关该类的详细信息 TrackedVCToolTask 的示例或文档。 如果这是特别感兴趣的,请在开发者社区将语音添加到请求中。

增量生成和最新检查

默认的 MSBuild 增量生成目标使用 InputsOutputs 属性。 如果指定它们,则 MSBuild 仅当任何输入的时间戳都高于所有输出时,才会调用目标。 由于源文件通常包括或导入其他文件,并且生成工具会根据工具选项生成不同的输出,因此很难在 MSBuild 目标中指定所有可能的输入和输出。

为了管理此问题,C++ 生成使用不同的技术来支持增量生成。 大多数目标不会指定输入和输出,因此,始终在生成期间运行。 目标调用的任务会将有关所有输入和输出 的信息写入具有 .tlog 扩展名的 tlog 文件中。 更高版本的 .tlog 文件用于检查已更改和需要重新生成的内容,以及最新的内容。 .tlog 文件也是 IDE 中默认内部版本最新检查的唯一源。

若要确定所有输入和输出,本机工具任务使用 MSBuild 提供的 tracker.exe 和 FileTracker 类。

Microsoft.Build.CPPTasks.Common.dll 定义 TrackedVCToolTask 公共抽象基类。 大多数本机工具任务都派生自此类。

从 Visual Studio 2017 update 15.8 开始,可以使用 GetOutOfDateItems 在 Microsoft.Cpp.Common.Tasks.dll 中实现的任务为具有已知输入和输出的自定义目标生成 .tlog 文件。 或者,可以使用任务创建它们 WriteLinesToFile_WriteMasmTlogs请参阅 BuildCustomizations\masm.targets 中的$(VCTargetsPath)\目标作为示例。

.tlog 文件

有三种类型的 .tlog 文件: 读取写入命令行。 读取和写入 .tlog 文件由增量生成和 IDE 中的最新检查使用。 命令行 .tlog 文件仅用于增量生成。

MSBuild 提供以下帮助程序类来读取和写入 .tlog 文件:

FlatTrackingData 类可用于访问读取和写入 .tlog 文件,以及标识比输出更新的输入,或者如果缺少输出。 它用于最新的检查。

命令行 .tlog 文件包含有关生成中使用的命令行的信息。 它们仅用于增量生成,而不是最新的检查,因此内部格式由生成它们的 MSBuild 任务确定。

读取 .tlog 格式

读取 .tlog 文件 (*.read.*.tlog) 包含有关源文件及其依赖项的信息。

行开头的插入点 (^) 指示一个或多个源。 共享相同依赖项的源由垂直条分隔(|)。

依赖项文件在源之后列出,每个文件在其自己的行中列出。 所有文件名都是完整路径。

例如,假设项目源位于 F:\test\ConsoleApplication1\ConsoleApplication1\ ConsoleApplication1 中。 如果源文件 Class1.cpp 包含以下内容:

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

然后,CL.read.1.tlog 文件包含源文件,后跟其两个依赖项:

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

不需要以大写形式编写文件名,但对于某些工具来说,这是一种方便。

写入 .tlog 格式

编写 .tlog (*.write.*.tlog) 文件连接源和输出。

行开头的插入点 (^) 指示一个或多个源。 多个源由垂直条分隔(|)。

从源生成的输出文件应列在源之后,每个文件在其自己的行中列出。 所有文件名都必须是完整路径。

例如,对于具有附加源文件 Class1.cpp 的简单 ConsoleApplication 项目, link.write.1.tlog 文件可能包含:

^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

设计时生成

在 IDE 中,.vcxproj 项目使用一组 MSBuild 目标从项目获取其他信息并重新生成输出文件。 其中一些目标仅用于设计时生成,但其中许多目标用于常规生成和设计时生成。

有关设计时生成的常规信息,请参阅设计时生成的 CPS 文档。 本文档仅部分适用于 Visual C++ 项目。

Compile设计CompileDesignTime时生成文档中提及的目标永远不会针对 .vcxproj 项目运行。 Visual C++ .vcxproj 项目使用不同的设计时目标来获取 IntelliSense 信息。

IntelliSense 信息的设计时目标

.vcxproj 项目中使用的设计时目标在 Microsoft.Cpp.DesignTime.targets$(VCTargetsPath)\定义。

目标 GetClCommandLines 收集 IntelliSense 的编译器选项:

<Target
  Name="GetClCommandLines"
  Returns="@(ClCommandLines)"
  DependsOnTargets="$(DesignTimeBuildInitTargets);$(ComputeCompileInputsTargets)">
  • DesignTimeBuildInitTargets – 设计时仅目标,设计时生成初始化所需的目标。 除此之外,这些目标还禁用某些常规生成功能以提高性能。

  • ComputeCompileInputsTargets – 一组修改编译器选项和项的目标。 这些目标在设计时和常规生成中运行。

目标调用 CLCommandLine 任务以创建用于 IntelliSense 的命令行。 同样,尽管名称如此,但它不仅可以处理 CL 选项,还可以处理 Clang 和 gcc 选项。 编译器开关的类型由 ClangMode 属性控制。

目前,任务生成的 CLCommandLine 命令行始终使用 CL 开关(即使在 Clang 模式下),因为它们更易于 IntelliSense 引擎进行分析。

如果要添加在编译之前运行的目标,无论是常规版本还是设计时,请确保它不会中断设计时生成或影响性能。 测试目标的最简单方法是打开开发人员命令提示符并运行以下命令:

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

此命令会生成详细的生成日志 msbuild.log,该日志具有最终目标和任务的性能摘要。

请确保 Condition ="'$(DesignTimeBuild)' != 'true'" 在所有操作中使用,这些操作仅适用于常规生成,而不适用于设计时生成。

生成源的设计时目标

默认情况下,对于桌面本机项目,此功能处于禁用状态,目前缓存项目不支持此功能。

如果 GeneratorTarget 为项目项定义了元数据,则当加载项目和更改源文件时,目标会自动运行。

例如,若要从 .xaml 文件自动生成 .cpp 或 .h 文件,$(VSInstallDir)\MSBuild\Microsoft\WindowsXaml\v16.0\*\Microsoft.Windows.UI.Xaml.CPP.Targets 文件定义以下实体:

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

Task.HostObject若要用于获取源文件的未保存内容,应将目标和任务注册为 pkgdef 中给定项目的 MsbuildHostObjects

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

Visual Studio IDE 中的 Visual C++ 项目扩展性

Visual C++ 项目系统基于 VS 项目系统,并使用其扩展点。 但是,项目层次结构实现特定于 Visual C++ 而不是基于 CPS,因此层次结构扩展性仅限于项目项。

项目属性页

有关常规设计信息,请参阅 VC++ 项目的框架多目标。

简单来说,在 C++ 项目的“项目属性”对话框中看到的属性页由规则文件定义。 规则文件指定要在属性页上显示的属性集,以及它们应保存在项目文件中的方式和位置。 规则文件是使用 Xaml 格式的 .xml 文件。 用于序列化它们的类型在 Microsoft.Build.Framework.XamlTypes介绍。 有关在项目中使用规则文件的详细信息,请参阅 属性页 XML 规则文件

必须将规则文件添加到 PropertyPageSchema 项组:

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

Context 元数据限制规则可见性,该可见性也受规则类型控制,并且可以具有以下值之一:

Project | File | PropertySheet

CPS 支持上下文类型的其他值,但在 Visual C++ 项目中不使用它们。

如果规则应在多个上下文中可见,请使用分号(;)分隔上下文值,如下所示:

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

规则格式和主要类型

规则格式非常简单,因此本部分仅描述影响规则在用户界面中外观的属性。

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

PageTemplate属性定义规则在“属性页”对话框中的显示方式。 该属性可以具有以下值之一:

Attribute 说明
generic 所有属性显示在类别标题下的一页上
规则对上下文PropertySheet可见,但不能FileProject

示例: $(VCTargetsPath)\1033\general.xml
tool 类别显示为子页。
规则可在所有上下文中可见: ProjectPropertySheetFile
只有在项目具有具有 ItemType 定义 Rule.DataSource项的项目时,该规则才会在项目属性中可见,除非规则名称包含在 ProjectTools 项组中。

示例: $(VCTargetsPath)\1033\clang.xml
debugger 该页显示为“调试”页的一部分。
当前忽略类别。
规则名称应与调试启动器 MEF 对象的 ExportDebugger 属性匹配。

示例: $(VCTargetsPath)\1033\debugger_local_windows.xml
custom 自定义模板。 模板的名称应与 MEF 对象的属性PropertyPageUIFactoryProvider匹配ExportPropertyPageUIFactoryProvider。 请参阅 Microsoft.VisualStudio.ProjectSystem.Designers.Properties.IPropertyPageUIFactoryProvider

示例: $(VCTargetsPath)\1033\userMacros.xml

如果规则使用基于属性网格的模板之一,则它可以对其属性使用这些扩展点:

扩展规则

如果要使用现有规则,但需要添加或删除(即隐藏)仅几个属性,则可以创建 扩展规则

重写规则

也许你希望工具集使用大部分项目默认规则,但只替换其中一个或几个规则。 例如,假设只想更改 C/C++ 规则以显示不同的编译器开关。 你可以提供与现有规则相同的名称和显示名称的新规则,并在导入默认 cpp 目标后将其 PropertyPageSchema 包含在项组中。 项目中只使用具有给定名称的一个规则,最后一个规则包含在 PropertyPageSchema 项组中。

项目物料

ProjectItemsSchema.xml 文件定义ContentType被视为项目项的项的和ItemType值,并定义FileExtension元素以确定将新文件添加到的项组。

默认 ProjectItemsSchema 文件位于 1033 ProjectItemsSchema.xml$(VCTargetsPath)\\ 若要扩展它,必须创建具有新名称的架构文件,例如 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>

然后在目标文件中,添加:

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

示例: $(VCTargetsPath)\BuildCustomizations\masm.xml

调试器

Visual Studio 中的调试服务支持调试引擎的扩展性。 有关详细信息,请参阅以下示例:

若要为调试会话指定调试引擎和其他属性,必须实现 调试启动器 MEF 组件,并添加 debugger 规则。 有关示例,请参阅 $(VCTargetsPath)\1033\debugger_local_windows.xml 文件。

部署

.vcxproj 项目使用用于部署提供程序Visual Studio 项目系统扩展性。

构建最新的检查

默认情况下,生成最新的检查要求在所有生成输入和输出生成期间在文件夹中创建$(TlogLocation)读取 .tlog 和写入 .tlog 文件。

若要使用自定义最新检查,

  1. 通过在 Toolset.targets 文件中添加NoVCDefaultBuildUpToDateCheckProvider功能来禁用默认的最新检查:

    <ItemGroup>
      <ProjectCapability Include="NoVCDefaultBuildUpToDateCheckProvider" />
    </ItemGroup>
    
  2. 实现自己的 IBuildUpToDateCheckProvider

项目升级

默认 .vcxproj 项目升级程序

默认的 .vcxproj 项目升级程序会更改 PlatformToolsetMSBuild ApplicationTypeRevision工具集版本和 .NET Framework。 最后两个始终更改为 Visual Studio 版本默认值,但PlatformToolsetApplicationTypeRevision可由特殊的 MSBuild 属性控制。

升级程序使用以下条件来确定是否可以升级项目:

  1. 对于定义和ApplicationTypeRevision定义的ApplicationType项目,有一个具有比当前修订号更高的文件夹。

  2. 该属性 _UpgradePlatformToolsetFor_<safe_toolset_name> 为当前工具集定义,其值不等于当前工具集。

    在这些属性名称中, <safe_toolset_name> 表示工具集名称,其中包含由下划线(_)替换的所有非字母数字字符。

升级项目后,它将参与 解决方案重定目标。 有关详细信息,请参阅 IVsTrackProjectRetargeting2

如果要在项目使用特定工具集时在解决方案资源管理器装饰项目名称,请定义属性_PlatformToolsetShortNameFor_<safe_toolset_name>

有关属性定义的示例 _UpgradePlatformToolsetFor_<safe_toolset_name>_PlatformToolsetShortNameFor_<safe_toolset_name> 请参阅 Microsoft.Cpp.Default.props 文件。 有关用法示例,请参阅 $(VCTargetPath)\Microsoft.Cpp.Platform.targets 文件。

自定义项目升级程序

若要使用自定义项目升级程序对象,请实现 MEF 组件,如下所示:

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

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

代码可以导入并调用默认的 .vcxproj 升级程序对象:

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

IProjectRetargetHandler在 Microsoft.VisualStudio.ProjectSystem.VS.dll定义,类似于 IVsRetargetProjectAsync.

定义属性 VCProjectUpgraderObjectName 以告知项目系统使用自定义升级程序对象:

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

禁用项目升级

若要禁用项目升级,请使用值 NoUpgrade

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

项目缓存和扩展性

为了在 Visual Studio 2017 中使用大型 C++ 解决方案时提高性能, 引入了项目缓存 。 它作为填充项目数据的 SQLite 数据库实现,然后用于加载项目,而无需将 MSBuild 或 CPS 项目加载到内存中。

由于缓存中加载的 .vcxproj 项目不存在 CPS 对象,因此无法创建导入 UnconfiguredProjectConfiguredProject 无法创建的扩展的 MEF 组件。 为了支持扩展性,Visual Studio 检测到项目是使用(还是可能使用)MEF 扩展时,不会使用项目缓存。

这些项目类型始终完全加载,并且内存中具有 CPS 对象,因此会为其创建所有 MEF 扩展:

  • 启动项目

  • 具有自定义项目升级程序的项目,即定义 VCProjectUpgraderObjectName 属性

  • 不面向桌面 Windows 的项目,即定义 ApplicationType 属性

  • 共享项项目(.vcxitems)和通过导入 .vcxitems 项目引用它们的任何项目。

如果未检测到这些条件,则会创建项目缓存。 缓存包括用于回答 get 接口查询 VCProjectEngine 所需的 MSBuild 项目中的所有数据。 这意味着,扩展完成的 MSBuild 属性和目标文件级别的所有修改应仅适用于从缓存加载的项目。

寄送扩展插件

有关如何创建 VSIX 文件的信息,请参阅 传送 Visual Studio 扩展。 有关如何将文件添加到特殊安装位置的信息,例如,若要在下方 $(VCTargetsPath)添加文件,请参阅 “在扩展文件夹外安装”。

其他资源

Microsoft 生成系统(MSBuild)为项目文件提供生成引擎和基于 XML 的可扩展格式。 你应该熟悉基本的 MSBuild 概念 以及 MSBuild for Visual C++ 的工作原理,以便扩展 Visual C++ 项目系统。

托管扩展性框架(MEF)提供 CPS 和 Visual C++ 项目系统使用的扩展 API。 有关 CPS 如何使用 MEF 的概述,请参阅 VSProjectSystem MEF 概述中的 CPS 和 MEF

可以自定义现有的生成系统,以添加生成步骤或新的文件类型。 有关详细信息,请参阅 MSBuild (Visual C++) 概述处理项目属性